提示:如果本文对您有帮助,欢迎点赞支持!
前言
1、添加Pipe对象
(1)初始化
(2)重置
(3)帧渲染
(4)实现效果
2、添加Bird对象
(1)初始化
(2)重置
(3)帧渲染
(4)实现效果
在之前的代码中,我们已经实现了一个用Pygame搭建FlappyBird的基本框架,其最终生成效果如下:
现在我们添加继续添加Bird和Pipe对象,让该游戏看起来更加完整。
在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()
获取一个随机管道的位置信息:
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']},
]
首先计算每个管道的位置:
# 计算上下管道的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)) # 地面
最终我们的实现效果就是:
由于Bird比较复杂,所以我们要将其单独初始化为一个类
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()
重置游戏时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 # 玩家是否上升
我们在每帧中渲染的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'])) # 玩家
最终我们的实现效果就是: