#### 4.1 需求分析
特点:
1、播放与停止背景音乐
2、随机生成管道与导弹障碍
3、显示积分
4、跳跃躲避障碍
5、碰撞障碍
6、游戏音效
#### 4.2 系统设计
##### 4.2.1 系统功能结构
音效
- 背景音乐的播放与停止
- 动作音效(跳跃,加分。碰撞)
主窗体:
- 移动的玛丽
- 滚动的地图
- 碰撞
- 积分
随机障碍
- 飞行的导弹
- 管道
##### 4.2.2 系统业务流程
用户 --> 主窗体 --> 随机出现障碍 -->躲避障碍 --> 验证 --> (是) 添加积分
验证--> (否) 碰撞 ---> 结束 ---> 主窗体
#### 4.3 系统开发必备
##### 4.3.1 开发工具必备
开发运行环境:
操作系统:win7,win10
python版本:3.7
内置模块:itertools,random
第三方模块:pygame
##### 4.3.2 文件夹组织架构
marie_adventure -- 项目包
- audio --- 保存音效文件
- image --- 保存图片
- marie.py -- 游戏文件
#### 4.4 实现
##### 4.4.1 游戏窗体的实现
开始 → 1、定义窗体大小/2、定义更新画面的时间 -->
---> 初始化:应用 init()函数
---> 循环更新窗体 (应用:pygame.display.update()方法)
---> 是否关闭窗体 ---> 是 ---> 关闭 ---> 结束
-----> 否 ---> 循环更新窗体
具体步骤:
(1) 创建文件夹
(2) 导入pygame库和pygame中的常量库,定义窗体的宽度和高度
```python
import pygame
from pygame.locals import * # 导入pygame中的常量
import sys # 系统模块
SCREENWIDTH = 822 # 窗口宽度
SCREENHEIGHT = 199 # 窗口高度
FPS = 30 # 更新画面的时间
```
(3) 创建mainGame()方法。在该方法中首先进行pygame的初始化工作,然后创建时间对象用于更新窗体中的画面,再创建窗体实例并设置窗体的标题文字,最后通过循环实现窗体的显示与刷新
```
def mainGame():
score = 0
over = False
global SCREEN, FPSCLOCK
pygame.init() # 初始化pygame
# 使用python时钟控制每个循环多长时间运行一次,
```
##### 4.4.2 地图加载
```
```
##### 4.4.3 跳跃功能
1、指定玛丽的固定坐标(默认显示在地图上的固定位置),
2、判断是否按下<space>键,按下了就开启跳跃开关,以5个像素的距离向上移动
3、当玛丽到达窗体顶部的边缘时,再让其以5个像素的距离向下移动,回到地面后关闭跳跃的开关
开始 --- > 创建Marie类(加载图片)<应用:init()函数> ---> 是否按下空格键 --- 是 ---> 玛丽是否在地面 ---是--> 实现玛丽跳跃 应用:marie.jump_audio.play()方法, jump()函数 ,move()函数 , draw_marie()函数。
具体步骤:
(1)导入迭代工具,创建一个名称为Marie的玛丽类,然后在该类的初始化方法中,首先定义玛丽跳跃时所需要的变量,然后加载玛丽跑动的三张照片,最后加载玛丽跳跃时的音效并设置玛丽默认显示的坐标位置,
```python
from itertools import cycle # 导入迭代工具
class Marie():
def __init__(self):
# 初始化玛丽矩形
self.rect = pygame.Rect(0,0,0,0)
self.jumpState = False # 跳跃的状态
self.jumpHeight = 130 # 跳跃的高度
self.lowest_y = 140 # 最低坐标
self.jumpValue = 0 # 跳跃增变量
# 玛丽动图索引
self.marieIndex = 0
self.marieIndexGen = cycle([0,1,2])
# 加载玛丽图片
self.adventure_img = (
pygame.image.load('image/adventure1.png').convert_alpha(),
pygame.image.load('image/adventure2.png').convert_alpha(),
pygame.image.load('image/adventure3.png').convert_alpha(),
)
self.jump_audio = pygame.mixer.Sound('audio/jump.wav') # 跳音效
self.recv.size = self.adventure_img[0].get_size()
self.x = 50; # 绘制玛丽的x坐标
self.y = self.lowest_y # 绘制玛丽的y坐标
self.rect.topleft =(self.x, self.y)
```
(2)在Marie类中创建jump()方法,通过该方法实现开启跳跃的开关,
```python
# 跳状态
def jump(self):
self.jumpState = True
```
(3)在Marie类中创建move()方法,在该方法中判断如果玛丽的跳跃开关开启时,再判断玛丽是否在地面上,如果满足这两个条件玛丽就以五个像素的距离向上移动,当玛丽到达窗体顶部时以5个像素的距离向下移动,当玛丽回到地面后关闭跳跃开关
```
# 玛丽移动
def move(self):
if self.jumpState:
if self.rect.y >= self.lowest_y:
self.jumpValue = -5
if self.rect.y <= self.lowest_y - self.jumpHeight:
self.jumpValue = 5
self.rect.y += self.jumpValue
if self.rect.y >= self.lowest_y:
self.jumpState = False
```
##### 4.4.4 随机出现的障碍
##### 4.4.5 背景音乐的播放与停止
##### 4.4.6 碰撞和积分的实现
开始 -- 循环执行游戏(障碍物与玛丽) --> 是否发生碰撞 --> Y --> 游戏结束:应用:game_over函数 --> 结束
---> N --> 是否越过障碍 --> Y --> 加分,应用:getScore()函数 -->循环执行游戏..
实现碰撞和积分功能的具体步骤如下:
(1)Obstacle类中,draw_obstacle()方法的下面创建getScore()方法用于获取分数并播放加分音效,然后创建showScore()方法用于在窗体顶部右侧的位置显示分数。
```python
# 获取分数
def getScore(self):
tmp = self.score
if tmp == 1;
self.score_audio.play() # 播放加分音乐 ??
self.score = 0
return tmp
# 显示分数
def showScore(self,score):
# 获取得分数字
self.scoreDigits = [int(x) for x in list(str(score))]
totalWidth = 0 # 要显示的所有数字的总宽度
for digit in self.scoreDigits:
# 获取积分图片的宽度
totalWidth += self.numbers[digit].get_width()
# 分数横向位置
Xoffset = (SCREENWIDTH - (totalWidth+30))
for digit in self.scoreDigits:
# 绘制分数
SCREEN.blit(self.numbers[digit],(Xoffset,SCREENHEIGHT*0.1))
# 随着数字增加改变位置
Xoffset += self.numbers[digit].get_width()
```
(2) 在mainGame()方法的上面最外层创建game_over()方法,在该方法中首先需要加载与播放撞击的音效,然后获取窗体的宽度与高度,最后加载游戏结束的图片并将该图片显示在窗体的中间位置,代码如下:
```python
# 游戏结束的方法
def game_over():
bump_audio = pygame.mixer.Sound('audio/bump.wav') # 撞击
bump_audio.play() # 播放撞击音效
# 获取窗体宽,高
screen_w = pygame.display.Info().current_W
screen_h = pygame.display.Info().current_h
# 加载游戏结束的图片
over_img = pygame.image.load('image/gameover.png').convert_alpha()
# 将游戏结束的图片绘制在窗体的中间位置
SCREEN.blit(over_img,((screen_w - over_img.get_width())/2,(screen_h - over_img.get_height())/2))
```
(3) 在mainGame()方法中,绘制障碍物代码的下面判断玛丽与障碍物是否发生碰撞,如果发生了碰撞则开启游戏结束的开关,并调用游戏结束的方法显示游戏结束的图片,否则判断玛丽是否越过了障碍物,越过就进行分数的增加并显示当前得分,代码如下
```python
# 判断玛丽与障碍物是否碰撞
if pygame.sprite.collide_rect(marie, list[i]):
over = True # 碰撞后开启结束开关
game_over() # 调用游戏结束的方法
music_button.bg_music.stop()
else:
# 判断玛丽是否越过障碍物
if(list[i].rect.x + list[i].rect.width) < marie.rect.x:
# 加分
score += list[i].getScore()
# 显示分数
list[i].showScore(score)
```
(4) 为了实现游戏结束后再次按下键盘上的<space>(空格)键时,重新启动游戏。所以需要在mainGame()方法中开启玛丽跳的状态代码的下面判断游戏结束的开关是否开启,如果开启将重新调用mainGame()方法重新启动游戏,代码如下
```python
if over == True: # 判断游戏结束的开关是否开启
mainGame() # 如果开启将调用mainGame方法重启游戏
```
#### 4.5 小结
pygame为核心模块
itertools实现动态图片的迭代
random产生随机数字,实现障碍物的随机出现