'''''''''
@file: Flappy_Bird_Env.py
@author: MRL Liu
@time: 2021/5/2 15:49
@env: Python,Numpy
@desc: 游戏环境
@ref:
@blog: https://blog.csdn.net/qq_41959920
'''''''''
import sys
from itertools import cycle
import pygame
import flappy_bird_utils as tool
import numpy as np
import random
from pygame.locals import *
FPS = 30 # 刷新频率
SCREENWIDTH = 288 # 屏幕宽度
SCREENHEIGHT = 512 # 屏幕高度
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()
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 # 玩家是否上升
def frame_step(self, input_actions,BASEY):
# 检查输入是否正确
if sum(input_actions) != 1:
raise ValueError('Multiple input actions!')
# input_actions[0] == 1: do nothing
# input_actions[1] == 1: flap the bird
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'])) # 玩家
class Flappy_Bird_Env(object):
def __init__(self):
# 初始化窗口
pygame.init() # 初始化游戏,即初始化pygame的各个子模块
self.clock = pygame.time.Clock() # 创建时钟对象,可以控制游戏循环频率
self.screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT)) # 创建游戏窗口(SCREENWIDTH*SCREENHEIGHT)
pygame.display.set_caption('Flappy Bird by MRL') # 设置窗口标题,默认为‘pygame window’
# 定义一些常量
self.IMAGES, self.SOUNDS = tool.load() # 加载游戏资源
self.HITMASKS = tool.get_hitmask(self.IMAGES) # 获取遮罩数据
# 背景图片相关设置
self.BACKGROUND_WIDTH = self.IMAGES['background'].get_width()
# 地面图片相关设置
self.BASEX = 0 # 地面图片的x坐标
self.BASEY = SCREENHEIGHT * 0.79 # 地面图片的y坐标
self.baseShift = self.IMAGES['base'].get_width() - self.BACKGROUND_WIDTH # 地面图片多余出的x距离,用来实现移动效果
# 管道图片相关设置
self.pipeVelX = -4 # 管道移动速度
self.PIPEGAPSIZE = 100 # 上下管道之间的间距
self.PIPE_WIDTH = self.IMAGES['pipe'][0].get_width()
self.PIPE_HEIGHT = self.IMAGES['pipe'][0].get_height()
# 玩家图片相关设置
self.bird = Bird(self.IMAGES['player'],self.screen)
self.reset()
def reset(self):
# 关键变量
self.score = 0
self.bird.reset()
# 获取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']},
]
def frame_step(self,input_actions):
pygame.event.pump() # 让pygame采取默认的事件操作
reward = 0.1
terminal = False
# 绘制背景图像
self.draw_bg()
# 绘制上下管道图像
self.draw_pipes()
# 绘制地面图像
self.draw_base()
# 绘制玩家图像
self.bird.frame_step(input_actions, self.BASEY)
# 检查分数
playerMidPos = self.bird.PlayerInfo['x'] + self.bird.PlayerInfo['w'] / 2
for pipe in self.upperPipes:
pipeMidPos = pipe['x'] + self.PIPE_WIDTH / 2 # 计算上管道的x中点
# 如果此时在一个小范围内
if pipeMidPos <= playerMidPos < pipeMidPos + 4:
self.score += 1
#self.SOUNDS['point'].play()
reward = 1
# 检查是否发生碰撞
isCrash = self.checkCrash(self.bird.PlayerInfo,self.upperPipes, self.lowerPipes)
if isCrash:
#self.SOUNDS['hit'].play()
#self.SOUNDS['die'].play()
terminal = True
self.reset() # 重置
reward = -1
# 绘制分数图像
self.showScore(self.score)
# 将像素拷贝到是一个三维数据中,数组表示为:RGB的颜色整数值
image_data = pygame.surfarray.array3d(pygame.display.get_surface())
# 更新游戏窗口
pygame.display.update()
self.clock.tick(FPS) # 指定循环频率
return image_data,reward, terminal
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)
def draw_bg(self):
self.screen.blit(self.IMAGES['background'], (0, 0)) # 背景,元组参数表示绘制位置,也可以通过Rect矩形类来表示
【Python小游戏】用Python编写小游戏FlappyBird
5星 · 超过95%的资源 需积分: 50 39 浏览量
2021-05-02
22:27:25
上传
评论 2
收藏 6.09MB ZIP 举报
魔法攻城狮MRL
- 粉丝: 225
- 资源: 8
最新资源
- HITK0203MP-VB一款N-Channel沟道SOT23的MOSFET晶体管参数介绍与应用说明
- HITK0202MP-VB一款N-Channel沟道SOT23的MOSFET晶体管参数介绍与应用说
- 电子电气工程师使用的单位和符号
- HITK0201MP-VB一款N-Channel沟道SOT23的MOSFET晶体管参数介绍与应用说明
- MyBatis动态SQL:构建灵活查询的利器.md
- HITJ0303MP-VB一款P-Channel沟道SOT23的MOSFET晶体管参数介绍与应用说明
- tesseract安装包
- 1_32陀螺仪舵机.zip
- HITJ0302MP-VB一款P-Channel沟道SOT23的MOSFET晶体管参数介绍与应用说明
- XILINXFPGA源码PCIExpress标准概述
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
评论5