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游戏_小蝌蚪吃蚊子幼虫成长的主要内容,如果未能解决你的问题,请参考以下文章