前言
本次开发的游戏为炸弹人游戏,是一个经典的小游戏,4399、7k7k等上面就可以找到,本游戏基于python语言,基于pygame开发,pygame是 跨平台 Python模块,专为电子游戏设计。 包含图像、声音。建立在SDL基础上,允许实时电子游戏研发而无需被低阶语言,如C语言或是更低阶的组合语言束缚。
实现游戏概述
炸弹人游戏,一个主机玩家和两个AI玩家,在地图场景内主机玩家可按空格投放炸弹,主机玩家用‘↑’‘↓’‘←’‘→’四个方向键进行四个方位移动,AI玩家电脑随机移动,地图中有墙面进行格挡,炸弹爆炸不可透墙,每个玩家有50生命值,炸弹爆炸效果持续一秒,玩家在爆炸范围内会受到持续伤害,主机玩家炸死两个AI玩家即通关下一关,一共设置两个关卡,游戏右上角有暂停键可以暂停游戏,左上角显示三个玩家的生命值,游戏开始会随机投放水果,不同水果可以恢复不同血量。每个玩家的生命值都有上限,满血吃水果不补生命值。
游戏结构
系统结构
系统模块
1.选择模块
需要起码两个按钮,一个退出按钮,以及一个复用功能按钮,使用监听事件监听按钮是否被点击,按钮实现是使用pygame.draw绘制在屏幕上,所以监听事件监听的是整个按钮区域是否被点击。
外加一张美观的背景图
复用功能按钮:按钮位置不变,代表含义不同,“下一关”,“重生”,“开始”,具体
开始界面
下一关界面
重生界面
胜利界面
2.游戏模块
游戏屏幕里出现的所有一切都可以定义为一个个游戏元素,每一个游戏元素都有一个共性,所有的游戏元素都需要坐标,显示的高度和宽度,以及显示的图片,所以游戏元素定义一个游戏基类,所有共性可以提炼到游戏基类,游戏基类继承pygame.sprite.Sprite,所有的游戏元素继承游戏基类。
3.地图模块
解析.map文件,每张地图的每一行信息用一个列表存储,再把每一行列表信息加到一个列表中,可以理解为一个二维数组。解析完再将遍历整个列表,将列表中的每一个游戏元素,调用游戏元素自身的draw方法绘制到屏幕上,整个列表遍历完地图绘制完成。实现在地图上获取空地功能,可以方便水果的绘制以及游戏角色的降临。
第一关地图.map文件
第二关地图.map文件
4.资源模块
我觉得很有必要划为一个模块,程序的可移植性会变的更加可观,任何资源的地址都使用宏定义资源位置更改只需更改资源模块的定义即可。包括地图使用.map文件存储,map是一种图像数据调用文件,可以模拟场景。先将游戏元素设置标记,即给定代号,然后调用通过解析成对应的游戏元素就可以显示出来
主机玩家
AI玩家1
AI玩家2
背景块
墙块
水果
炸弹和爆炸效果
5.游戏主模块
游戏中所有的规定都在此模块实现,游戏一开始是选择画面,选择进入游戏或者退出,如果进行游戏,游戏地图使用一个循环遍历,一张地图过关再进入下一张地图,游戏开始循环刷新游戏面,每秒三十帧,每张地图开端会随机获取几块空地,投放水果以供恢复血量,玩家用方向键控制主机角色移动,空格投放炸弹,AI角色随机移动随机投放炸弹,玩家生命值为0失败,又是进入重生页面,两个AI生命值为0,玩家获胜选择下一关页面,所有地图过关胜利,显示获胜画面,获胜后可以退出或重新游戏。
实现代码
1 GameSprites.py
1.1 设计游戏基类
GameSprites继承pygame.sprite.Sprite
初始化方法:
用于获取图片,图片坐标以及图片大小
def __init__(self, imagepath, coordinate, blocksize, **kwargs):
super().__init__(self)
self.image = pygame.image.load(imagepath)
#缩放函数,设置图片大小,按每个图片都缩小为30*30
self.image = pygame.transform.scale(self.image, (blocksize, blocksize))
self.rect = self.image.get_rect()
self.rect.x, self.rect.y = coordinate[0] * blocksize, coordinate[1] * blocksize
self.coordinate = coordinate
self.blocksize = blocksize
1.2 基于游戏基类的屏幕元素
游戏屏幕中的元素都基于GameSprites
1.2.1 Wall
墙,作为游戏中的障碍物,可以隔断爆炸,阻拦角色移动,直接在初始化方法时候传入参数调用父类即可,draw绘制墙元素在屏幕上
class Wall(GameSprites):
def __init__(self, imagepath, coordinate, blocksize, **kwargs):
super().__init__(self, imagepath, coordinate, blocksize, **kwargs)
def draw(self, screen):
screen.blit(self.image, self.rect)
return True
1.2.2 Background
背景类Background,初始化调用父类初始化,有三种背景色供选择,所以背景是一小块一小块的绘制
class Background(GameSprites):
def __init__(self, imagepath, coordinate, blocksize, **kwargs):
super().__init__(imagepath, coordinate, blocksize)
def draw(self, screen):
screen.blit(self.image, self.rect)
return True
1.2.3 Fruit
用于恢复生命值的水果类
在父类GameSprites的基础上加入属性分类,不同的水果恢复生命值不一样
class Fruit(GameSprites):
def __init__(self, imagepath, coordinate, blocksize, **kwargs):
super().__init__(imagepath, coordinate, blocksize)
self.kind = imagepath.split('/')[-1].split('.')[0]
if self.kind == 'peach':
self.value = 5
elif self.kind == 'pineapple':
self.value = 10
else:
raise ValueError('Unknow fruit <%s>...' % self.kind)
def draw(self, screen):
screen.blit(self.image, self.rect)
return True
1.2.4 Bomb
炸弹类:用定时器进行定时爆炸,由玩家与AI端持有技能,用于炸伤炸死敌人
功能:炸弹能进行倒计时,有一定范围的爆炸,不可穿墙,爆炸效果持续一秒
1.2.4.1 Bomb的初始化函数
在父类的基础上增加属性
explode_image:存放爆炸效果图
explode_millisecond:爆炸倒计时最大值,毫秒级
explode_second:显示于炸弹上的秒数
start_explode:爆炸效果持续时间
explode_count:爆炸持续时间
harm_value:伤害生命值
is_being:判断炸弹是否存在
font:倒计时显示的数字字体以及大小设置
digitalcolor:倒计时数字颜色
def __init__(self, imagepath, coordinate, blocksize, digitalcolor, explode_imagepath, **kwargs):
super().__init__(self, imagepath, coordinate, blocksize, **kwargs)
self.explode_image = explode_imagepath
self.explode_millisecond = 6000 * 1 - 1
self.explode_second = int(self.explode_millisecond / 1000)
self.start_explode = False
self.explode_count = 1000 * 1
self.harm_value = 1
self.is_being = True
self.font = pygame.font.SysFont('my_font.ttf', 20)
self.digitalcolor = digitalcolor
1.2.4.2 draw 函数将炸弹显示到屏幕上
dt:计时
map_parser:地图
def draw(self, screen, dt, map_parser):
if not self.start_explode:
# 进行爆炸倒计时
self.explode_millisecond -= dt
self.explode_second = int(self.explode_millisecond / 1000)
if self.explode_millisecond < 0:
self.start_explode = True
screen.blit(self.image, self.rect)
text = self.font.render(str(self.explode_second), True, self.digitalcolor)
rect = text.get_rect(center=(self.rect.centerx-5, self.rect.centery+5))
screen.blit(text, rect)
return False
else:
# 爆炸效果持续倒计时
self.exploding_count -= dt
if self.exploding_count > 0:
return self.__explode(screen, map_parser)
else:
self.is_being = False
return False
1.2.4.3 __calcExplodeArea计算爆炸区域
区域计算规则为墙可以阻止爆炸扩散, 且爆炸范围仅在游戏地图范围内
instances_list:
ymin: 爆炸高端,不可超过屏幕顶端
ymax: 爆炸低端,不可超过屏幕底端
xmin: 爆炸左端,不可超过屏幕左端
xmax: 爆炸右端,不可超过屏幕右端
explode_area: 爆炸区域
def __calcExplodeArea(self, instances_list):
explode_area = []
for ymin in range(self.coordinate[1], self.coordinate[1]-5, -1):
if ymin < 1 or instances_list[ymin][self.coordinate[0]] in ['w', 'x', 'z']:
break
explode_area.append([self.coordinate[0], ymin])
for ymax in range(self.coordinate[1]+1, self.coordinate[1]+5):
if ymax >= len(instances_list) or instances_list[ymax][self.coordinate[0]] in ['w', 'x', 'z']:
break
explode_area.append([self.coordinate[0], ymax])
for xmin in range(self.coordinate[0], self.coordinate