文章目录
- 一、游戏运行效果
- 二、代码实现
- 2.1 项目搭建
- 2.2 加载我方坦克
- 2.3 加载敌方坦克
- 2.4 添加爆炸效果
- 2.5 坦克大战之音效处理
- 三、完整代码
一、游戏运行效果
二、代码实现
坦克大战游戏
2.1 项目搭建
本游戏主要分为两个对象,分别是我方坦克和敌方坦克。用户可以通过控制我方的坦克来摧毁敌方的坦克保护自己的“家”,把所有的敌方坦克消灭完达到胜利。敌方的坦克在初始的时候是默认 5 个的(这可以自己设置),当然,如果我方坦克被敌方坦克的子弹打中,游戏结束。从面向对象分析该项目有以下类组成:
- 主类:主要包括开始游戏、结束游戏的功能。
class MainGame():def __init__(self):pass# 开始游戏def startGame(self):pass# 结束游戏def endGame(self):pass
- 坦克类:主要包括坦克的创建、显示、移动及射击的功能。
class Tank():def __init__(self):pass# 移动def move(self):pass# 射击def shot(self):pass# 展示坦克的方法def displayTank(self):pass
- 我方坦克类继承坦克类,主要包括创建、与敌方坦克的碰撞方法。
# 我方坦克
class MyTank(Tank):def __init__(self):pass
- 敌方坦克类继承坦克类,主要包括创建、与我方坦克碰撞方法。
# 敌方坦克
class EnemyTank(Tank):def __init__(self):pass
- 子弹类:主要包括子弹的创建、显示及移动的功能。
# 子弹类
class Bullet():def __init__(self):pass# 移动def move(self):pass# 展示子弹的方法def displayBullet(self):pass
- 墙壁类:主要包括墙壁的创建、显示的功能。
class Wall():def __init__(self):pass# 展示墙壁的方法def displayWall(self):pass
- 爆炸效果类:主要展示爆炸效果。
class Explode():def __init__(self):pass# 展示爆炸效果的方法def displayExplode(self):pass
- 音效类:主要播放音乐。
class Music():def __init__(self):pass# 播放音乐def play(self):pass
显示游戏窗口
在游戏设计的前期,要先创建游戏的界面,也就是要为所设计的游戏创建一个窗口。
【示例】:显示游戏窗口
def startGame(self):# 加载主窗口# 初始化窗口pygame.display.init()# 设置窗口的大小及显示MainGame.window = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])# 设置窗口的标题pygame.display.set_caption('坦克大战1.03')while True:# 给窗口设置填充色MainGame.window.fill(BG_COLOR)pygame.display.update()
MainGame().startGame()
运行效果:
添加提示文字
在运行代码时会发现,创建的窗口没有任何提示。然而在实际中希望窗口提示敌方坦克的数量,因此,需要在现有窗口进行必须的改进,添加敌方坦克数量提示。
# 文字显示
def getTextSuface(self, text):pygame.font.init() # 字体初始化font = pygame.font.SysFont('kaiti', 16)# 绘制文字信息textSurface = font.render(text, True, TEXT_COLOR)return textSurface
2.2 加载我方坦克
通过加载一张图片来表示游戏中的坦克,此坦克代表我方坦克,完善坦克类。
class Tank():# 添加距离左边left 距离上边topdef __init__(self, left, top):# 保存加载的图片self.images = {'U': pygame.image.load('img/p1tankU.gif'),'D': pygame.image.load('img/p1tankD.gif'),'L': pygame.image.load('img/p1tankL.gif'),'R': pygame.image.load('img/p1tankR.gif'),}# 方向self.direction = 'L'# 根据当前图片的方向获取图片 surfaceself.image = self.images[self.direction]# 根据图片获取区域self.rect = self.image.get_rect()# 设置区域的left 和topself.rect.left = leftself.rect.top = top
添加事件监听
上面创建的坦克还不能动,显示不是创建游戏的目的,因此,要给创建的坦克赋予“生命”。添加事件监听,控制上、下、左、右四个方向键,实现针对不同的键改变坦克的方向及移动功能,点击关闭退出游戏。
实现退出方法:
# 结束游戏def endGame(self):print('游戏结束')exit() # 退出游戏
坦克类中添加移动开关属性,按下上、下、左、右四个方向键修改坦克的方向及开关状态,按下关闭键,调用关闭方法退出游戏。
# 获取程序期间所有事件(鼠标事件,键盘事件)def getEvent(self):# 获取所有事件eventList = pygame.event.get()# 遍历事件for event in eventList:# 判断按下的键是关闭还是键盘按下# 如果按的是退出,关闭窗口if event.type == pygame.QUIT:self.endGame()# 如果是键盘的按下if event.type == pygame.KEYDOWN:# 判断按下的是上、下、左、右if event.key == pygame.K_LEFT:print('按下左键,坦克向左移动')elif event.key == pygame.K_RIGHT:print('按下右键,坦克向右移动')elif event.key == pygame.K_UP:print('按下上键,坦克向上移动')elif event.key == pygame.K_DOWN:print('按下左键,坦克向下移动')
按下上、下、左、右之后控制台上会打印对应的信息。
随机生成敌方坦克
初始化敌方坦克,随机在不同坐标生成敌方坦克。
# 敌方坦克
class EnemyTank(Tank):def __init__(self, left, top, speed):super(EnemyTank, self).__init__(left, top)# 加载图片集self.images = {'U': pygame.image.load('img/enemy1U.gif'),'D': pygame.image.load('img/enemy1D.gif'),'L': pygame.image.load('img/enemy1L.gif'),'R': pygame.image.load('img/enemy1R.gif'),}# 随机生成方向self.direction = self.randDirection()self.image = self.images[self.direction] # 根据方向获取图片self.rect = self.image.get_rect() # 获取区域self.rect.left, self.rect.top = left, top # 对left和top赋值self.speed = speed # 速度self.flag = True # 坦克移动开关self.step = 50 # 敌方坦克步数
2.3 加载敌方坦克
在MainGame类中创建敌方坦克:
def createEnemyTank(self): # 初始化敌方坦克, 将敌方坦克添加到列表中top = 100for i in range(self.enemyTankCount): # 生成指定敌方坦克数量left = random.randint(0, 600)speed = random.randint(1, 4)enemy = EnemyTank(left, top, speed)MainGame.enemyTankList.append(enemy)
在敌方坦克类中实现敌方坦克的随机移动
def randMove(self): # 坦克的随机方向移动if self.step < 0: # 步数小于0, 随机改变方向self.direction = self.randDirection()self.step = 50 # 步数复位else:self.move()self.step -= 1
在开始游戏方法,加载敌方坦克
self.creatEnemyTank()
我方坦克发射子弹
在子弹类中初始化子弹,每个子弹在不同的方向发射会有不同的运动轨迹,每个子弹在坦克方向上的不同子弹发射的坐标也会有所不同。需要计算四个不同方向上的子弹发射坐标。
def __init__(self, tank):self.image = pygame.image.load('img/enemymissile.gif') # 图片加载self.direction = tank.direction # 子弹的方向self.rect = self.image.get_rect() # 获取区域if self.direction == 'U': # 子弹的left和top与方向有关self.rect.left = tank.rect.left + tank.rect.width / 2 - self.rect.width / 2self.rect.top = tank.rect.top - self.rect.heightelif self.direction == 'D':self.rect.left = tank.rect.left + tank.rect.width / 2 - self.rect.width / 2self.rect.top = tank.rect.top + tank.rect.heightelif self.direction == 'L':self.rect.left = tank.rect.left - self.rect.width / 2 - self.rect.width / 2self.rect.top = tank.rect.top + tank.rect.width / 2 - self.rect.width / 2elif self.direction == 'R':self.rect.left = tank.rect.left + tank.rect.widthself.rect.top = tank.rect.top + tank.rect.width / 2 - self.rect.width / 2self.speed = 5 # 子弹的速度self.live = True # 子弹的状态
敌方坦克随机发射子弹
def shot(self):num = random.randint(1,1000)if num <= 20:return Bullet(self)
我方法子弹与敌方坦克的碰撞检测
在游戏开发中,通常把显示图像的对象叫做精灵 Spire,精灵需要有两个属性 image 要
显示的图像,rect 图像要显示在屏幕的位置。
在 Pygame 框架中,使用 pygame. sprite 模块中的内置函数可以实现碰撞检测。代码如
下:
pygame.sprite.collide_rect(first, second) #返回布尔值
pygame.sprite.Sprite 是 pygame 精灵的基类,一般来说,总是需要写一个自己的精灵类继承 pygame.sprite.Sprite。让坦克类、子弹类都继承编写的精灵类。
在子弹类中增加我方子弹碰撞敌方坦克的方法,如果发生碰撞,修改我方子弹及敌方坦克 live 属性的状态值。
#新增我方子弹碰撞敌方坦克的方法
def hitEnemyTank(self):for eTank in MainGame.EnemyTank_list:if pygame.sprite.collide_rect(eTank,self):self.live = FalseeTank.live = False
2.4 添加爆炸效果
在我方子弹碰撞敌方坦克的方法中,如果检测到碰撞,产生爆炸类,并将爆炸效果添加到爆炸列表。
#新增我方子弹碰撞敌方坦克的方法
def hitEnemyTank(self):for eTank in MainGame.EnemyTank_list:if pygame.sprite.collide_rect(eTank,self):#产生一个爆炸效果explode = Explode(eTank)#将爆炸效果加入到爆炸效果列表MainGame.Explode_list.append(explode)self.live = FalseeTank.live = False
我方坦克的消亡
子弹类中,新增敌方子弹与我方坦克的碰撞。如果发生碰撞,修改敌方子弹、我方坦克的状态及产生爆炸效果。
添加敌方子弹到窗口中时候,如果子弹还活着,显示子弹、调用子弹移动并判断敌方子弹是否与我方坦克发生碰撞。
def blitEnemyBullet(self): # 循环敌方子弹列表, 并展示for enemyBullet in MainGame.enemyBulletList:if enemyBullet.live:enemyBullet.displayBullet()enemyBullet.move()enemyBullet.enemyBullet_hit_myTank()enemyBullet.hitWall() # 检测敌方坦克子弹是否碰撞else:MainGame.enemyBulletList.remove(enemyBullet)
子弹不能穿墙
子弹类中新增方法,子弹与墙壁的碰撞,如果子弹与墙壁碰撞,修改子弹的状态,墙壁的生命值减少,如果墙壁的生命值小于等于零时候修改墙壁的状态。
坦克不能穿墙
如果坦克与墙壁碰撞,则坦克不能继续移动,需要修改坦克的坐标为移动之前的。因此在坦克类中新增属性 oldLeft、oldTop 记录移动之前的坐标,新增 stay()、hitWalls()方法。
def hitWall(self):for wall in MainGame.WallList: # 循环遍历墙壁列表if pygame.sprite.collide_rect(self, wall): # 检测子弹是否碰撞墙壁self.live = False # 修改子弹状态wall.hp -= 1 # 碰撞后墙壁生命值减少if wall.hp <= 0:wall.live = False
双方坦克之间的碰撞检测
如果我方坦克碰撞到敌方坦克,则我方坦克再不能继续移动。同理如果敌方坦克碰撞到
我方坦克也不能继续移动。
在我方坦克类中新增我方坦克与敌方坦克碰撞的方法。
class MyTank(Tank):def __init__(self, left, top):super(MyTank, self).__init__(left, top)def myTank_hit_enemyTank(self):for enemyTank in MainGame.enemyTankList:if pygame.sprite.collide_rect(self, enemyTank):self.stay()
我方坦克移动后,调用是否与敌方坦克发生碰撞。在敌方坦克类中,新增敌方坦克碰撞我方坦克的方法。敌方坦克添加到窗口时候,调用是否与我方坦克碰撞。
def blitEnemyBullet(self): # 循环敌方子弹列表, 并展示for enemyBullet in MainGame.enemyBulletList:if enemyBullet.live:enemyBullet.displayBullet()enemyBullet.move()enemyBullet.enemyBullet_hit_myTank()enemyBullet.hitWall() # 检测敌方坦克子弹是否碰撞else:MainGame.enemyBulletList.remove(enemyBullet)
2.5 坦克大战之音效处理
music 是 pygame 中控制流音频的 pygame 模块,音乐模块与 pygame.mixer 紧密相连,pygame.mixer 是一个用来处理声音的模块,其含义为“混音器”。游戏中对声音的处理一般包括制造声音和播放声音两部分。使用 pygame.mixer.music.load()加载一个播放音乐的文件,pygame.mixer.music.play() 开始播放音乐流。
初始化音效类
class Music():def __init__(self, filename):self.filename = filenamepygame.mixer.init()pygame.mixer.music.load(self.filename) # 加载音乐# 音乐播放def play(self):pygame.mixer.music.play()
music.play()
创建坦克时,添加音效和在我方坦克发射子弹时,添加音效。
三、完整代码
注意:因为代码过长,且含音频和图片,不方便复制,可使用下方码云链接直接下载就好啦
https://gitee.com/bow-elongation/tank-battle.git