在pygame的类/子类中设置和显示精灵时遇到问题

Flat_Pancake

您好,我是开发游戏/编码的新手,所以很抱歉我要带来的众多问题以及我的代码组织得很糟糕,我正在尝试让我的班级具有将自己呈现为函数的功能游戏,而不是使用外部资源

`class Animal(pygame.sprite.Sprite):
    def __init__(Self,):
        super().__init__()
        Self.Image=pygame.image.load('Blank.png').convert_alpha()
        Self.rect=Self.image.get_rect()
        Self.x=x
        Self.y=y
        Self.Screen= screen
        #Self.Width=Width
        #Self.Height=Height
        #Self.Energy=0
        
        

    def BoundryX(entityX):
        if entityX<=0:
            entityX=0
        elif entityX>=600:
            entityX=600
            
    def BoundryY(entityY):
        if entityY<=0:
            entityY=0
        elif entityY>=800:
            entityY=800
        
class Predator(Animal):
    def __init__(Self):
        #super().__init__()
        Self.Img=pygame.image.load('Icon.png')
        Self.PredatorX=0
        Self.PredatorY=0
        Self.Screen= screen
        
        
    def Render(Self,Img,X,Y):
        Self.screen.blit(Img,(X,Y))
        `

我遇到了问题,因为它说该类没有“屏幕”属性,我也不知道这意味着什么,顺便说一句,创建函数以在之后创建更多的设置类是最好的方法他们已经吃掉了足够多的食物链,并且具有删除它们以及组织所有不同子画面的功能(我知道这不是我的主要问题,因此,如果没有得到答案,那很好)

这是完整的代码:(对于我糟糕的格式化所造成的任何痛苦,我们深表歉意。

 #imports
    import math
    import random
    import pygame,sys 
    import random
    import pdb
    from pygame.locals  import *
    
    
    timmer=1
    
    
    
    
    class Animal(pygame.sprite.Sprite):
        def __init__(Self,):
            super().__init__()
            Self.Image=pygame.image.load('Blank.png').convert_alpha()
            Self.rect=Self.image.get_rect()
            Self.x=x
            Self.y=y
            Self.Screen= screen
            #Self.Width=Width
            #Self.Height=Height
            #Self.Energy=0
            
            
    
        def BoundryX(entityX):
            if entityX<=0:
                entityX=0
            elif entityX>=600:
                entityX=600
                
        def BoundryY(entityY):
            if entityY<=0:
                entityY=0
            elif entityY>=800:
                entityY=800
                
       
            
    
    
            
    class Predator(Animal):
        def __init__(Self):
            #super().__init__()
            Self.Img=pygame.image.load('Icon.png')
            Self.PredatorX=0
            Self.PredatorY=0
            Self.Screen= screen
            
            
        def Render(Self,Img,X,Y):
            Self.screen.blit(Img,(X,Y))
            
            
    
    
    
             
    class prey(pygame.sprite.Sprite):
        def __init__():
            
            Self.preyImg=pygame.image.load('Prey.png')
            Self.preyX=300
            Self.preyY=700
            Self.PreyX_change=0
             
        def Render(Self):
            Self.screen.blit(preyImg,(preyX,preyY))
            
        def delete(Self):
            i.delete()
    
    
    
        
    CarrotImg=pygame.image.load('carrot.png')
    CarrotX=100
    CarrotY=300
    foodamount=7
    
    
    def food():
        #CarrotX=random.randint(10,950)
        #CarrotY=random.randint(10,750)
        screen.blit(CarrotImg,(CarrotX,CarrotY))
        
        
    
    #setup pygame
    pygame.init()
    
    #caption and Icons
    pygame.display.set_caption("Game Of Life")
    
    #predator icon
    
    predatorImg=pygame.image.load('Icon.png')
    predatorX=900
    predatorY=100
    predatorX_change=0
    
    
    #Prey Icon
    preyImg=pygame.image.load('Prey.png')
    preyX=300
    preyY=700
    PreyX_change=0
    
    
            
    #def delete():
            #prey.delete()
            
    preyImg=pygame.image.load('Prey.png')
    preyX=300
    preyY=700
    PreyX_change=0
    
    #def Prey():
        #screen.blit(preyImg,(preyX,preyY))
    class setup():
        def __init__():
            x=1
            
        def Predator1(Self):
            screen.blit(predatorImg,(predatorX,predatorY))
    
    #Finding closest prey
    def FindClosestItem(AgressorX,DefenderX,AgressorY,DefenderY):
        dist = math.sqrt((AgressorX-DefenderX)**2 + (AgressorY-DefenderY)**2)#finds distance in pixels
        
    
    #create pop out for game
    screen=pygame.display.set_mode((1000,800))
    
    
    
    
    
    def Tracking(AgressorX,DefenderX,AgressorY,DefenderY):
        global XMovement#make variables global so it actually works
        global YMovement
        
        if AgressorX > DefenderX:#finds whether its position then moves left/righ,up/down depending on its location
            XMovement=-0.25
        
        elif AgressorX< DefenderX:
            XMovement=0.25
            
        else:
            XMovement=0
            
        
        if AgressorY > DefenderY:
            YMovement=-0.25
            
        elif AgressorY < DefenderY: 
            YMovement=0.25
            
        else:
            YMovement=0
            
            
    def EatPrey(predatorX,PreyX,predatorY,preyY):
        dist = math.sqrt((predatorX-preyX)**2 + (predatorY-preyY)**2)
        if dist < 20:
            return True
        else:
            return False
    
    
    #setup test
    
    predator=Predator()
    
    
    #Sprite groups
    all_sprites_Wolves=pygame.sprite.Group()
    
    
    all_sprites_Rabbits=pygame.sprite.Group()
    
    
    all_sprites_Carrots=pygame.sprite.Group()
    
        
    
    #game loop
    running=True
    while running:
    
        #Back ground colour
        screen.fill((0,128,0))
        
        for event in pygame.event.get():
            if event.type==pygame.QUIT:
                running=False
        
    
    
        
       
        
        predator.Render(pygame.image.load('Icon.png'),600,700)
        #Prey.Render()
    
        ClosestPrey=FindClosestItem(predatorX,preyX,predatorY,preyY)
        
        
        food()
        
        Track(predatorX,preyX,predatorY,preyY)
        predatorX+=XMovement
        predatorY+=YMovement
        #predatorX=BoundryX(predatorX)
        #predatorY=BoundryY(predatorY)
       
        
        Track(preyX,CarrotX,preyY,CarrotY)
        preyX+=XMovement
        preyY+=YMovement
        #preyX=BoundryX(preyX)
        #preyY=BoundryY(preyY)
        
    
        #Eat=EatPrey(preyX,preyY,predatorX,predatorY)
        
        #if Eat==True:
            #delete()
            #T=1
        
        #Boundry(prey)
        if preyX<=0:
            preyX=0
        elif preyX>=950:
            preyX=950
        if preyY<=0:
            preyY=0
        elif preyY>=750:
            preyY=750
            #preyY-=1
    
        #Boundry(predator)
        if predatorX<=0:
            predatorX=0
        elif predatorX>=950:
            predatorX=950
        elif predatorY<=0:
            predatorY=0
        elif predatorY>=750:
            predatorY=750
        pygame.display.update()
    
        timmer=timmer+1


        
懒惰

您的代码相当混乱,但是请放心,让我们逐步创建一个简单的pygame游戏步骤。尝试了解每个步骤的作用。

首先,让我们从游戏的基本框架开始,如下所示:

import pygame

def main():
    screen = pygame.display.set_mode((640, 480))
    clock = pygame.time.Clock()
    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return
        screen.fill('grey')
        pygame.display.flip()
        clock.tick(60)

if __name__ == '__main__':
    main()

在这里,我们有一个简单的main功能和简单的游戏循环,它只是监听QUIT事件,使一切灰色和限制帧率到60你不具备有一个main功能和__name__检查,但这样做是很好的实践它允许您导入文件而无需运行游戏。另外,我帮助不要污染全局名称空间。

好,让我们创建一些Sprites

import pygame
from random import randint, choice

class Animal(pygame.sprite.Sprite):
    
    colors = ['lightblue', 'blue', 'darkblue', 'dodgerblue']

    def __init__(self, pos=None, color=None):
        super().__init__()
        self.image = pygame.Surface((32, 32))
        self.image.fill(color if color else choice(Animal.colors))
        self.rect = self.image.get_rect(center = pos if pos else (randint(100, 540), randint(100, 380)))

def main():
    screen = pygame.display.set_mode((640, 480))
    clock = pygame.time.Clock()
    
    animals = pygame.sprite.Group()
    animals.add(Animal())
    animals.add(Animal())
    animals.add(Animal())

    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return
        screen.fill('grey')
        animals.draw(screen)
        pygame.display.flip()
        clock.tick(60)

if __name__ == '__main__':
    main()

Sprite在pygame中使用该类,该类需要一个image属性(一个Surface)和一个rect属性(一个),Rect并包含的位置和大小Surface如果创建Sprite这样的对象,则可以利用Group该类(或其子类)来绘制和更新精灵。为了画些东西,我在一个组中添加了三个动物,animals并调用draw函数,将screenSurface作为参数传递,这样就Group知道了在哪里将动物的图像变灰。

在此处输入图片说明

到目前为止,由于这很无聊,因此让我们向精灵添加一些行为:

import pygame
from random import randint, choice

class Animal(pygame.sprite.Sprite):
    
    colors = ['lightblue', 'blue', 'darkblue', 'dodgerblue']

    def __init__(self, pos=None, color=None):
        super().__init__()
        self.image = pygame.Surface((32, 32))
        self.image.fill(color if color else choice(Animal.colors))
        self.rect = self.image.get_rect(center = pos if pos else (randint(100, 540), randint(100, 380)))
        self.pos = pygame.Vector2(*self.rect.center)
        self.speed = 3
        self.direction = pygame.Vector2(1, 0).rotate(randint(0, 360))

    def update(self, dt):
        v = self.direction * self.speed
        while not pygame.display.get_surface().get_rect().contains(self.rect.move(v)):
            self.direction = pygame.Vector2(1, 0).rotate(randint(0, 360))
            v = self.direction * self.speed
        self.pos += v
        self.rect.center = self.pos

def main():
    screen = pygame.display.set_mode((640, 480))
    clock, dt = pygame.time.Clock(), 0
    
    animals = pygame.sprite.Group()
    animals.add(Animal())
    animals.add(Animal())
    animals.add(Animal())

    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return
                
        animals.update(dt/1000)
        
        screen.fill('grey')
        animals.draw(screen)
        pygame.display.flip()
        dt = clock.tick(60)

if __name__ == '__main__':
    main()

As you can see, we keep all the moving logic in the Animal class. The only thing that changed in the game loop is that we keep track of the delta time dt to ensure a constant frame rate (honestly, that's not that important in a small example like this, but again, good practice), and pass it to the groups update function, which in turn will call the update function of each sprite it contains.

In the Animal class, we use some simple vector math to move the sprite: we have a speed and a direction (which is a vector); and also an additional pos vector. Changing the position is easy with vectors because we can just do something like pos = pos + direction * speed, and changing the direction is simple too if we just randomly rotate the direction vector.

If you want to create a 2D game with moving parts I recommend that you learn a litte bit of vector math if you didn't already learn it in school. You don't need to know much more than the fact that you can easily add them up or multiply them etc.

Remember that the sprite is drawn at the coordinate of its rect, so we need to update the rect's position, too.

Pygame's Rect class has some handy functions, too. Just look how we check if the sprite would go out of screen. We can simply grab the Rect of the display surface, move the Sprite's Rect and check if it's still inside the screen rect. If not, we randomly rotate our direction vector (well, it's not 100% perfect, but KISS).

在此处输入图片说明

So what about other sprites? Let's just subclass our Animal class, change the speed and color and the behaviour by overwriting the update function:

import pygame
import pygame.freetype
from random import randint, choice
from math import hypot

class Animal(pygame.sprite.Sprite):
    
    colors = ['lightblue', 'blue', 'darkblue', 'dodgerblue']

    def __init__(self, pos=None, color=None, *grps):
        super().__init__(*grps)
        self.image = pygame.Surface((32, 32))
        self.color = color if color else choice(Animal.colors)
        self.image.fill(self.color)
        self.rect = self.image.get_rect(center = pos if pos else (randint(100, 540), randint(100, 380)))
        self.pos = pygame.Vector2(*self.rect.center)
        self.speed = 3
        self.direction = pygame.Vector2(1, 0).rotate(randint(0, 360))

    def update(self, dt):
        v = self.direction * self.speed
        while not pygame.display.get_surface().get_rect().contains(self.rect.move(v)):
            self.direction = pygame.Vector2(1, 0).rotate(randint(0, 360))
            v = self.direction * self.speed
        self.pos += v
        self.rect.center = self.pos


class Preditor(Animal):
    
    def __init__(self, animals, pos=None, color=None, *grps):
        super().__init__(pos, color or 'red', *grps)
        self.speed = 4
        self.target = None
        self.animals = animals
        self.eaten = 0
        self.font = pygame.freetype.SysFont(None, 16)
        self.font.render_to(self.image, (10, 10), str(self.eaten), 'white')

    def get_nearest_animal(self):
        target = None
        distance = None
        for animal in self.animals:
            pygame.draw.line(pygame.display.get_surface(), 'darkgrey', self.pos, animal.pos)
            if not target:
                target = animal
                distance = hypot(animal.pos.x - self.pos.x, animal.pos.y - self.pos.y)
            else:
                new_distance = hypot(animal.pos.x - self.pos.x, animal.pos.y - self.pos.y)
                if new_distance < distance:
                    target = animal
                    distance = new_distance
        if target:
            pygame.draw.line(pygame.display.get_surface(), 'green', self.pos, target.pos)
        return target

    def update(self, dt):
        self.target = self.get_nearest_animal()
        if self.target:
            self.direction = (self.target.pos - self.pos).normalize()
        else:
            self.direction = pygame.Vector2(0, 0)
        
        self.pos += self.direction * self.speed
        self.rect.center = self.pos
        
        if self.target and self.rect.colliderect(self.target.rect):
            self.target.kill()
            self.image.fill(self.color)
            self.eaten += 1
            self.font.render_to(self.image, (10, 10), str(self.eaten), 'white')

def main():
    pygame.init()
    screen = pygame.display.set_mode((640, 480))
    clock, dt = pygame.time.Clock(), 0
    
    animals = pygame.sprite.Group()
    all_sprites = pygame.sprite.Group()
    for _ in range(5):
        Animal(None, None, animals, all_sprites)
    Preditor(animals, None, None, all_sprites)

    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return
            if e.type == pygame.KEYDOWN:
                Animal(None, None, animals, all_sprites)
        
        screen.fill('grey')
        all_sprites.update(dt/1000)
        all_sprites.draw(screen)
        pygame.display.flip()
        dt = clock.tick(60)

if __name__ == '__main__':
    main()

在此处输入图片说明

Sprites can be part of multiple groups, and we use that here to give the Predator a list of all its victims it can hunt and eat. Again, see how all sprite behaviour is inside the sprite classes. The only thing the main loop does is creating the initial state telling the sprite groups to update and draw all their sprites (and adding new Animals by pressing a key, because why not). Also note how we can use kill to remove it from all it groups, basically removing it from the game.

Hope that helps and gives you an idea on how to organize your pygame game.

只是玩一点。那些需要吃饭才能生存和繁殖的动物怎么样?捕食者只需要触手可及的较慢动物,如果没有,就吃其他捕食者甚至植物?

import pygame
import pygame.freetype
from random import randint, choice
from math import hypot
from dataclasses import dataclass

class Plant(pygame.sprite.Sprite):
    
    colors = ['green', 'lightgreen', 'darkgreen']

    def __init__(self, pos=None, color=None, *grps):
        self._layer = -10
        super().__init__(*grps)
        self.image = pygame.Surface((24, 24))
        self.color = color if color else choice(Plant.colors)
        self.image.fill(self.color)
        self.rect = self.image.get_rect(center = pos if pos else (randint(10, 630), randint(10, 470)))
        self.pos = pygame.Vector2(*self.rect.center)

class Animal(pygame.sprite.Sprite):
    
    font = None
    colors = ['lightblue', 'blue', 'darkblue', 'dodgerblue']

    def __init__(self, system, pos=None, color=None, *grps):
        super().__init__(*grps)
        self.image = pygame.Surface((24, 24))
        self.color = color if color else choice(Animal.colors)
        self.image.fill(self.color)
        self.rect = self.image.get_rect(center = pos if pos else (randint(100, 540), randint(100, 380)))
        self.pos = pygame.Vector2(*self.rect.center)
        self.speed = randint(20, 50) / 10
        self.direction = pygame.Vector2(1, 0).rotate(randint(0, 360))
        self.reproduce = randint(1, 5)
        self.sleep = 0
        self.eaten = 0
        self.energy = 10
        self.system = system
        if not self.font:
            Animal.font = pygame.freetype.SysFont(None, 16)

    def base_update(self, dt):
        self.energy -= dt * (self.speed / 2)
        if self.energy <= 0:
            self.kill()
            return False
    
        if self.sleep >= 0:
            self.sleep -= dt
            return False

        self.reproduce -= dt
        if self.reproduce <= 0 and self.energy >= 4:
            self.reproduce = randint(1, 7)
            self.__class__(self.system, self.pos, None, *self.groups())
            self.sleep = 0.5
            self.energy -= 1.5

        return True

    def update_image(self):
        self.image.fill(self.color)
        self.image.set_alpha(122 if self.sleep > 0 else 255)
            
        pygame.draw.rect(self.image, 'green', (0, 0, self.rect.width * self.energy/10, 3))
        self.font.render_to(self.image, (7, 7), str(self.eaten), 'white')

    def get_nearest_target(self, targets, max_distance=250):
        target = None
        distance = None
        for possible_target in targets:
            if possible_target == self or hasattr(possible_target, 'speed') and possible_target.speed > self.speed:
                continue
            
            new_distance = hypot(possible_target.pos.x - self.pos.x, possible_target.pos.y - self.pos.y)
            pygame.draw.line(pygame.display.get_surface(), 'darkgrey' if new_distance > max_distance else 'white', self.pos, possible_target.pos)
            if new_distance <= max_distance:
                if not target or new_distance < distance:
                    target = possible_target
                    distance = new_distance
        if target:
            pygame.draw.line(pygame.display.get_surface(), 'green', self.pos, target.pos)
        return target

    def update(self, dt):
        if not self.base_update(dt) or len(self.groups()) == 0:
            return
            
        v = self.direction * self.speed
        while not pygame.display.get_surface().get_rect().contains(self.rect.move(v)):
            self.direction = pygame.Vector2(1, 0).rotate(randint(0, 360))
            v = self.direction * self.speed

        for plant in self.system.plants:
            if plant.rect.colliderect(self.rect) and self.energy < 8:
                plant.kill()
                self.eaten += 1
                self.energy = 10
                continue

        self.pos += v
        self.rect.center = self.pos
        self.update_image()

class Preditor(Animal):
    
    def __init__(self, system, pos=None, color=None, *grps):
        super().__init__(system, pos, color or 'red', *grps)
        self.speed = randint(20, 40) / 10
        self.target = None
        self.update_image()

    def update(self, dt):
        if not self.base_update(dt) or len(self.groups()) == 0:
            return

        self.target = self.get_nearest_target(self.system.animals)
        if not self.target:
            self.target = self.get_nearest_target(self.system.preditors)
        if not self.target:
            self.target = self.get_nearest_target(self.system.plants)
            
        if self.target:
            self.direction = (self.target.pos - self.pos).normalize()
        else:
            self.direction = pygame.Vector2(0, 0)
        
        self.pos += self.direction * self.speed
        self.rect.center = self.pos
        
        if self.target and self.rect.colliderect(self.target.rect):
            self.target.kill()
            self.eaten += 1
            self.sleep = 0.5
            self.energy += 3
            if self.energy > 10:
                self.energy = 10

        self.update_image()

@dataclass
class System:
    plants: object
    animals: object
    preditors: object

def main():
    pygame.init()
    screen = pygame.display.set_mode((640, 480))
    clock, dt = pygame.time.Clock(), 0

    GROW = pygame.USEREVENT + 1
    pygame.time.set_timer(GROW, 1000)

    
    animals = pygame.sprite.Group()
    plants = pygame.sprite.Group()
    preditors = pygame.sprite.Group()
    all_sprites = pygame.sprite.LayeredUpdates()

    system = System(plants, animals, preditors)
    
    for _ in range(4):
        Animal(system, None, None, animals, all_sprites)

    for _ in range(5):
        Plant(None, None, plants, all_sprites)

    Preditor(system, None, None, preditors, all_sprites)

    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return
            if e.type == pygame.KEYDOWN:
                Animal(system, None, None, animals, all_sprites)
            if e.type == GROW:
                for _ in range(5):
                    Plant(None, None, plants, all_sprites)
        
        screen.fill('grey')
        all_sprites.update(dt/1000)
        all_sprites.draw(screen)
        pygame.display.flip()
        dt = clock.tick(30)

if __name__ == '__main__':
    main()

在此处输入图片说明

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章