使用pygame实现的一个复古小游戏
sys中用到用来退出游戏的函数
import pygame,sys
size = width, height = 600,600 #窗口大小
screen = pygame.display.set_mode(size)
pygame.display.set_caption("flybird")
设计机制是游戏处于一个循环体内,不断刷新窗口内的像素位置,形成动画。以下循环展示了进入游戏的初始界面,首先是第一个for循环内的pygame.event.get(),所有的监听器处于这个消息队列中,每次循环都对其进行一次遍历。在我们的游戏中一个是要监听游戏关闭事件pygame.QUIT,另一个就是鼠标点击事件pygame.MOUSEBUTTONDOWN,通过返回鼠标的点击位置来判断是否开始游戏,或是对游戏内小鸟的控制。
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit() #游戏的退出
elif event.type == pygame.MOUSEBUTTONDOWN:
if pygame.mouse.get_pressed()[0]:
loc = pygame.mouse.get_pos()
if (loc[0] > width / 2 -90) and (loc[0] < width / 2 +90) and (loc[1] > height / 2 -80) and (loc [1] < height / 2 +80):
start_fly(screen #进入start_fly表示进入开始游戏之后的循环体
这个项目没有使用任何的图片素材,因此游戏画面内所有的元素由pygame.draw模块绘制完成,并且为了达到这种像素风,仅仅使用了pygame.draw.rect来完成基本矩形的绘制。以下谈到的像素均为自己定义的像素,而非实际像素。
游戏画面采取的是笛卡尔坐标系,以窗口左上角为坐标原点,x轴正方向往屏幕右侧,y轴正方向往屏幕下侧。
- class Pixel: 像素类,用来对定义的像素点做基本的绘制,移动操作。
import pygame class Pixel: """游戏内容均为像素点,实质上为固定大小的矩形""" scale = 0,0 location = 0,0 color = 0,0,0 #构造方法 需要的参数有像素的长宽,起始位置,颜色,均由元组表示。 def __init__(self, scale , location, color): self.scale = scale self.location = location self.color = color def move(self,target): self.location = target def ncolor(self,color): self.color = color def draw(self,screen): pygame.draw.rect(screen,self.color,(self.location,self.scale))
- class element: 这个类通过使用class Pixel:的实例化对象来绘制获得游戏内容。通过改变成员变量 shift[ x, y] 的值来控制图像外接矩形左上角的坐标,改变 speed[ x, y] 来控制图像在x轴及y轴上的平移速度。而该类提供了 move(location) 和 setSpeed(speed) 两个成员方法来改变上述两个量。图片的绘制信息位于 build_BIRD,build_CLOUD ,build_SWITCH ,build_OBSTACLE, LETTER几个变量中。
import pygame from pixel import Pixel class Element: pixelScale = [0,0] #此处的长宽代表像素点的个数 scale = [0,0] mes = [] shifting = [0,0] speed = [1,1] #构造方法,传入欲绘制图像的像素点长宽(元组),整个图像外接矩形的长宽(元组),图片的绘制信息格式为((x,y),color),以此类元组形成的列表传入构造函数 def __init__(self,pixelScale,scale,mes): self.pixelScale = pixelScale self.scale = scale self.mes = mes #将图像绘制到指定的surface对象上 def draw(self,screen): for _ in range(len(self.mes)): location = [(self.mes[_][0][0]-1) * self.pixelScale[0] + self.shifting[0], (self.mes[_][0][1]) * self.pixelScale[1] + self.shifting[1]] color = self.mes[_][1] pixel = Pixel(self.pixelScale,location,color) pixel.draw(screen) def move(self,location): self.shifting = location def setSpeed(self,speed): self.speed = speed
- 开始按钮:
switch = Element((10, 10),(13, 18), build_SWITCH) switch.move((width / 2 - 90,height / 2 - 80))
- 小鸟
# 鸟 bird = Element((3, 3), (11, 17), build_BIRD) bird.move((size[0] / 2 - 60, size[1] / 4)) bird.draw(screen) bird.speed = [0,0]
- 云
cloud_1 = Element((5, 5), (15, 19), build_CLOUD) cloud_1.move((size[0] / 6, size[1] / 5)) cloud_1.setSpeed((-0.7, 0)) cloud_2 = Element((7, 7), (15, 19), build_CLOUD) cloud_2.move((size[0] / 1.2, size[1] / 3)) cloud_2.setSpeed((-1.5, 0)) cloud_3 = Element((10, 10), (15, 19), build_CLOUD) cloud_3.move((size[0] / 2, size[1] / 1.5)) cloud_3.setSpeed((-2, 0))
- 障碍物
obstacle_1_1 = Element((5, 5), (75, 21), build_OBSTACLE) obstacle_1_1.move((size[0], -size[1] / 3.5)) obstacle_1_2 = Element((5, 5), (75, 21), build_OBSTACLE) obstacle_1_2.move((size[0], 1.3*size[1] - obstacle_1_2.scale[0]*obstacle_1_2.pixelScale[0])) obstacle_2_1 = Element((5, 5), (75, 21), build_OBSTACLE) obstacle_2_1.move((size[0] *1.4 , -size[1] / 3.5)) obstacle_2_2 = Element((5, 5), (75, 21), build_OBSTACLE) obstacle_2_2.move((size[0] *1.4, 1.3*size[1] - obstacle_2_2.scale[0]*obstacle_2_2.pixelScale[0])) obstacle_3_1 = Element((5, 5), (75, 21), build_OBSTACLE) obstacle_3_1.move((size[0] *1.7 , -size[1] / 3.5)) obstacle_3_2 = Element((5, 5), (75, 21), build_OBSTACLE) obstacle_3_2.move((size[0] *1.7, 1.3*size[1] - obstacle_3_2.scale[0]*obstacle_3_2.pixelScale[0]))
- 分数
score 用来存储当前分数,游戏结束的时候返回游戏分数这个参数至主界面并显示
#每过一个障碍物加一分,显示分数 score_ten = Element( (10,10),(5,5), LETTER[ int (score / 10) ] ) score_one = Element( (10,10),(5,5), LETTER[ score % 10] ) score_ten.move((10,0)) score_one.move((60,0)) score_ten.draw(screen) score_one.draw(screen)
所有的游戏动画均为平移,因此使用 class Element: 里的 move(location) 和 setSpeed(speed) 足以完成所有的动画效果。小鸟处于确定x坐标的竖直区域运动,云和障碍物不断的左移即可。
在遍历消息队列中。
if pygame.mouse.get_pressed()[0]:
loc = pygame.mouse.get_pos()
#开始新游戏
if (loc[0] > width / 2 - 90) and (loc[0] < width / 2 + 90) and (loc[1] > height / 2 - 80) and (loc[1] < height / 2 + 80):
score = start_fly(screen)
def cloud_animation(cloud):
#若云的整体位置已越过窗口左侧,设置云的外接矩形左上角位于窗口最右侧。
if cloud.shifting[0] < - (cloud.scale[1] * cloud.pixelScale[1]):
cloud.move((size[0], cloud.shifting[1]))
cloud.move(( cloud.shifting[0] + cloud.speed[0], cloud.shifting[1] ))
cloud.draw(screen)
bird.move((bird.shifting[0], bird.shifting[1] + bird.speed[1]))
bird.speed[1] += 1
bird.draw(screen)
监听鼠标右键点击事件对小鸟提供极大的瞬时向上的加速度,达到缓冲小鸟下落的效果,在遍历消息队列中。
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse = pygame.mouse.get_pressed()
if mouse[2]:
bird.speed[1] -= 25
(由于一开始游戏难度过大, 我将障碍物设置为空心,即小鸟不会和障碍物的正下方或正上方相撞,但会和障碍物的侧边相撞) 通过传入一定范围内的随机参数ran控制障碍物从最右端开始向左平移的初始位置。在每个障碍物对象经过小鸟的位置令分数+1,便可完成分数的记录。
def obstacle_animation(obstacle,ran,bird_height):
if obstacle.shifting[0] < - (obstacle.scale[1] * obstacle.pixelScale[1]):
obstacle.move((size[0], obstacle.shifting[1] + ran * (obstacle.scale[1] * obstacle.pixelScale[1]) ))
obstacle.move(( obstacle.shifting[0] - 1, obstacle.shifting[1] ))
obstacle.draw(screen)
if (obstacle.shifting[0] < size[0] / 2) and (obstacle.shifting[0] > size[0] / 2 - 60): #可能发生碰撞的矩形区域
if obstacle.shifting[1] < 0: #和上管道相撞的区域
if obstacle.shifting[1] + 375 >= bird_height: #和上管道右侧相撞的区域
if obstacle.shifting[0] < size[0] / 2:
return True
else: return False
elif obstacle.shifting[0] < size[0] / 2:
if obstacle.shifting[1] + 375 >=bird_height:
return True
else: return False
elif obstacle.shifting[1] < bird_height:
if obstacle.shifting[0] < size[0] / 2:
return True
else: return False
elif obstacle.shifting[0] < size[0] / 2:
if obstacle.shifting[1] < bird_height:
return True
else: return False
(已安装pyinstaller) 在命令行窗口,进入到游戏入口文件的路径下输入命令
pyinstaller -w -F 文件名.py 文件名.py...
打包完成之后可执行文件处于dist目录下。