pygame游戏_小蝌蚪吃蚊子幼虫成长

Posted geng_zhaoying

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pygame游戏_小蝌蚪吃蚊子幼虫成长相关的知识,希望对你有一定的参考价值。

网上有许多小蝌蚪的游戏。其中有一游戏,小蝌蚪开始很小,其四处游动吃蚊虫(蚊子幼虫),吃一个蚊虫后其身体长大一点,长大到某尺寸变为青蛙。本例实现其部分功能。游戏有3个角色:小蝌蚪、蚊虫和背景角色。小蝌蚪和蚊虫各有有两个造型,以实现动画。游戏窗口为480*/360,使用大背景,尺寸为960*720。游戏的3个角色造型如下。



处理有多个类似角色,例如多个蚊虫,最好使用pygame.sprite.Sprite(简称Sprite)类作为基类派生自己的蚊虫类,将多个蚊虫实例存入pygame.sprite.Group类实例中,使蚊虫动画、数据更新和处理碰撞程序设计极大简化。首先介绍以Sprite类作为基类派生的蚊虫类必须定义的属性和方法。

class Larva(pygame.sprite.Sprite):   		#蚊虫类,基类必须是Sprite类
	def __init__(self):				#构造函数
		...
		self.image=...            #这两个属性必须定义
		self.rect=...
	def update(self):			#除非角色不动,一般要定义该方法
		...	

不用定义Draw()方法,Sprite类定义了Draw()方法,该方法使用属性self.image和self.rect用blit(self.image,self.rect)在窗体显示造型。除非角色不动,一般需定义update方法,例如角色在不同帧有不同造型,在update方法中要修改self.image属性,如角色移动,要修改self.rect.x和self.rect.y。总之在用blit在窗体显示造型前所有需要修改的数据要放在update方法中修改。可建立多个Larva实例,都要保存入pygame.sprite.Group类实例中。

allSprites=pygame.sprite.Group()  #本质上是一个列表,但有列表没有的一些功能
for i in range(5):
    larva=Larva(images)
    allSprites.add(larva)while running:语句中,加入显示所有larva实例的语句。
while running:
	...	
	allSprites.draw(screen) 			#显示组内的所有精灵
	allSprites.update()				#更新组内的所有精灵数据
	...

游戏中有多个蚊虫,身体上下随机摆动,蚊虫向左或向右游动,到边界后直到不可见,反向游动进入窗体,看起来象另一蚊虫游入窗体。当碰到小蝌蚪被吃掉后,原地消失,在窗体外重新出现,慢慢游入窗体,看起来象这个蚊虫被吃掉,是另一蚊虫游入窗体。定义一个Larva类,封装蚊虫的上述行为和数据。所有蚊虫造型都相同,没必要每个蚊虫都保存自己的造型,在主程序定义一个images列表,保存蚊虫两个造型(第80-84句),并将列表实例传递给Larva类(第56句)。在构造函数中,蚊虫沿x轴移动速度被赋于随机值,使不同蚊虫有不同的速度(第58句)。每个蚊虫的初始位置也不同(第60句)。蚊虫在游动中,尾巴不停摆动,首先生成一个随机数n(第63句),选择列表中第n(0或1)项的造型(第64句),由于n为0或1的概率相同,也就实现了蚊虫尾巴不停摆动。然后移动蚊虫图像(第65句),注意,蚊虫除了沿x轴以self.xi速度移动,在y轴方向也随机移动。蚊虫主要还是沿x轴以设定速度移动,当移出窗体不见后,要反向移动进入窗体,似乎另一蚊虫游入窗体。在y轴方向也要避免移出窗体外。这部分代码在第66-75句。第105句检查小蝌蚪和蚊虫的碰撞,发生碰撞的蚊虫在列表larvaHitList中。发生碰撞的蚊虫将被移到窗体左侧或右侧,似乎消失,从两侧游入的是其它蚊虫。具体蚊虫被移到窗体左侧还是右侧,由随机数n决定(第107句)。n为0,蚊虫被移到左侧(第108-110句),否则被移到右侧(第111-113句)。注意,y轴方向移动也是随机的。
游戏中小蝌蚪随鼠标移动,蝌蚪头部总是指向鼠标,其尾巴不停摆动,碰到蚊虫吃掉后,尺寸变大。定义了小蝌蚪类:class Tadpole(pygame.sprite.Sprite):(第24句),封装了小蝌蚪的这些行为和数据。注意必须有Sprite做为基类,有这个基类,并且定义属性self.rect,才能用第105句检查小蝌蚪和蚊虫的碰撞。在博文“向量学习3:蝌蚪随鼠标移动且蝌蚪头部总是指向鼠标”中详细讨论了实现小蝌蚪随鼠标移动,蝌蚪头部总是指向鼠标的方法,读者可参考有关部分,实现基本思路是:用鼠标当前坐标向量-鼠标前次坐标向量得到鼠标移动向量的角度(第43句),令小蝌蚪头部旋转相同角度(第44句)。不同之处是本例用类进行了封装,增加了尾巴不停摆动,碰到蚊虫吃掉后,尺寸变大。小蝌蚪有两个造型,尾巴向上和尾巴向下,如一帧显示尾巴向上造型,一帧显示尾巴向下造型,就能实现小蝌蚪尾巴摆动动画。但是游戏每秒渲染帧数(fps)太快,使小蝌蚪尾巴也摆动太快,就不像动画了。本程序fps=8,希望降低蝌蚪尾巴摆动周期为0.5秒。见第48-54句,k按0、1、2、3循环,0和1,frameNum=0;2和3,frameNum=1,这样第39句每隔0.25秒取不同造型,周期为0.5秒。小蝌蚪尺寸变大见第41句,self.m越小其尺寸越大,当小蝌蚪吃掉一条蚊虫,即两者发生碰撞,self.m减小,小蝌蚪尺寸变大(第114句)。
本文游戏使用大背景,背景是4个游戏窗口大,即背景的宽和高都是游戏窗口的宽和高的两倍,这就要求小蝌蚪移到游戏窗口左(或右、上和下)边界,同时也移到大背景左(或右、上和下)边界,即背景也要移动。博文“pygame游戏背景使用不分割大图像的方法”中详细介绍了使用不分割大背景图像的方法,使小蝌蚪能游到960*720大图像的任何位置,读者可参考有关部分。上述博文使用键盘控制小蝌蚪移动,而本游戏使用鼠标控制小蝌蚪移动,即小蝌蚪可同时在x轴和y轴方向同时移动,采用向量方法简单些。首先要得到从上帧到本帧鼠标移动向量(第12句),进而通过鼠标移动向量修改self.rect.topleft(第14句),在第23句从大背景取出self.rect指定区域作为背景。
游戏玩起来感觉太容易了,小蝌蚪横冲直撞去吃蚊虫,很快小蝌蚪就变的很胖。改进方法是增加记分功能,吃一只蚊子幼虫加一分。但虫子尺寸可随机改变,蝌蚪去吃尺寸比较大的虫子减一分,这样小蝌蚪就无法横冲直撞去吃蚊虫,吃前必须判断一下,使游戏难度加大。蝌蚪达到一定分数变为青蛙,分数减到某值,蝌蚪死亡。有兴趣读者可自己增加这些功能。
下边是实现该设想的完整程序。注意程序中,用鼠标控制小蝌蚪移动,背景也要反向移动,两者速度相同。

import pygame
import random
class Background():
    def __init__(self,screen):          #screen是游戏主窗体,Surface类实例
        self.screen=screen
        self.oldMouse = pygame.math.Vector2(0,0)
        self.bg_img = pygame.image.load("背景.jpeg").convert()   #背景图像
        self.mouse_pos=None
        self.rect = pygame.Rect(240,180,480,360)    #blit方法第3个参数
    def draw(self):
        mouse=pygame.math.Vector2(self.mouse_pos)   #鼠标位置向量
        mouseMoveV=mouse-self.oldMouse                  #从上帧到本帧鼠标移动向量
        self.oldMouse=mouse                     #下句背景移动应和蝌蚪(鼠标)移动反向        
        self.rect.topleft=self.rect.x+int(mouseMoveV.x),self.rect.y+int(mouseMoveV.y)
        if self.rect.x<0:                   #以下保证不越界
            self.rect.x=0
        if self.rect.x>480:
            self.rect.x=480
        if self.rect.y<0:
            self.rect.y=0
        if self.rect.y>360:
            self.rect.y=360
        self.screen.blit(self.bg_img,(0,0),self.rect)                  #绘制背景 
class Tadpole(pygame.sprite.Sprite):                        #蝌蚪类
    def __init__(self,screen):          #screen是游戏主窗体,Surface类实例
        pygame.sprite.Sprite.__init__(self)
        self.screen=screen
        self.oldMouse = pygame.math.Vector2(0,0)
        self.images=[]
        for n in range(2):          #将2帧图像保存到列表中
            p = pygame.image.load('小蝌蚪'+str(n)+'.png').convert_alpha()#文件名为小蝌蚪0.png,小蝌蚪1.png            
            self.images.append(p)
        self.mouse_pos=None
        self.frameNum=0
        self.k=0
        self.m=3.0
        self.rect=None                              #如使用sprite.Group检测碰撞,必须有此属性
    def draw(self):                                 #主程序调用,实现蝌蚪动画
        p=self.images[self.frameNum]                #从列表取出指定帧的图像
        r=p.get_rect()      
        p=pygame.transform.scale(p,(int(r.width//self.m), int(r.height//self.m)))#调整图像的大小
        mouse=pygame.math.Vector2(self.mouse_pos)   #鼠标位置向量
        r1,angle=(mouse-self.oldMouse).as_polar()       #向量mouse-self.oldMouse为鼠标移动向量
        p=pygame.transform.rotate(p, -angle)        #蝌蚪p1头部转向鼠标移动方向
        self.rect=p.get_rect(center=self.mouse_pos)         #蝌蚪将移到鼠标位置 
        self.oldMouse=mouse     #保存鼠标位置向量,下次新鼠标位置向量将减该向量,得到新鼠标移动向量
        self.screen.blit(p,self.rect)
        if self.k<2:
            self.frameNum=0
        elif self.k<4:
            self.frameNum=1
        self.k+=1
        if self.k==4:
            self.k=0
class Larva(pygame.sprite.Sprite):               #蚊虫类
    def __init__(self,images):                   #images是保存2个蚊虫造型的列表
        pygame.sprite.Sprite.__init__(self)      #父类构造函数
        self.xi=random.randint(1,5)     #蚊虫沿x轴移动速度。随机数保证不同蚊虫速度不同
        self.images=images              #蚊虫造型列表
        self.image=self.images[0]       #取出蚊虫图形,下句是蚊虫初始位置,是随机的
        self.rect=self.image.get_rect(center=(random.randint(10,470),random.randint(10,350)))
    def update(self):        
        n=random.randint(0,1)           #取那个图形是随机的,即蚊虫上下摆尾动作是随机的
        self.image=self.images[n]
        self.rect=self.rect.move(self.xi,random.randint(-10,10))#返回移动后的新位置
        if self.rect.centerx<-25:      #蚊虫越界,沿x轴反向运动
            self.xi=abs(self.xi)
        if self.rect.centerx>505:
            self.xi=-abs(self.xi)
        if self.xi<0:           #如果反向,蚊虫也要转身
            self.image=pygame.transform.flip(self.image,True,False)     #反向
        if self.rect.y<=0:      #保证沿y轴不出界
            self.rect.y+=20
        if self.rect.y>360:
            self.rect.y-=20
pygame.init()
size = width, height = 480,360                      #创建游戏窗口大小
screen = pygame.display.set_mode(size)
pygame.display.set_caption("小蝌蚪吃蚊子幼虫成长")  #设置窗口标题
images=[]                   #列表保存蚊虫两个造型,必须保证两图像等高宽,因2造型共用rect
for n in range(2):          #有蚊虫上下摆尾各1个图像,将2个图像保存到列表中,供所有蚊虫使用
    p=pygame.image.load('虫子'+str(n)+'.png').convert_alpha()#文件名为:虫子0.png,虫子1.png
    r=p.get_rect()      
    p=pygame.transform.scale(p, (r.width//10, r.height//10))    #调整图像的大小
    images.append(p)
allSprites= pygame.sprite.Group()
for i in range(5):
    larva=Larva(images)
    allSprites.add(larva)
background=Background(screen)
tadpole=Tadpole(screen)
fclock = pygame.time.Clock()                        #创建控制频率的clock
fps = 8                                            #定义刷新频率
running = True                                      #程序是否结束,初始运行
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:               #处理退出事件
            running = False                         #程序结束        
    tadpole.mouse_pos=pygame.mouse.get_pos()
    background.mouse_pos=tadpole.mouse_pos    
    background.draw()       #显示背景
    allSprites.draw(screen) #显示组内的所有精灵
    allSprites.update()     #更新组内的所有精灵
    tadpole.draw()  #显示蝌蚪。下句是碰撞检测,False表示不删除Group内发生碰撞sprite
    larvaHitList=pygame.sprite.spritecollide(tadpole,allSprites,False)
    for aLarva in larvaHitList:                 #取出被蝌蚪吃掉蚊虫,使其立即消失
        n=random.randint(0,1)                   #n是随机数,可能是0,也可能是1
        if n==0:                                #如是0,从窗体左侧游出,似新蚊虫游入  
            aLarva.rect.center=(-26,random.randint(10,350))
            aLarva.xi=abs(aLarva.xi)
        else:                                   #如是1,从窗体游侧游出
            aLarva.rect.center=(506,random.randint(10,350))
            aLarva.xi=-abs(aLarva.xi)
        tadpole.m-=0.02     #0.02值变大,蝌蚪变大越快
    pygame.display.flip()                           #刷新游戏场景
    fclock.tick(fps)        #fps是每秒多少帧,减去程序运行时间,为实现fps,还需延迟时间
pygame.quit()

以上是关于pygame游戏_小蝌蚪吃蚊子幼虫成长的主要内容,如果未能解决你的问题,请参考以下文章

召唤神龙游戏源码

向量学习3:蝌蚪随鼠标移动且蝌蚪头部总是指向鼠标

向量学习3:蝌蚪随鼠标移动且蝌蚪头部总是指向鼠标

集训队日常训练20181201 E 1005 : 小蝌蚪

小蝌蚪传记:jscsshtml压缩与混淆汇总

小蝌蚪找妈妈(召唤神龙)源码