提示:如果本文对您有帮助,欢迎点赞支持!
文章目录
1、玩家控制Bird
在该游戏中玩家只需要按空格或者up键来控制输入,玩家每按一次,小鸟就向上飞行一小段距离,这也是该游戏的特点
(1)更改游戏主循环
我们在游戏主循环中添加接收玩家输入事件的判断程序,如下:
def run_game(self):
while True:
is_flap = False # 是否让小鸟飞翔
# 遍历系统的事件列表
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE): # 退出事件,Esc
pygame.quit()
sys.exit()
if event.type == KEYDOWN and (event.key == K_SPACE or event.key == K_UP): # 按下空格或者上方向键
actions = np.array([0, 1]) # 让小鸟飞翔
self.frame_step(input_actions=actions)
is_flap = True
# 如果没有接收到输入就让小鸟降落
if not is_flap:
actions = np.array([1, 0]) # 让小鸟降落
self.frame_step(input_actions=actions)
从程序中我们可以看到,我们输入一个OneHot形式的数组来区别两个不同的动作:
# input_actions[0] == 1: 小鸟下降 # input_actions[1] == 1: 小鸟上升
(2)更改游戏帧渲染
我们然后我们在Bird类的帧渲染函数中如下修改:
def frame_step(self, input_actions,BASEY):
# 检查输入是否正确
if sum(input_actions) != 1:
raise ValueError('Multiple input actions!')
if input_actions[1] == 1:
if self.PlayerInfo['y'] > -2 * self.PlayerInfo['h']:
self.playerVelY = self.playerFlapAcc # 速度方向一下变为朝上
self.playerFlapped = True
# SOUNDS['wing'].play()
# 玩家的移动
if self.playerVelY < self.playerMaxVelY and not self.playerFlapped: #如果y速度没有最大且没有上升时
self.playerVelY += self.playerAccY
if self.playerFlapped:
self.playerFlapped = False
self.PlayerInfo['y'] += min(self.playerVelY, BASEY - self.PlayerInfo['y'] - self.PlayerInfo['h'] )# 在y的速度和离地面的距离中取一个最小值
if self.PlayerInfo['y'] < 0: # 玩家的最高位置
self.PlayerInfo['y'] = 0
# 计算玩家序列帧
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'])) # 玩家
此时我们就可以判断用户的输入,并控制小鸟的动作了
2、Bird的碰撞检测
(1)更改游戏帧渲染
在上述的代码中,我们虽然已经实现了小鸟的运动,但是并没有实现Bird的碰撞检测,此时的Bird可以穿过Pipe,所以我们要在游戏的帧渲染函数中继续添加碰撞检测的代码。
# 绘制玩家图像
self.bird.frame_step(input_actions, self.BASEY)
# 检查是否发生碰撞
isCrash = self.checkCrash(self.bird.PlayerInfo,self.upperPipes, self.lowerPipes)
if isCrash:
#self.SOUNDS['hit'].play()
#self.SOUNDS['die'].play()
self.reset() # 重置
(2)碰撞检测函数
def checkCrash(self,player, upperPipes, lowerPipes):
"""检查玩家是否碰撞到管道和地面"""
pi = player['index']
# 检查是否碰到地面
if player['y'] + player['h'] >= self.BASEY - 1:
return True
else:
playerRect = pygame.Rect(player['x'], player['y'],
player['w'], player['h'])
for uPipe, lPipe in zip(upperPipes, lowerPipes):
# upper and lower pipe rects
uPipeRect = pygame.Rect(uPipe['x'], uPipe['y'], self.PIPE_WIDTH, self.PIPE_HEIGHT)
lPipeRect = pygame.Rect(lPipe['x'], lPipe['y'], self.PIPE_WIDTH, self.PIPE_HEIGHT)
# player and upper/lower pipe hitmasks
pHitMask = self.HITMASKS['player'][pi]
uHitmask = self.HITMASKS['pipe'][0]
lHitmask = self.HITMASKS['pipe'][1]
# if bird collided with upipe or lpipe
uCollide = tool.pixelCollision(playerRect, uPipeRect, pHitMask, uHitmask)
lCollide = tool.pixelCollision(playerRect, lPipeRect, pHitMask, lHitmask)
if uCollide or lCollide:
return True
return False
(3)像素级碰撞检查
def pixelCollision(rect1, rect2, hitmask1, hitmask2):
"""检查两个矩形是否发生像素级碰撞"""
rect = rect1.clip(rect2) #获取两个Rect对象互相重叠的部分
# 如果重叠部分不存在则没有发生碰撞
if rect.width == 0 or rect.height == 0:
return False
# 遍历两个碰撞遮罩的重叠部分的alpha的值都不为0则发生了碰撞
x1, y1 = rect.x - rect1.x, rect.y - rect1.y
x2, y2 = rect.x - rect2.x, rect.y - rect2.y
for x in range(rect.width):
for y in range(rect.height):
if hitmask1[x1 + x][y1 + y] and hitmask2[x2 + x][y2 + y]:
return True
return False