在 pygame 的类/子类中设置和显示精灵时遇到问题 [英] having issues setting up and displaying the sprites in my classes/subclasses in pygame

查看:46
本文介绍了在 pygame 的类/子类中设置和显示精灵时遇到问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好,我对创建游戏/编码还比较陌生,对于我将要带来的大量问题以及我的代码的糟糕组织,我很抱歉,我正在尝试让我的班级有一个功能将自己渲染到游戏中,而不是使用外部资源

`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()自我.x=x自我.y=ySelf.Screen=屏幕#Self.Width=宽度#Self.Height=高度#Self.Energy=0def BoundryX(entityX):如果实体X<=0:实体X=0elif entityX>=600:实体X=600def BoundryY(entityY):如果实体Y<=0:实体Y=0elif entityY>=800:实体Y=800类捕食者(动物):def __init__(自己):#super().__init__()Self.Img=pygame.image.load('Icon.png')Self.PredatorX=0Self.PredatorY=0Self.Screen=屏幕def 渲染(自我,图像,X,Y):Self.screen.blit(Img,(X,Y))`

我遇到了问题,因为它说该类没有属性屏幕";我不知道这意味着什么,顺便提一下,在他们吃掉足够的食物链以及删除它们的函数之后,创建一个函数来创建更多集合类的最佳方法是什么组织所有不同的精灵(我知道这不是我的主要问题的一部分,所以如果没有得到答案也没关系)

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

 #imports导入数学随机导入导入 pygame,sys随机导入导入 pdb从 pygame.locals 导入 *计时器=1类动物(pygame.sprite.Sprite):def __init__(Self,):super().__init__()Self.Image=pygame.image.load('Blank.png').convert_alpha()Self.rect=Self.image.get_rect()自我.x=x自我.y=ySelf.Screen=屏幕#Self.Width=宽度#Self.Height=高度#Self.Energy=0def BoundryX(entityX):如果实体X<=0:实体X=0elif entityX>=600:实体X=600def BoundryY(entityY):如果实体Y<=0:实体Y=0elif entityY>=800:实体Y=800类捕食者(动物):def __init__(自己):#super().__init__()Self.Img=pygame.image.load('Icon.png')Self.PredatorX=0Self.PredatorY=0Self.Screen=屏幕def 渲染(自我,图像,X,Y):Self.screen.blit(Img,(X,Y))类猎物(pygame.sprite.Sprite):定义 __init__():Self.preyImg=pygame.image.load('Prey.png')Self.preyX=300Self.preyY=700Self.PreyX_change=0def渲染(自我):Self.screen.blit(preyImg,(preyX,preyY))定义删除(自我):i.delete()CarrotImg=pygame.image.load('carrot.png')胡萝卜X=100胡萝卜Y=300食物量=7定义食物():#CarrotX=random.randint(10,950)#CarrotY=random.randint(10,750)screen.blit(CarrotImg,(CarrotX,CarrotY))#设置pygamepygame.init()#caption 和图标pygame.display.set_caption(生命游戏")#捕食者图标捕食者Img = pygame.image.load('Icon.png')捕食者X=900捕食者Y=100捕食者X_change=0#猎物图标preyImg=pygame.image.load('Prey.png')猎物X=300猎物Y=700PreyX_change=0#def 删除():#prey.delete()preyImg=pygame.image.load('Prey.png')猎物X=300猎物Y=700PreyX_change=0#def 猎物():#screen.blit(preyImg,(preyX,preyY))类设置():定义 __init__():x=1def Predator1(Self):screen.blit(捕食者图像,(捕食者X,捕食者Y))#寻找最近的猎物def FindClosestItem(AgressorX,DefenderX,AgressorY,DefenderY):dist = math.sqrt((AgressorX-DefenderX)**2 + (AgressorY-DefenderY)**2)#以像素为单位求距离#为游戏创建弹出窗口屏幕=pygame.display.set_mode((1000,800))def 跟踪(AgressorX,DefenderX,AgressorY,DefenderY):global XMovement#make variables global 所以它实际上有效全球运动如果 AgressorX >DefenderX:#找到它的位置然后根据它的位置向左/向右、向上/向下移动XMovement=-0.25elif AgressorX<后卫X:XMovement=0.25别的:XMovement=0如果 AgressorY >后卫:Y运动=-0.25elif AgressorY <后卫:Y运动=0.25别的:Y运动=0def EatPrey(捕食者X,捕食者X,捕食者,猎物Y):dist = math.sqrt((predatorX-preyX)**2 + (predatorY-preyY)**2)如果距离<20:返回真别的:返回错误#设置测试捕食者=捕食者()#精灵组all_sprites_Wolves=pygame.sprite.Group()all_sprites_Rabbits=pygame.sprite.Group()all_sprites_Carrots=pygame.sprite.Group()#游戏循环运行=真在跑步的时候:#背景色screen.fill((0,128,0))对于 pygame.event.get() 中的事件:如果 event.type==pygame.QUIT:运行=假捕食者.渲染(pygame.image.load('Icon.png'),600,700)#Prey.Render()ClosestPrey=FindClosestItem(predatorX,preyX,predatorY,preyY)食物()跟踪(捕食者X,猎物X,捕食者,猎物Y)捕食者X+=X移动捕食者Y+=Y运动#捕食者X=边界X(捕食者X)#predatorY=BoundryY(predatorY)跟踪(preyX,CarrotX,preyY,CarrotY)猎物X+=X移动猎物Y+=Y移动#preyX=BoundryX(preyX)#preyY=BoundryY(preyY)#Eat=EatPrey(preyX,preyY,predatorX,predatorY)#如果吃==真:#删除()#T=1#边界(猎物)如果猎物X<=0:猎物X=0elif猎物X>=950:猎物X=950如果猎物Y<=0:猎物Y=0elif猎物Y>=750:猎物Y=750#preyY-=1#边界(捕食者)如果捕食者X<=0:捕食者X=0elif捕食者X>=950:捕食者X=950elif 掠食者Y<=0:捕食者Y=0elif 掠食者Y>=750:捕食者Y=750pygame.display.update()计时器=计时器+1

解决方案

你的代码很乱,不过别担心,让我们一步一步地创建一个简单的 pygame 游戏.尝试了解每个步骤的作用.

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

导入pygame定义主():屏幕 = pygame.display.set_mode((640, 480))时钟 = pygame.time.Clock()为真:事件 = pygame.event.get()对于事件中的 e:如果 e.type == pygame.QUIT:返回screen.fill('灰色')pygame.display.flip()时钟滴答(60)如果 __name__ == '__main__':主要的()

在这里,我们有一个简单的 main 函数和一个简单的游戏循环,它只监听 QUIT 事件,将所有内容设为灰色并将帧率限制为 60.你没有必须有一个 main 函数和 __name__ 检查,但这样做是一个很好的做法,因为它允许你导入文件而不运行游戏.此外,我有助于不污染全局命名空间.

好的,让我们创建一些Sprites:

导入pygame从随机导入randint,选择类动物(pygame.sprite.Sprite):颜色 = ['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 selection(Animal.colors))self.rect = self.image.get_rect(center = pos if pos else (randint(100, 540), randint(100, 380)))定义主():屏幕 = pygame.display.set_mode((640, 480))时钟 = pygame.time.Clock()动物 = pygame.sprite.Group()动物.添加(动物())动物.添加(动物())动物.添加(动物())为真:事件 = pygame.event.get()对于事件中的 e:如果 e.type == pygame.QUIT:返回screen.fill('灰色')动物绘制(屏幕)pygame.display.flip()时钟滴答(60)如果 __name__ == '__main__':主要的()

使用

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

导入pygame从随机导入randint,选择类动物(pygame.sprite.Sprite):颜色 = ['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 selection(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 = 3self.direction = pygame.Vector2(1, 0).rotate(randint(0, 360))定义更新(自我,DT):v = self.direction * self.speed而不是 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.speedself.pos += vself.rect.center = self.pos定义主():屏幕 = pygame.display.set_mode((640, 480))时钟,dt = pygame.time.Clock(), 0动物 = pygame.sprite.Group()动物.添加(动物())动物.添加(动物())动物.添加(动物())为真:事件 = pygame.event.get()对于事件中的 e:如果 e.type == pygame.QUIT:返回动物.更新(dt/1000)screen.fill('灰色')动物绘制(屏幕)pygame.display.flip()dt = 时钟.tick(60)如果 __name__ == '__main__':主要的()

如您所见,我们将所有移动逻辑保留在 Animal 类中.游戏循环中唯一改变的是我们跟踪 delta time dt 以确保恒定的帧速率(老实说,这在一个小例子中并不重要像这样,但同样是一个好习惯),并将其传递给组 update 函数,后者将调用它包含的每个精灵的 update 函数.

在Animal类中,我们使用一些简单的向量数学来移动精灵:我们有一个speed和一个direction(这是一个向量);还有一个额外的 pos 向量.用向量改变位置很容易,因为我们可以做一些类似pos = pos + direction * speed的事情,如果我们随机旋转方向向量,改变方向也很简单.

如果您想创建一个带有移动部件的 2D 游戏,我建议您学习一点矢量数学(如果您在学校还没有学过).除了可以轻松地将它们相加或相乘等这一事实之外,您不需要知道更多.

记住精灵是在其rect的坐标处绘制的,所以我们也需要更新rect的位置.

Pygame 的 Rect 类也有一些方便的功能.看看我们如何检查精灵是否会离开屏幕.我们可以简单地抓取显示表面的 Rect,移动 Sprite 的 Rect 并检查它是否仍在屏幕矩形内.如果不是,我们随机旋转我们的 direction 向量(好吧,它不是 100% 完美,而是 KISS).

那么其他精灵呢?让我们继承我们的 Animal 类,通过覆盖更新函数来改变速度、颜色和行为:

导入pygame导入 pygame.freetype从随机导入randint,选择从数学导入假设类动物(pygame.sprite.Sprite):颜色 = ['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 selection(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 = 3self.direction = pygame.Vector2(1, 0).rotate(randint(0, 360))定义更新(自我,DT):v = self.direction * self.speed而不是 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.speedself.pos += vself.rect.center = self.pos类捕食者(动物):def __init__(self,animals, pos=None, color=None, *grps):super().__init__(pos, color or 'red', *grps)self.speed = 4self.target = 无self.animals = 动物自食 = 0self.font = pygame.freetype.SysFont(None, 16)self.font.render_to(self.image, (10, 10), str(self.eaten), 'white')def get_nearest_animal(self):目标 = 无距离 = 无对于 self.animals 中的动物:pygame.draw.line(pygame.display.get_surface(),'darkgrey',self.pos,animal.pos)如果不是目标:目标 = 动物距离 = hypot(animal.pos.x - self.pos.x,animal.pos.y - self.pos.y)别的:new_distance = hypot(animal.pos.x - self.pos.x,animal.pos.y - self.pos.y)如果 new_distance <距离:目标 = 动物距离 = new_distance如果目标:pygame.draw.line(pygame.display.get_surface(), 'green', self.pos, target.pos)返回目标定义更新(自我,DT):self.target = self.get_nearest_animal()如果 self.target:self.direction = (self.target.pos - self.pos).normalize()别的:self.direction = pygame.Vector2(0, 0)self.pos += self.direction * self.speedself.rect.center = self.pos如果 self.target 和 self.rect.colliderect(self.target.rect):self.target.kill()self.image.fill(self.color)自食+= 1self.font.render_to(self.image, (10, 10), str(self.eaten), 'white')定义主():pygame.init()屏幕 = pygame.display.set_mode((640, 480))时钟,dt = pygame.time.Clock(), 0动物 = pygame.sprite.Group()all_sprites = pygame.sprite.Group()对于 _ 范围(5):动物(无,无,动物,all_sprites)捕食者(动物,无,无,all_sprites)为真:事件 = pygame.event.get()对于事件中的 e:如果 e.type == pygame.QUIT:返回如果 e.type == pygame.KEYDOWN:动物(无,无,动物,all_sprites)screen.fill('灰色')all_sprites.update(dt/1000)all_sprites.draw(屏幕)pygame.display.flip()dt = 时钟.tick(60)如果 __name__ == '__main__':主要的()

精灵可以是多个组的一部分,我们在这里使用它来为 Predator 提供它可以猎杀和吃掉的所有受害者的列表.再次,看看所有的精灵行为是如何在精灵类中的.主循环所做的唯一一件事就是创建初始状态,告诉精灵组更新和绘制它们的所有精灵(并通过按键添加新的动物,因为为什么不呢).还要注意我们如何使用 kill 将其从所有 it 组中删除,基本上将其从游戏中删除.

希望对您有所帮助,并让您了解如何组织您的 pygame 游戏.

随便玩玩吧.需要进食以维持生命和繁殖的动物怎么样?捕食者只需要触手可及的速度较慢的动物,如果没有,就吃其他捕食者甚至植物?

导入pygame导入 pygame.freetype从随机导入randint,选择从数学导入假设从数据类导入数据类类植物(pygame.sprite.Sprite):颜色 = ['绿色','浅绿色','深绿色']def __init__(self, pos=None, color=None, *grps):self._layer = -10super().__init__(*grps)self.image = pygame.Surface((24, 24))self.color = color if color else selection(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)类动物(pygame.sprite.Sprite):字体 = 无颜色 = ['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 selection(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)/10self.direction = pygame.Vector2(1, 0).rotate(randint(0, 360))self.reproduce = randint(1, 5)self.sleep = 0自食 = 0自我.能量 = 10self.system = 系统如果不是 self.font:Animal.font = pygame.freetype.SysFont(None, 16)def base_update(self, dt):self.energy -= dt * (self.speed/2)如果 self.energy <= 0:self.kill()返回错误如果 self.sleep >= 0:self.sleep -= dt返回错误self.reproduce -= dt如果 self.reproduce <= 0 并且 self.energy >= 4:self.reproduce = randint(1, 7)self.__class__(self.system, self.pos, None, *self.groups())self.sleep = 0.5自我能量 -= 1.5返回真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):目标 = 无距离 = 无对于目标中的可能目标:if possible_target == self 或 hasattr(possible_target, 'speed') and possible_target.speed >self.speed:继续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)如果 new_distance <= max_distance:如果不是 target 或 new_distance <距离:目标 = 可能的_目标距离 = new_distance如果目标:pygame.draw.line(pygame.display.get_surface(), 'green', self.pos, target.pos)返回目标定义更新(自我,DT):如果不是 self.base_update(dt) 或 len(self.groups()) == 0:返回v = self.direction * self.speed而不是 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.system.plants 中的植物:如果 plant.rect.colliderect(self.rect) 和 self.energy <8:植物杀死()自食+= 1自我.能量 = 10继续self.pos += vself.rect.center = self.posself.update_image()类捕食者(动物):def __init__(self, system, pos=None, color=None, *grps):super().__init__(system, pos, color or 'red', *grps)self.speed = randint(20, 40)/10self.target = 无self.update_image()定义更新(自我,DT):如果不是 self.base_update(dt) 或 len(self.groups()) == 0:返回self.target = self.get_nearest_target(self.system.animals)如果不是 self.target:self.target = self.get_nearest_target(self.system.preeditors)如果不是 self.target:self.target = self.get_nearest_target(self.system.plants)如果 self.target:self.direction = (self.target.pos - self.pos).normalize()别的:self.direction = pygame.Vector2(0, 0)self.pos += self.direction * self.speedself.rect.center = self.pos如果 self.target 和 self.rect.colliderect(self.target.rect):self.target.kill()自食+= 1self.sleep = 0.5自身能量 += 3如果 self.energy >10:自我.能量 = 10self.update_image()@数据类类系统:植物:对象动物:物体预兆:对象定义主():pygame.init()屏幕 = pygame.display.set_mode((640, 480))时钟,dt = pygame.time.Clock(), 0增长 = pygame.USEREVENT + 1pygame.time.set_timer(增长,1000)动物 = pygame.sprite.Group()植物 = pygame.sprite.Group()捕食者 = pygame.sprite.Group()all_sprites = pygame.sprite.LayeredUpdates()系统 = 系统(植物、动物、捕食者)对于范围内的 _(4):动物(系统,无,无,动物,all_sprites)对于 _ 范围(5):植物(无,无,植物,all_sprites)捕食者(系统,无,无,捕食者,all_sprites)为真:事件 = pygame.event.get()对于事件中的 e:如果 e.type == pygame.QUIT:返回如果 e.type == pygame.KEYDOWN:动物(系统,无,无,动物,all_sprites)如果 e.type == 增长:对于 _ 范围(5):植物(无,无,植物,all_sprites)screen.fill('灰色')all_sprites.update(dt/1000)all_sprites.draw(屏幕)pygame.display.flip()dt = 时钟.tick(30)如果 __name__ == '__main__':主要的()

Hello I am relatively new to creating games/coding so sorry before hand for the multitude of issues I am going to be bringing and the god awful organisation of my code, I'm attempting to have my class' have a function to render themselves into the game instead of using an outside source

`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))
        `

I'm having issues as it says the class doesn't have the attribute "screen" and I do not know what that means, on a side note what would be the best way to create a function to create more of a set class after they have eaten enough of their food chain as well as a function to remove them as well as organise all of the different sprites(I understand this isn't apart of my main issue so if it doesn't get answer that's fine)

here is the full code: (sorry for any pain caused by my terrible formatting

 #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


        

解决方案

Your code is quite a mess, but don't worry, let's create a simple pygame game step for step. Try to understand what each step does.

First, let's start with a basic skeleton for a game, something like this:

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()

Here, we have a simple main function and a simple game loop that does nothing but listen for the QUIT event, make everything grey and limit the framerate to 60. You don't have to have a main function and the __name__ check but doing this is good practice as it allows you to import file without running the game. Also, I helps to not pollute the global namespace.

OK, let's create some 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()

To use the Sprite class in pygame, the class needs an image attribute, which is a Surface, and a rect attribute, which is a Rect and contains the position and the size of the Surface. If you create a Sprite like this, you can make use of the Group class (or its subclasses) to draw and update your sprites. To draw somethin, I added three Animals to a group animals and call the draw function, passing the screen Surface as an argument so the Group knows where to blit the Animals' images.

Since this is quite boring so far, let's add some behaviour to our 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)))
        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.

Just play around a little. How about Animals that need to eat to stay alive and reproduce? And predators that will only need slower animals within reach, and if there are none, eat other predators or even plants?

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()

这篇关于在 pygame 的类/子类中设置和显示精灵时遇到问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆