前言
1、添加Pipe对象
在之前的代码中,我们已经实现了一个用Pygame搭建FlappyBird的基本框架,其最终生成效果如下:
现在我们添加继续添加Bird和Pipe对象,让该游戏看起来更加完整。
1、添加Pipe对象
(1)初始化
在Flappy_Bird_Env的init中添加如下变量的初始化:
# 管道图片相关设置 self.pipeVelX = -4 # 管道移动速度 self.PIPEGAPSIZE = 100 # 上下管道之间的间距 self.PIPE_WIDTH = self.IMAGES['pipe'][0].get_width() self.PIPE_HEIGHT = self.IMAGES['pipe'][0].get_height()
(2)重置
获取一个随机管道的位置信息:
def getRandomPipe(self): """随机获取一个管道的x和y的参数""" # 随机获取一个管道间距距离 gapYs = [20, 30, 40, 50, 60, 70, 80, 90] #上管道的y坐标 index = random.randint(0, len(gapYs) - 1) gapY = gapYs[index] gapY += int(self.BASEY * 0.2) pipeX = SCREENWIDTH + 10 return [ {'x': pipeX, 'y': gapY - self.PIPE_HEIGHT}, # 上管道 {'x': pipeX, 'y': gapY + self.PIPEGAPSIZE}, # 下管道 ]
在reset函数中继续写管道的初始信息,reset被Flappy_Bird_Env的init调用:
def reset(self): # 获取2个新的pipes newPipe1 = self.getRandomPipe() newPipe2 = self.getRandomPipe() # 屏幕显示的上管道列表 self.upperPipes = [ {'x': SCREENWIDTH, 'y': newPipe1[0]['y']}, # 屏幕上第1个管道 {'x': SCREENWIDTH + (SCREENWIDTH / 2), 'y': newPipe2[0]['y']},# 屏幕上第2个管道 ] # 屏幕显示的下管道列表 self.lowerPipes = [ {'x': SCREENWIDTH, 'y': newPipe1[1]['y']}, {'x': SCREENWIDTH + (SCREENWIDTH / 2), 'y': newPipe2[1]['y']}, ]
(3)帧渲染
首先计算每个管道的位置:
# 计算上下管道的x坐标 for uPipe, lPipe in zip(self.upperPipes, self.lowerPipes): uPipe['x'] += self.pipeVelX lPipe['x'] += self.pipeVelX # 如果第一个管道的x坐标小于5但是大于0时提前生成一个新管道到列表中 if 0 < self.upperPipes[0]['x'] < 5: newPipe = self.getRandomPipe() self.upperPipes.append(newPipe[0]) self.lowerPipes.append(newPipe[1]) # 如果第一个管道的x坐标完全离开管道时就将其移除 if self.upperPipes[0]['x'] < -self.PIPE_WIDTH: self.upperPipes.pop(0) self.lowerPipes.pop(0)
渲染管道图片,注意渲染顺序:
# 绘制背景图像 self.screen.blit(self.IMAGES['background'], (0, 0)) # 背景,元组参数表示绘制位置,也可以通过Rect矩形类来表示位置 # 绘制上下管道图像 for uPipe, lPipe in zip(self.upperPipes, self.lowerPipes): self.screen.blit(self.IMAGES['pipe'][0], (uPipe['x'], uPipe['y'])) self.screen.blit(self.IMAGES['pipe'][1], (lPipe['x'], lPipe['y'])) # 绘制地面图像 self.screen.blit(self.IMAGES['base'], (self.BASEX, self.BASEY)) # 地面
(4)实现效果
最终我们的实现效果就是:
2、添加Bird对象由于Bird比较复杂,所以我们要将其单独初始化为一个类
(1)初始化
class Bird(object): def __init__(self,_Player_Sprite,_screen): self.screen = _screen # 玩家图片相关设置 self.Player_Sprite = _Player_Sprite # 加载图片资源 self.PlayerInfo = {} # 创建一个玩家信息字典 self.PlayerInfo['w'] = self.Player_Sprite[0].get_width() # 获取玩家图片的宽度 self.PlayerInfo['h'] = self.Player_Sprite[0].get_height() # 获取玩家图片的高度 self.PLAYER_INDEX_GEN = cycle([0, 1, 2, 1]) # 图片序列的循环 self.playerMaxVelY = 10 # 玩家在y轴上的最大速度 self.playerMinVelY = -8 # 玩家在y轴上的最小速度 self.playerAccY = 1 # 玩家在y轴上的下降的加速度 self.playerFlapAcc = -7 # 玩家在y轴上的上升的加速度,向下为正方向 # 重置游戏设置w self.reset()
(2)重置
重置游戏时Bird的调用函数:
def reset(self): self.loopIter = 0 self.PlayerInfo['x'] = int(SCREENWIDTH * 0.2) # 玩家初始位置x self.PlayerInfo['y'] = int((SCREENHEIGHT - self.PlayerInfo['h']) / 2) # 玩家初始位置y self.PlayerInfo['index'] = 0 # 玩家初始帧序列 self.playerVelY = 0 # 玩家在y轴上的速度,向下为正方向 self.playerFlapped = False # 玩家是否上升
(3)帧渲染
我们在每帧中渲染的Bird图片是不一样的,这样就可以实现小鸟的动画效果:
def frame_step(self, input_actions,BASEY): # 计算玩家序列帧 if (self.loopIter + 1) % 3 == 0: self.PlayerInfo['index'] = next(self.PLAYER_INDEX_GEN) self.loopIter = (self.loopIter + 1) % 30 # 绘制玩家图像 self.screen.blit(self.Player_Sprite[self.PlayerInfo['index']], (self.PlayerInfo['x'], self.PlayerInfo['y'])) # 玩家
(4)实现效果
最终我们的实现效果就是:
图片来源:http://www.lyouxi.com/ 手游