前言

本次开发的游戏为炸弹人游戏,是一个经典的小游戏,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*30self.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] * blocksizeself.coordinate = coordinateself.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 = 5elif self.kind == 'pineapple':self.value = 10else: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_imagepathself.explode_millisecond = 6000 * 1 - 1self.explode_second = int(self.explode_millisecond / 1000)self.start_explode = Falseself.explode_count = 1000 * 1self.harm_value = 1self.is_being = Trueself.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 -= dtself.explode_second = int(self.explode_millisecond / 1000)if self.explode_millisecond < 0:self.start_explode = Truescreen.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 Falseelse:# 爆炸效果持续倒计时self.exploding_count -= dtif self.exploding_count > 0:return self.__explode(screen, map_parser)else:self.is_being = Falsereturn 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']:breakexplode_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']:breakexplode_area.append([self.coordinate[0], ymax])for xmin in range(self.coordinate[0], self.coordinate[0]-5, -1):if xmin < 0 or instances_list[self.coordinate[1]][xmin] in ['w', 'x', 'z']:breakexplode_area.append([xmin, self.coordinate[1]])for xmax in range(self.coordinate[0]+1, self.coordinate[0]+5):if xmax >= len(instances_list[0]) or instances_list[self.coordinate[1]][xmax] in ['w', 'x', 'z']:breakexplode_area.append([xmax, self.coordinate[1]])return explode_area

1.2.4.3 __explode爆炸效果
通过explode_area将爆炸效果图显示在该坐标上

def __explode(self, screen, map_parser):explode_area = self.__calcExplodeArea(map_parser.instances_list)for each in explode_area:image = pygame.image.load(self.explode_imagepath)image = pygame.transform.scale(image, (self.blocksize, self.blocksize))rect = image.get_rect()rect.left, rect.top = each[0] * self.blocksize, each[1] * self.blocksizescreen.blit(image, rect)return explode_area

1.2.5 Role
角色类:角色进行四个方位的移动上下左右,有角色名称用于区分玩家和AI,每个角色都有生命值,都可以获取水果加生命值,每个角色的四个方位移动会对应着四个朝向,可以生成炸弹,AI会进行随机方位的移动,玩家用‘↑’‘↓’‘←’‘→’方向键进行移动
3.1.2.5.1 Role的初始化函数
直接继承于pygame.sprite.Sprite,角色有四个动作,所以每个角色的绘制图片有四张,游戏基类的初始化方法有冲突
role: 角色名称
health_value: 角色生命值
max_value: 角色最大生命值
bomb_cooling_time: 炸弹冷却时间
bomb_cooling_count: 炸弹冷却时间计时
randommove_cooling_time: 随机移动冷却时间(AI专用)
randommove_cooling_count: 随机移动冷却时间计时(AI专用)
map_parser: 地图

def __init__(self, imagepaths, coordinate, blocksize, map_parser, **kwargs):pygame.sprite.Sprite.__init__(self)self.imagepaths = imagepathsself.image = pygame.image.load(imagepaths[-1])self.image = pygame.transform.scale(self.image, (blocksize, blocksize))self.rect = self.image.get_rect()self.rect.left, self.rect.top = coordinate[0] * blocksize, coordinate[1] * blocksizeself.coordinate = coordinateself.blocksize = blocksizeself.map_parser = map_parserself.role = kwargs.get('role_name')# 生命值self.health_value = 50self.max_value = 50# 炸弹冷却时间self.bomb_cooling_time = 5000self.bomb_cooling_count = 0# 随机移动冷却时间(仅AI电脑用)self.randommove_cooling_time = 100self.randommove_cooling_count = 0

1.2.5.2 move
玩家角色进行移动,分为上下左右四个方位,墙体阻挡角色的移动,以及在游戏屏幕界限内,不可以超过计分区域
实现具体方法,角色坐标限则在游戏屏幕内,特别的顶端限制在计分区域下,下一步到达墙类元素止步

def move(self, direction):self.__updateImage(direction)if direction == 'left':if self.coordinate[0]-1 < 0 or self.map_parser.getElemByCoordinate([self.coordinate[0]-1, self.coordinate[1]]) in ['w', 'x', 'z']:return Falseself.coordinate[0] = self.coordinate[0] - 1elif direction == 'right':if self.coordinate[0]+1 >= self.map_parser.width or self.map_parser.getElemByCoordinate([self.coordinate[0]+1, self.coordinate[1]]) in ['w', 'x', 'z']:return Falseself.coordinate[0] = self.coordinate[0] + 1elif direction == 'up':if self.coordinate[1]-2 < 0 or self.map_parser.getElemByCoordinate([self.coordinate[0], self.coordinate[1]-1]) in ['w', 'x', 'z']:return Falseself.coordinate[1] = self.coordinate[1] - 1elif direction == 'down':if self.coordinate[1]+1 >= self.map_parser.height or self.map_parser.getElemByCoordinate([self.coordinate[0], self.coordinate[1]+1]) in ['w', 'x', 'z']:return Falseself.coordinate[1] = self.coordinate[1] + 1else:raise ValueError('Unknow direction <%s>...' % direction)self.rect.left, self.rect.top = self.coordinate[0] * self.blocksize, self.coordinate[1] * self.blocksizereturn True

1.2.5.2 randomAction
该类提供AI进行随机的移动
使AI随机方位的移动并且小概率的投放炸弹,随机移动冷却时间为0.1秒,炸弹爆炸冷却时间为5秒
randommove_cooling_time: 随机移动冷却时间(AI专用)
randommove_cooling_count: 随机移动冷却时间计时(AI专用)
action: 接下来的动作

def randomAction(self, dt):if self.randommove_cooling_count > 0:self.randommove_cooling_count -= dtaction = random.choice(['left', 'left', 'right', 'right', 'up', 'up', 'down', 'down', 'dropbomb'])flag = Falseif action in ['left', 'right', 'up', 'down']:if self.randommove_cooling_count <= 0:flag = Trueself.move(action)self.randommove_cooling_count = self.randommove_cooling_timeelif action in ['dropbomb']:if self.bomb_cooling_count <= 0:flag = Trueself.bomb_cooling_count = self.bomb_cooling_timereturn action, flag
3.1.2.5.2 generateBomb
生成炸弹,调用Bomb类生成炸弹
def generateBomb(self, imagepath, digitalcolor, explode_imagepath):return Bomb(imagepath=imagepath, coordinate=copy.deepcopy(self.coordinate), blocksize=self.blocksize, digitalcolor=digitalcolor, explode_imagepath=explode_imagepath)

1.2.5.2 draw
将角色显示到屏幕上,并进行角色投放炸弹之后的倒计时

def draw(self, screen, dt):if self.bomb_cooling_count > 0:self.bomb_cooling_count -= dtscreen.blit(self.image, self.rect)return True

1.2.5.2 eatFruit
角色进行吃水果恢复血量,角色覆盖水果位置,水果消失,角色类生命值增加,生命值达到上限则保持在生命值上限。

def eatFruit(self, fruit_sprite_group):eaten_fruit = pygame.sprite.spritecollide(self, fruit_sprite_group, True, None)for fruit in eaten_fruit:self.health_value += fruit.valueif self.health_value > self.health_maxvalue:self.health_value = self.health_maxvalue

1.2.5.2 __updateImage
更新角色朝向

def __updateImage(self, direction):directions = ['left', 'right', 'up', 'down']idx = directions.index(direction)self.image = pygame.image.load(self.imagepaths[idx])self.image = pygame.transform.scale(self.image, (self.blocksize, self.blocksize))

2 choice.py
#选择模块
import sys
import pygame
2.1 showText
在屏幕指定位置显示文字
text: 要显示的文字内容
font.render:
参数一:显示的内容
参数二:是否开启抗锯齿,就是说True的话字体会比较平滑,不过相应的速度有一点点影响
参数三:字体颜色
position: 文字显示坐标

def showText(screen, font, text, color, position):text_render = font.render(text, True, color)rect = text_render.get_rect()rect.left, rect.top = positionscreen.blit(text_render, rect)return rect.right

2.2 Button
绘制按钮
linecolor: 按钮边框颜色,金色
buttoncolor: 按钮颜色,洋红色
textcolor:字体颜色,白色
四条线条宽度设置为5

def Button(screen, position, text, buttoncolor=(255, 0, 255), linecolor=(255, 215, 0), textcolor=(255, 255, 255), bwidth=200, bheight=50):left, top = positionpygame.draw.line(screen, linecolor, (left, top), (left+bwidth, top), 5)pygame.draw.line(screen, linecolor, (left, top-2), (left, top+bheight), 5)pygame.draw.line(screen, linecolor, (left, top+bheight), (left+bwidth, top+bheight), 5)pygame.draw.line(screen, linecolor, (left+bwidth, top+bheight), (left+bwidth, top), 5)pygame.draw.rect(screen, buttoncolor, (left, top, bwidth, bheight))font = pygame.font.SysFont('Consolas', 30)text_render = font.render(text, 1, textcolor)rect = text_render.get_rect()rect.centerx, rect.centery = left + bwidth / 2, top + bheight / 2return screen.blit(text_render, rect)

2.3 choice_interface
绘制四个选择界面,可供选择开始,下一关,重生及成功,主要是背景图的不同,调用规则在主游戏模块实现

def choice_interface(screen, resources, mode='START'):pygame.display.set_mode(resources.SCREENSIZE)if mode == 'START' or mode == 'NEXT' or mode == 'RESTART' or mode == 'WIN':clock = pygame.time.Clock()while True:if mode == 'START':bg = pygame.image.load("resources/images/background1.png")elif mode == 'WIN':bg = pygame.image.load("resources/images/win.png")else:bg = pygame.image.load("resources/images/background2.png")screen.blit(bg, (0,0))button_1 = Button(screen, (220, 150), mode)button_2 = Button(screen, (220, 250), 'QUIT')for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()sys.exit(-1)elif event.type == pygame.MOUSEBUTTONDOWN:if button_1.collidepoint(pygame.mouse.get_pos()):return Trueelif button_2.collidepoint(pygame.mouse.get_pos()):pygame.quit()sys.exit(-1)pygame.display.update()clock.tick(resources.FPS)else:raise ValueError('Interface.mode unsupport <%s>...' % mode)

3 map.py
游戏屏幕的初始布局
3.1 mapParser
屏幕地图解析
3.1.1 初始化

获取地图文件,背景块图片,墙图片,以及背景块尺寸

def __init__(self, mapfilepath, bg_paths, wall_paths, blocksize, **kwargs):self.instances_list = self.__parse(mapfilepath)self.bg_paths = bg_pathsself.wall_paths = wall_pathsself.blocksize = blocksizeself.height = len(self.instances_list)self.width = len(self.instances_list[0])self.screen_size = (blocksize * self.width, blocksize * self.height)

3.1.2 draw
将地图上的元素画到屏幕上,三种不同的墙体,以及三种颜色的背景块

def draw(self, screen):for j in range(self.height):for i in range(self.width):instance = self.instances_list[j][i]if instance == 'w':elem = Wall(self.wall_paths[0], [i, j], self.blocksize)elif instance == 'x':elem = Wall(self.wall_paths[1], [i, j], self.blocksize)elif instance == 'z':elem = Wall(self.wall_paths[2], [i, j], self.blocksize)elif instance == '0':elem = Background(self.bg_paths[0], [i, j], self.blocksize)elif instance == '1':elem = Background(self.bg_paths[1], [i, j], self.blocksize)elif instance == '2':elem = Background(self.bg_paths[2], [i, j], self.blocksize)else:raise ValueError('instance parse error in mapParser.draw...')elem.draw(screen)

3.1.3 randomGetSpace
随机获取一块空地,实现是获取地图上的背景块坐标

def randomGetSpace(self, used_spaces=None):while True:i = random.randint(0, self.width-1)j = random.randint(0, self.height-1)coordinate = [i, j]if used_spaces and coordinate in used_spaces:continueinstance = self.instances_list[j][i]if instance in ['0', '1', '2']:breakreturn coordinate

3.1.4 getElemByCoordinate
根据坐标获取元素类型

def getElemByCoordinate(self, coordinate):return self.instances_list[coordinate[1]][coordinate[0]]

3.1.5 __parse
解析地图.map文件,每一行相当于一个列表,再把代表每一行的列表统一放在一个列表了相当于一个二维数组

def __parse(self, mapfilepath):instances_list = []with open(mapfilepath) as f:for line in f.readlines():instances_line_list = []for c in line:if c in ['w', 'x', 'z', '0', '1', '2']:instances_line_list.append(c)instances_list.append(instances_line_list)return instances_list

4 resources.py
所有图片,音频资源,包括一些宏定义

SCREENSIZE = (640, 480) 屏幕大小
BLOCKSIZE = 30
FPS = 30 帧数
游戏地图路径
GAMEMAPPATHS = ['resources/maps/1.map', 'resources/maps/2.map']
代表墙块路径
WALLPATHS = ['resources/images/res/wall0.png', 'resources/images/res/wall1.png', 'resources/images/res/wall2.png']
角色的四个方位图片路径
ROLEAI1PATHS = ['resources/images/ming/left.png', 'resources/images/ming/right.png', 'resources/images/ming/up.png', 'resources/images/ming/down.png']
HEROROLEPATHS = ['resources/images/zuo/left.png', 'resources/images/zuo/right.png', 'resources/images/zuo/up.png', 'resources/images/zuo/down.png']
ROLEAI2PATHS = ['resources/images/jiu/left.png', 'resources/images/jiu/right.png', 'resources/images/jiu/up.png', 'resources/images/jiu/down.png']
水果的图片路径
FRUITPATHS = ['resources/images/res/peach.png', 'resources/images/res/pineapple.png']
暂停按钮
PAUSEDPATHS = ['resources/images/pause_nor.png','resources/images/pause_pressed.png','resources/images/resume_nor.png','resources/images/resume_pressed.png']
背景图片的路径
BACKGROUNDPATHS = ['resources/images/res/bg0.png', 'resources/images/res/bg1.png', 'resources/images/res/bg2.png', 'resources/images/res/bg3.png']
炸弹图片的路径
BOMBPATH = 'resources/images/res/bomb.png'
炸弹爆炸效果图片的路径
FIREPATH = 'resources/images/res/fire.png'
游戏背景音乐的路径
BGMPATH = 'resources/audio/bgm.mp3'
屏幕上调用的色彩
YELLOW = (255, 255, 0)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
BLACK = (0, 0, 0)
ORANGE = (255, 253, 0)
WHITE = (255, 255, 255)

5 bomberman.py

import sys
import random
import pygamefrom modules import res
from modules.map import *
from modules.choice import *
from modules.GameSprites import *
from modules.res import *游戏主程序
def main(resources):# 初始化pygame.init()# 游戏音频初始化,游戏开始bgm响起pygame.mixer.init()pygame.mixer.music.load(resources.BGMPATH)#一直循环pygame.mixer.music.play(-1, 0.0)#初始化一个准备显示的屏幕screen = pygame.display.set_mode(resources.SCREENSIZE)
#设置图标
screen = pygame.display.set_mode(res.SCREENSIZE)
icon = pygame.image.load("resources/pika.png")#窗口标题pygame.display.set_caption('Bomber Man ')# 开始界面choice_interface(screen, resources, mode='START')# 游戏主循环#选择字体类型及大小font = pygame.font.SysFont('Consolas', 15)#记录过关数count = 1#遍历游戏地图 for gamemap_path in resources.GAMEMAPPATHS:# -解析.map生成地图map_parser = mapParser(gamemap_path, bg_paths= resources.BACKGROUNDPATHS, wall_paths= resources.WALLPATHS, blocksize= resources.BLOCKSIZE)# -水果精灵组fruit_sprite_group = pygame.sprite.Group()#空地,防止空地被重复获取used_spaces = []for i in range(5):#随机获取空地投放水果coordinate = map_parser.randomGetSpace(used_spaces)used_spaces.append(coordinate)fruit_sprite_group.add(Fruit(random.choice(resources.FRUITPATHS), coordinate=coordinate, blocksize=cfg.BLOCKSIZE))# -我方Role 随机获取一块空地降临coordinate = map_parser.randomGetSpace(used_spaces)used_spaces.append(coordinate)ourhero = Role(imagepaths=resources.HEROROLEPATHS, coordinate=coordinate, blocksize= resources.BLOCKSIZE, map_parser=map_parser, role='zuo')# -电脑 Role 随机获取一块空地降临aihero_sprite_group = pygame.sprite.Group()coordinate = map_parser.randomGetSpace(used_spaces)aihero_sprite_group.add(Role(imagepaths=resources.ROLEAI1PATHS, coordinate=coordinate, blocksize= resources.BLOCKSIZE, map_parser=map_parser, role ='jiu'))used_spaces.append(coordinate)coordinate = map_parser.randomGetSpace(used_spaces)aihero_sprite_group.add(Role(imagepaths= resources. ROLEAI2PATHS, coordinate=coordinate, blocksize= resources.BLOCKSIZE, map_parser=map_parser, role ='ming'))used_spaces.append(coordinate)# -炸弹精灵组 bomb_sprite_group = pygame.sprite.Group()# -用于判断游戏胜利或者失败的flagis_win_flag = False# -主循环screen = pygame.display.set_mode(map_parser.screen_size)# -clock创建时钟对象(可以控制游戏循环频率) clock = pygame.time.Clock()# 标志是否暂停游戏
paused = False
#暂停按钮paused_nor_image = pygame.image.load(res.PAUSEDPATHS[0])
paused_nor_image = pygame.transform.scale(paused_nor_image, (30, 30))#暂停按钮(鼠标停留在上方时显示),使颜色加深
pause_pressed_image = pygame.image.load(res.PAUSEDPATHS[1])
pause_pressed_image = pygame.transform.scale(pause_pressed_image, (30, 30))#启动按钮
resume_nor_image = pygame.image.load(res.PAUSEDPATHS[2])
resume_nor_image = pygame.transform.scale(resume_nor_image, (30, 30))#启动按钮(鼠标停留在上方时显示) ,使颜色加深
resume_pressed_image = pygame.image.load(res.PAUSEDPATHS[3])
resume_pressed_image = pygame.transform.scale(resume_pressed_image, (30, 30))
paused_rect = paused_nor_image.get_rect()#暂停按钮位置设置,两张地图位置右上角
if order == 0:paused_rect.left, paused_rect.top = 12 * 30, 0
elif order == 1:paused_rect.left, paused_rect.top = 24 * 30, 0
paused_image = paused_nor_imagewhile True:#设置帧率dt = clock.tick(res.FPS)#监听暂停按钮和关闭程序for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()sys.exit(-1)elif event.type == pygame.MOUSEBUTTONDOWN:if event.button == 1 and paused_rect.collidepoint(event.pos):paused = not paused#暂停切换图片,关掉BGMif paused:pygame.time.set_timer(pygame.USEREVENT, 0)pygame.mixer.music.pause()pygame.mixer.pause()paused_image = resume_pressed_imageelse:pygame.time.set_timer(pygame.USEREVENT, 30 * 1000)pygame.mixer.music.unpause()pygame.mixer.unpause()paused_image = pause_pressed_imagescreen.fill(res.WHITE)#如果当前是否运行状态if not paused:#为保证按钮连贯,不松开按钮亦可响应,方向键不用监听事件监听# --↑↓←→键控制上下左右, 空格键丢炸弹keys_pressed = pygame.key.get_pressed()if keys_pressed[pygame.K_RIGHT]:ourhero.move('right')elif keys_pressed[pygame.K_LEFT]:ourhero.move('left')elif keys_pressed[pygame.K_UP]:ourhero.move('up')elif keys_pressed[pygame.K_DOWN]:ourhero.move('down')#空格投放炸弹elif keys_pressed[pygame.K_SPACE]:if ourhero.bomb_cooling_count <= 0:bomb_sprite_group.add(ourhero.generateBomb(imagepath=res.BOMBPATH, digitalcolor=res.ORANGE,explode_imagepath=res.FIREPATH))# --电脑AI随机行动for hero in aihero_sprite_group:action, flag = hero.randomAction(dt)if flag and action == 'dropbomb':bomb_sprite_group.add(hero.generateBomb(imagepath=res.BOMBPATH, digitalcolor=res.ORANGE, explode_imagepath=res.FIREPATH))# --吃到水果加生命值(只要是Role, 都能加),角色生命值在Role类已设#置上限,进行上限处理ourhero.eatFruit(fruit_sprite_group)for hero in aihero_sprite_group:hero.eatFruit(fruit_sprite_group)# --游戏元素都绑定到屏幕上map_parser.draw(screen)#绘制暂停按钮screen.blit(paused_image, paused_rect)for bomb in bomb_sprite_group:if not bomb.is_being:bomb_sprite_group.remove(bomb)explode_area = bomb.draw(screen, dt, map_parser)if explode_area:# --爆炸火焰范围内的Role生命值将持续下降if ourhero.coordinate in explode_area:ourhero.health_value -= bomb.harm_valuefor hero in aihero_sprite_group:if hero.coordinate in explode_area:hero.health_value -= bomb.harm_valuefruit_sprite_group.draw(screen)for hero in aihero_sprite_group:hero.draw(screen, dt)ourhero.draw(screen, dt)else:map_parser.draw(screen)screen.blit(paused_image, paused_rect)for bomb in bomb_sprite_group:if not bomb.is_being:bomb_sprite_group.remove(bomb)explode_area = bomb.draw(screen, dt, map_parser)fruit_sprite_group.draw(screen)for hero in aihero_sprite_group:hero.draw(screen, dt)ourhero.draw(screen, dt)# --左上角显示角色生命值pos_x = showText(screen, font, text=ourhero.hero_name+'(our):'+str(ourhero.health_value), color=cfg.YELLOW, position=[5, 5])for hero in aihero_sprite_group:pos_x, pos_y = pos_x+15, 5pos_x = showText(screen, font, text=hero.hero_name+'(ai):'+str(hero.health_value), color=cfg.YELLOW, position=[pos_x, pos_y])# --我方玩家生命值小于等于0/电脑方玩家生命值均小于等于0则判断游戏结束if ourhero.health_value <= 0:is_win_flag = Falsebreakfor hero in aihero_sprite_group:if hero.health_value <= 0:aihero_sprite_group.remove(hero)if len(aihero_sprite_group) == 0:is_win_flag = Truebreakpygame.display.update()clock.tick(cfg.FPS)if is_win_flag:#暂停按钮位置标志order = 1#游戏结束if count == 2:breakelse:choice_interface(screen, res, mode='NEXT')#过关统计count += 1else:break
#过关失败重生
if is_win_flag == False:choice_interface(screen, res, mode='RESTART')
#过关成功WIN
else:choice_interface(screen, res, mode='WIN')运行:
if __name__ == '__main__':while True:main(res)

实验效果

1起始选择页面
开始页面

2游戏页面
1第一关
第一关游戏画面

过关后进入下一关

2第二关
第二关游戏画面

顺利通关画面

3游戏页面元素介绍

游戏元素展示图

启动按钮

游戏中爆炸效果

失败可选重新游戏

展望

后续程序还可以接着改造,包括炸弹威力的等级可以分为多个等级,根据级别分类炸弹,水果加多种类,可以给角色提供高等级炸弹,以及移动加速,角色在爆炸范围内可以做出相应的反应等等。整个项目还可以优化,我只是作为初学者进行一个初步的开发,后继会接着添加功能。

pygame开发的炸弹人游戏(详细讲解)相关推荐

  1. Pygame开发打飞机游戏

    pygame 开发打飞机游戏 一.实验说明 1. 实现效果 单文件实现微信打飞机小游戏 2. 开发环境 python 2.7 pygame random sys 3. 源码下载 本课程中的所有源码:h ...

  2. 微信小游戏开发教程-2D游戏原理讲解

    微信小游戏开发教程-2D游戏原理讲解 原理 为了更加形象的描述,这里先上一张图: 背景 a. 首先,我们看到背景好像是一张无限长的图片在向下移动.实际则不然,这是一张顶部和底部刚好重叠的图片.这是一种 ...

  3. 使用Html5+C#+微信 开发移动端游戏详细教程 :(三)使用html5引擎搭建游戏框架...

    教程里的案例我们是通过H5游戏引擎开发,目前H5的游戏引擎比较好用的是白鹭,不过对于新手来说白鹭的开发环境和工具使用过于复杂,这里推荐一个国内大神编写的游戏引擎:lufylegend. 直接在页面引入 ...

  4. 运用Python+Pygame开发坦克大战游戏_版本V1.01

    这里写目录标题 一.项目整体说明 二.pygame下载方式 三.项目文件 1.坦克大战_框架_1.py 2.坦克大战_开始游戏_窗口设置_2.py 3.坦克大战_事件检测_3.py 4.坦克大战_基本 ...

  5. C#游戏开发之炸弹人游戏开发

    笔者第一次发表文章,考虑不全多多包涵.也想借此机会和大家交流游戏开发.希望大神能指点一二.笔者是利用VS2010编译器,下面进入正题: 利用C#控件来实现2D游戏开发还是比较方便.先从总体上介绍炸弹人 ...

  6. pygame精灵组有哪些方法_利用 pygame 开发一款游戏:「跳跳兔」(六)

    HackPython 改名为「懒编程」,纯粹是因为我有另外一个写杂文的号叫「懒写作」,此外,感觉「懒编程」比 HackPython 好记. 前言 在第 5 节内容中,实现了积分机制.玩家死亡逻辑以及游 ...

  7. 用 pygame 开发象棋小游戏

    源码及资源请前往github获取 如果觉得还不错的话,请赏个 star 呗. 最近因为工作原因,需要学习一下python,学习了基础语法,打算做一个游戏,算做python 学习的一个阶段点. 前段时间 ...

  8. 使用Html5+C#+微信 开发移动端游戏详细教程 总目录

    (一).序(关于作者创业失败的感想) (二).准备工作&开发环境 (三).使用html5引擎搭建游戏框架 (四).游戏中层的概念与设计 (五).游戏图像的加载与操作 (六).游戏界面布局与性能 ...

  9. 使用pygame开发一个小游戏

    学习了pygame,身为一个IKUN所以,做了一个简单的小游戏.游戏规则是,使用键盘的方向键控制坤坤,当坤坤触碰到篮球,就会爆发出音乐"只因你太美".代码如下: import ra ...

最新文章

  1. 技术图文:03 结构型设计模式(下)
  2. ICLR2020 NLP优秀论文分享(附源码)
  3. python四大软件-PYPL 9月编程语言排行榜发布 Python一枝独秀
  4. 分享丨10年DBA老司机整理的Oracle学习路线图
  5. PHP 多参数方法的重构
  6. web框架之Django(一)
  7. Spring Boot集成Redis缓存之RedisTemplate的方式
  8. 深度学习最常用的10个激活函数!
  9. [转]C#利用委托跨线程更新UI数据
  10. 20175320 2018-2019-2 《Java程序设计》第8周学习总结
  11. JavaStuNote 5
  12. 华为P30 HL2ELLEM VER.A手机图纸
  13. 百度地图-将经纬度转化为地址
  14. 计算机毕设Python+Vue兴发农家乐服务管理系统(程序+LW+部署)
  15. CC00307.CloudKubernetes——|KuberNetes运维.V27|——|监控.v04|PromQL查询_运算符|
  16. linux 创建wifi 热点_linux开启wifi和热点双用
  17. 解决H5播放视频黑屏只有声音没有图像的问题,Java调用ffmpeg转码成h264的mp4格式
  18. 互联网再升级,蓝汛CEO谈IPv6发展历程
  19. 设计模式 - 六大设计原则之LoD(迪米特法则原则)
  20. 征服嵌入式linux,成功征服英语的三十个好习惯

热门文章

  1. 区块链是怎么形成的,你究竟明白多少?
  2. 聚焦IoT安全:对多厂商智能汽车产品的安全性探究
  3. matlab三相功率测量不对,测量信号的功率 - MATLAB Simulink - MathWorks 中国
  4. 网络报文中的checksum是做什么的?ChatGPT如是说
  5. java关于23种设计模式之泡MM版(推荐)
  6. 何为Top-1,Top-5
  7. 2020中兴硬件类笔试
  8. 电脑无法启动,电源灯一直闪烁,风扇不转!
  9. mysql extract什么意思_mysql中json_extract函数的使用?作用是什么?
  10. .NET Fframework