博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
pygame开发的炸弹人游戏(详细讲解)
阅读量:2080 次
发布时间:2019-04-29

本文共 24422 字,大约阅读时间需要 81 分钟。

前言

本次开发的游戏为炸弹人游戏,是一个经典的小游戏,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[0]-5, -1):      if xmin < 0 or instances_list[self.coordinate[1]][xmin] in ['w', 'x', 'z']:         break      explode_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']:         break      explode_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.blocksize      screen.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 = imagepaths    self.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] * blocksize    self.coordinate = coordinate    self.blocksize = blocksize    self.map_parser = map_parser    self.role = kwargs.get('role_name')    # 生命值    self.health_value = 50    self.max_value = 50    # 炸弹冷却时间    self.bomb_cooling_time = 5000    self.bomb_cooling_count = 0    # 随机移动冷却时间(仅AI电脑用)    self.randommove_cooling_time = 100    self.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 False        self.coordinate[0] = self.coordinate[0] - 1    elif 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 False        self.coordinate[0] = self.coordinate[0] + 1    elif 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 False        self.coordinate[1] = self.coordinate[1] - 1    elif 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 False        self.coordinate[1] = self.coordinate[1] + 1    else:        raise ValueError('Unknow direction <%s>...' % direction)    self.rect.left, self.rect.top = self.coordinate[0] * self.blocksize, self.coordinate[1] * self.blocksize    return 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 -= dt   action = random.choice(['left', 'left', 'right', 'right', 'up', 'up', 'down', 'down', 'dropbomb'])   flag = False   if action in ['left', 'right', 'up', 'down']:      if self.randommove_cooling_count <= 0:         flag = True         self.move(action)         self.randommove_cooling_count = self.randommove_cooling_time   elif action in ['dropbomb']:      if self.bomb_cooling_count <= 0:         flag = True         self.bomb_cooling_count = self.bomb_cooling_time   return action, flag3.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 -= dt   screen.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.value        if 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 = position   screen.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 = position   pygame.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 / 2   return 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 True                    elif 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_paths   self.wall_paths = wall_paths   self.blocksize = blocksize   self.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:         continue      instance = self.instances_list[j][i]      if instance in ['0', '1', '2']:         break   return 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 sysimport randomimport pygamefrom modules import resfrom 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()      # -用于判断游戏胜利或者失败的flag      is_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, 0elif order == 1:   paused_rect.left, paused_rect.top = 24 * 30, 0paused_image = paused_nor_image     		while 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						#暂停切换图片,关掉BGM						if paused:						pygame.time.set_timer(pygame.USEREVENT, 0)							pygame.mixer.music.pause()							pygame.mixer.pause()							paused_image = resume_pressed_image						else:										pygame.time.set_timer(pygame.USEREVENT, 30 * 1000)							pygame.mixer.music.unpause()							pygame.mixer.unpause()							paused_image = pause_pressed_image			screen.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_value						for hero in aihero_sprite_group:							if hero.coordinate in explode_area:								hero.health_value -= bomb.harm_value				fruit_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, 5            pos_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 = False            break         for hero in aihero_sprite_group:            if hero.health_value <= 0:               aihero_sprite_group.remove(hero)         if len(aihero_sprite_group) == 0:            is_win_flag = True            break         pygame.display.update()         clock.tick(cfg.FPS)      if is_win_flag:	#暂停按钮位置标志      	order = 1	#游戏结束      	if count == 2:            break      	else:            choice_interface(screen, res, mode='NEXT')	#过关统计      count += 1   else:      break#过关失败重生if is_win_flag == False:   choice_interface(screen, res, mode='RESTART')#过关成功WINelse:   choice_interface(screen, res, mode='WIN')运行:if __name__ == '__main__':   while True:      main(res)

实验效果

1起始选择页面

开始页面
在这里插入图片描述

2游戏页面

1第一关
第一关游戏画面
在这里插入图片描述

过关后进入下一关

在这里插入图片描述
2第二关
第二关游戏画面
在这里插入图片描述

顺利通关画面

在这里插入图片描述

3游戏页面元素介绍

游戏元素展示图

在这里插入图片描述

启动按钮

在这里插入图片描述

游戏中爆炸效果

在这里插入图片描述

失败可选重新游戏

在这里插入图片描述

展望

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

转载地址:http://xakqf.baihongyu.com/

你可能感兴趣的文章
Linux下查看根目录各文件内存占用情况
查看>>
A星算法详解(个人认为最详细,最通俗易懂的一个版本)
查看>>
利用栈实现DFS
查看>>
(PAT 1019) General Palindromic Number (进制转换)
查看>>
(PAT 1073) Scientific Notation (字符串模拟题)
查看>>
(PAT 1080) Graduate Admission (排序)
查看>>
Play on Words UVA - 10129 (欧拉路径)
查看>>
mininet+floodlight搭建sdn环境并创建简答topo
查看>>
【linux】nohup和&的作用
查看>>
Set、WeakSet、Map以及WeakMap结构基本知识点
查看>>
【NLP学习笔记】(一)Gensim基本使用方法
查看>>
【NLP学习笔记】(二)gensim使用之Topics and Transformations
查看>>
【深度学习】LSTM的架构及公式
查看>>
【python】re模块常用方法
查看>>
剑指offer 19.二叉树的镜像
查看>>
剑指offer 20.顺时针打印矩阵
查看>>
剑指offer 23.从上往下打印二叉树
查看>>
Leetcode C++《热题 Hot 100-18》538.把二叉搜索树转换为累加树
查看>>
Leetcode C++《热题 Hot 100-21》581.最短无序连续子数组
查看>>
Leetcode C++《热题 Hot 100-22》2.两数相加
查看>>