赞
踩
坦克大战游戏包含很多个物体,现在要对这些物体进行总结
类名 | 包含的操作 | 包含的属性 |
---|---|---|
敌方坦克类 | 射击,移动,显示 | 生命,速度,伤害,方向,类型 |
我方坦克类 | 射击,移动,显示 | 生命,速度,伤害,方向,装甲,等级 |
子弹类 | 移动,显示 | 方向,伤害,发射源,速度 |
墙壁类、草类、石砖类、河类 | 显示 | 是否可以摧毁 |
音效类 | 播放,停止,设置音乐 | - |
爆炸效果类 | 显示 | 是否可以摧毁 |
主类 | … | … |
物体总结完毕后,规划一下窗口的大小,下面是我设置的窗口大小
素材链接:百度网盘
链接:https://pan.baidu.com/s/19sCyH7rp37f6DzRj0iXDCA?pwd=tkdz
提取码:tkdz
坦克大战代码链接:百度网盘
链接:https://pan.baidu.com/s/1qFV-0hi0cgZS1Hnvx6mK6Q?pwd=90tk
提取码:90tk
一切都准备就绪啦,现在开始编写坦克大战的代码吧
主类是整个游戏运作的类,当然你也可以不用使用类,直接创建一个函数也可以,这里使用了面向对象的思想
import pygame SCREEN_WIDTH = 1100 SCREEN_HEIGHT = 600 BACKGROUND_COLOR = pygame.Color(0, 0, 0) FONT_COLOR = (255, 255, 255) class MainGame: # 窗口Surface对象 window = None def __init__(self): pass def startGame(self): # 初始化展示模块 pygame.display.init() # 设置窗口大小 size = (SCREEN_WIDTH, SCREEN_HEIGHT) # 初始化窗口 MainGame.window = pygame.display.set_mode(size) # 设置窗口标题 pygame.display.set_caption('Tank Battle') while 1: # 设置背景颜色 MainGame.window.fill(BACKGROUND_COLOR) # 更新窗口 pygame.display.update() if __name__ == '__main__': MainGame().startGame()
运行结果
主类中运用到的知识,都是学习 Python 之 Pygame 开发坦克大战(一)中所包含的
坦克大战关键是对玩家自己的坦克进行操控,消灭敌人的坦克,所以键盘事件响应是必不可少的
def getPlayingModeEvent(self): # 获取所有事件 eventList = pygame.event.get() for event in eventList: if event.type == pygame.QUIT: sys.exit() if event.type == pygame.KEYDOWN: print('键盘按键按下') if event.key == pygame.K_w: print('w按下') elif event.key == pygame.K_s: print('s按下') elif event.key == pygame.K_a: print('a按下') elif event.key == pygame.K_d: print('d按下') elif event.key == pygame.K_j: print('j按下') if event.type == pygame.KEYUP: print('键盘按键抬起') if event.key == pygame.K_w: print('w抬起') elif event.key == pygame.K_s: print('s抬起') elif event.key == pygame.K_a: print('a抬起') elif event.key == pygame.K_d: print('d抬起')
获取窗口中的事件,用于玩家操控坦克、发射坦克子弹等操作
游戏中,我规定aswd操控坦克,j攻击,当然你也可以上下左右键移动,空格攻击,如果你想设置双人游戏,这也是可以的
import pygame import sys SCREEN_WIDTH = 1100 SCREEN_HEIGHT = 600 BACKGROUND_COLOR = pygame.Color(0, 0, 0) FONT_COLOR = (255, 255, 255) class MainGame: # 窗口Surface对象 window = None def __init__(self): pass def startGame(self): # 初始化展示模块 pygame.display.init() # 设置窗口大小 size = (SCREEN_WIDTH, SCREEN_HEIGHT) # 初始化窗口 MainGame.window = pygame.display.set_mode(size) # 设置窗口标题 pygame.display.set_caption('Tank Battle') while 1: # 设置背景颜色 MainGame.window.fill(BACKGROUND_COLOR) # 获取窗口事件 self.getPlayingModeEvent() # 更新窗口 pygame.display.update() def getPlayingModeEvent(self): # 获取所有事件 eventList = pygame.event.get() for event in eventList: if event.type == pygame.QUIT: sys.exit() if event.type == pygame.KEYDOWN: print('键盘按键按下') if event.key == pygame.K_w: print('w按下') elif event.key == pygame.K_s: print('s按下') elif event.key == pygame.K_a: print('a按下') elif event.key == pygame.K_d: print('d按下') elif event.key == pygame.K_j: print('j按下') if event.type == pygame.KEYUP: print('键盘按键抬起') if event.key == pygame.K_w: print('w抬起') elif event.key == pygame.K_s: print('s抬起') elif event.key == pygame.K_a: print('a抬起') elif event.key == pygame.K_d: print('d抬起') if __name__ == '__main__': MainGame().startGame()
坦克操控事件完成后,现在就是实现坦克啦,首先场景中的物体都需要发生物体间的碰撞,简单来说就是检测两个屏幕上的图片是否发生了重叠,如果发生了,就要触发一些事件,这里创建ParentObject类,用于继承pygame.sprite.Sprite类
pygame.sprite.Sprite类可以用来检测物体碰撞,是pygame提供的一个类,非常的方便
import pygame.sprite
class ParentObject(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
创建我方坦克类,并且继承基类
import pygame as pg import pygame.image from ParentObject import ParentObject class PlayerTank(ParentObject): def __init__(self, x, y, order, amour): """ :param x: 坦克横坐标 :param y: 坦克纵坐标 :param order: 玩家坦克序号,1表示一号玩家,2表示二号玩家 :param amour: 坦克初始护甲 """ super().__init__() self.images = [] if order == 1: self.images.append({ 'UP': pygame.image.load('../Image/Player1/45x45/UP1.png'), 'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN1.png'), 'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT1.png'), 'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT1.png') }) self.images.append({ 'UP': pygame.image.load('../Image/Player1/45x45/UP2.png'), 'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN2.png'), 'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT2.png'), 'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT2.png') }) self.images.append({ 'UP': pygame.image.load('../Image/Player1/45x45/UP3.png'), 'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN3.png'), 'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT3.png'), 'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT3.png') }) self.images.append({ 'UP': pygame.image.load('../Image/Player1/45x45/UP4.png'), 'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN4.png'), 'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT4.png'), 'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT4.png') }) self.images.append({ 'UP': pygame.image.load('../Image/Player1/45x45/UP5.png'), 'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN5.png'), 'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT5.png'), 'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT5.png') }) self.images.append({ 'UP': pygame.image.load('../Image/Player1/45x45/UP6.png'), 'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN6.png'), 'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT6.png'), 'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT6.png') }) # 生命 self.life = 3 # 装甲 self.armor = amour # 方向 self.direction = 'UP' # 根据护甲选择坦克的样子 self.image: pg.Surface = self.images[max(self.armor - 1, 0)][self.direction] self.rect = self.image.get_rect() self.rect.left = x self.rect.top = y # 速度 self.accumulation: float = 0 self.speed = 2 # 移动开关 self.stop = True # 等级 self.level = 1 # 伤害 self.damage = 1 def move(self): pass def shot(self): pass def draw(self): pass
accumulation 可以更细的控制坦克的移动速度
当 accumulation 累加到 1 时,坦克移动一次,如果不设置这个属性,即使是速度每次 +1,坦克移动的也速度很快,所以增加这个属性,可以减慢坦克的移动速度
def move(self): if self.accumulation >= 1: self.accumulation = 0 if self.direction == 'LEFT': if self.rect.left > 0: self.rect.left -= self.speed elif self.direction == 'UP': if self.rect.top > 0: self.rect.top -= self.speed elif self.direction == 'DOWN': if self.rect.top < 555: self.rect.top += self.speed elif self.direction == 'RIGHT': if self.rect.left < 855: self.rect.left += self.speed else: self.accumulation += 0.20
这里需要设置坦克的边界范围
防止坦克跑出窗口
坦克的图片是45x45
坦克的显示就是把坦克的图片显示在窗口中
def draw(self, window):
# window传入主窗口
# 坦克生命中为0,表示已经死亡,不再展示坦克
if self.life <= 0:
return
# 获取展示的对象
self.image = self.images[max(self.armor - 1, 0)][self.direction]
window.blit(self.image, self.rect)
我方坦克类完整代码
import pygame as pg import pygame.image from ParentObject import ParentObject class PlayerTank(ParentObject): def __init__(self, x, y, order, amour): """ :param x: 坦克横坐标 :param y: 坦克纵坐标 :param order: 玩家坦克序号,1表示一号玩家,2表示二号玩家 :param amour: 坦克初始护甲 """ super().__init__() self.images = [] if order == 1: self.images.append({ 'UP': pygame.image.load('../Image/Player1/45x45/UP1.png'), 'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN1.png'), 'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT1.png'), 'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT1.png') }) self.images.append({ 'UP': pygame.image.load('../Image/Player1/45x45/UP2.png'), 'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN2.png'), 'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT2.png'), 'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT2.png') }) self.images.append({ 'UP': pygame.image.load('../Image/Player1/45x45/UP3.png'), 'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN3.png'), 'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT3.png'), 'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT3.png') }) self.images.append({ 'UP': pygame.image.load('../Image/Player1/45x45/UP4.png'), 'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN4.png'), 'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT4.png'), 'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT4.png') }) self.images.append({ 'UP': pygame.image.load('../Image/Player1/45x45/UP5.png'), 'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN5.png'), 'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT5.png'), 'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT5.png') }) self.images.append({ 'UP': pygame.image.load('../Image/Player1/45x45/UP6.png'), 'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN6.png'), 'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT6.png'), 'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT6.png') }) # 生命 self.life = 3 # 装甲 self.armor = amour # 方向 self.direction = 'UP' # 根据护甲选择坦克的样子 self.image: pg.Surface = self.images[max(self.armor - 1, 0)][self.direction] self.rect = self.image.get_rect() self.rect.left = x self.rect.top = y # 速度 self.accumulation: float = 0 self.speed = 2 # 移动开关 self.stop = True # 碰撞前的坐标 self.prvX = self.rect.left self.prvY = self.rect.top # 等级 self.level = 1 # 伤害 self.damage = 1 def move(self): if self.accumulation >= 1: self.accumulation = 0 if self.direction == 'LEFT': if self.rect.left > 0: self.rect.left -= self.speed elif self.direction == 'UP': if self.rect.top > 0: self.rect.top -= self.speed elif self.direction == 'DOWN': if self.rect.top < 555: self.rect.top += self.speed elif self.direction == 'RIGHT': if self.rect.left < 855: self.rect.left += self.speed else: self.accumulation += 0.20 def shot(self): pass def draw(self, window): # 坦克生命中为0,表示已经死亡,不再展示坦克 if self.life <= 0: return # 获取展示的对象 self.image = self.images[max(self.armor - 1, 0)][self.direction] # 画出图片 window.blit(self.image, self.rect)
我方坦克类中移动和显示函数实现后,就要让它们在主类中调用
添加类变量playerTank
,用于存放我方坦克的对象
修改循环中的代码
while 1: # 设置背景颜色 MainGame.window.fill(BACKGROUND_COLOR) # 获取窗口事件 self.getPlayingModeEvent() # 显示我方坦克 MainGame.playerTank.draw(MainGame.window) # 我方坦克移动 if not MainGame.playerTank.stop: MainGame.playerTank.move() # 更新窗口 pygame.display.update()
完整我方坦克类代码
import pygame import sys from PlayerTank import PlayerTank SCREEN_WIDTH = 1100 SCREEN_HEIGHT = 600 BACKGROUND_COLOR = pygame.Color(0, 0, 0) FONT_COLOR = (255, 255, 255) PLAYER_TANK_POSITION = (325, 550) class MainGame: # 窗口Surface对象 window = None # 玩家坦克 playerTank = None def __init__(self): pass def startGame(self): # 初始化展示模块 pygame.display.init() # 设置窗口大小 size = (SCREEN_WIDTH, SCREEN_HEIGHT) # 初始化窗口 MainGame.window = pygame.display.set_mode(size) # 设置窗口标题 pygame.display.set_caption('Tank Battle') # 初始化我方坦克 MainGame.playerTank = PlayerTank(PLAYER_TANK_POSITION[0], PLAYER_TANK_POSITION[1], 1, 1) while 1: # 设置背景颜色 MainGame.window.fill(BACKGROUND_COLOR) # 获取窗口事件 self.getPlayingModeEvent() # 显示我方坦克 MainGame.playerTank.draw(MainGame.window) # 我方坦克移动 if not MainGame.playerTank.stop: MainGame.playerTank.move() # 更新窗口 pygame.display.update() def getPlayingModeEvent(self): # 获取所有事件 eventList = pygame.event.get() for event in eventList: if event.type == pygame.QUIT: sys.exit() """ stop属性用来控制坦克移动,当键盘按键按下时,坦克可以移动,一直按住一直移动,当按键抬起时,停止移动 如果没有该属性,按一下按键移动一次,按一下移动一下,不能一直按住一直移动 """ if event.type == pygame.KEYDOWN: print('键盘按键按下') if event.key == pygame.K_w: MainGame.playerTank.direction = 'UP' MainGame.playerTank.stop = False elif event.key == pygame.K_s: MainGame.playerTank.direction = 'DOWN' MainGame.playerTank.stop = False elif event.key == pygame.K_a: MainGame.playerTank.direction = 'LEFT' MainGame.playerTank.stop = False elif event.key == pygame.K_d: MainGame.playerTank.direction = 'RIGHT' MainGame.playerTank.stop = False elif event.key == pygame.K_j: print('j按下') if event.type == pygame.KEYUP: print('键盘按键抬起') if event.key == pygame.K_w: MainGame.playerTank.stop = True elif event.key == pygame.K_s: MainGame.playerTank.stop = True elif event.key == pygame.K_a: MainGame.playerTank.stop = True elif event.key == pygame.K_d: MainGame.playerTank.stop = True if __name__ == '__main__': MainGame().startGame()
运行结果
现在已经实现了坦克的移动啦,下面就要实现坦克的发射子弹
实际上,子弹也是一幅图片,当我们按下开火按键后,就在坦克的正前方画出子弹,随着时间的流逝,要让子弹按照当前方向一直运动下去
import pygame from ParentObject import ParentObject class Bullet(ParentObject): def __init__(self, tank): super().__init__() self.images = { 'UP': pygame.image.load('../Image/Bullet/Bullet(UP).png'), 'DOWN': pygame.image.load('../Image/Bullet/Bullet(DOWN).png'), 'LEFT': pygame.image.load('../Image/Bullet/Bullet(LEFT).png'), 'RIGHT': pygame.image.load('../Image/Bullet/Bullet(RIGHT).png') } # 方向 self.direction = tank.direction self.image: pygame.Surface = self.images[self.direction] self.rect = self.image.get_rect() # 坦克发射子弹的位置 if self.direction == 'UP': self.rect.left = tank.rect.left + 17.5 self.rect.top = tank.rect.top - 25 elif self.direction == 'DOWN': self.rect.left = tank.rect.left + 17.5 self.rect.top = tank.rect.top + 25 elif self.direction == 'LEFT': self.rect.left = tank.rect.left - 25 self.rect.top = tank.rect.top + 17.5 elif self.direction == 'RIGHT': self.rect.left = tank.rect.left + 25 self.rect.top = tank.rect.top + 17.5 # 速度 self.accumulationMax: float = 0 self.accumulation = 0.25 self.speed = 10 # 销毁开关 self.isDestroy = False # 发射源 self.source = tank # 伤害 self.damage = tank.damage def move(self, explodeList): pass def draw(self, window): window.blit(self.image, self.rect)
下面是确定子弹的位置:
子弹图片是25x10,坦克发射子弹是在坦克中间位置发射
子弹的初始位置确定后,一旦创建出来,就要一直移动下去,实际上就是刷新屏幕,然后把原来位置上的子弹图片去掉,在新的位置上再画出子弹图片,坦克移动的原理也是这样
修改move函数,添加检查子弹出界函数
def move(self): if self.accumulation >= 1: self.accumulation = 0 if self.direction == 'LEFT': self.rect.left -= self.speed elif self.direction == 'UP': self.rect.top -= self.speed elif self.direction == 'DOWN': self.rect.top += self.speed elif self.direction == 'RIGHT': self.rect.left += self.speed # 检查子弹是否出界 self.checkBullet() else: self.accumulation += 0.20 def checkBullet(self): toDestroy = False # 如果出界,就设置为销毁 if self.rect.top < 0 or self.rect.top > 600: toDestroy = True if self.rect.left < 0 or self.rect.right > 900: toDestroy = True if toDestroy: self.isDestroy = True
子弹类完整代码
import pygame from ParentObject import ParentObject class Bullet(ParentObject): def __init__(self, tank): super().__init__() self.images = { 'UP': pygame.image.load('../Image/Bullet/Bullet(UP).png'), 'DOWN': pygame.image.load('../Image/Bullet/Bullet(DOWN).png'), 'LEFT': pygame.image.load('../Image/Bullet/Bullet(LEFT).png'), 'RIGHT': pygame.image.load('../Image/Bullet/Bullet(RIGHT).png') } # 方向 self.direction = tank.direction self.image: pygame.Surface = self.images[self.direction] self.rect = self.image.get_rect() # 坦克发射子弹的位置 if self.direction == 'UP': self.rect.left = tank.rect.left + 17.5 self.rect.top = tank.rect.top - 25 elif self.direction == 'DOWN': self.rect.left = tank.rect.left + 17.5 self.rect.top = tank.rect.top + 25 elif self.direction == 'LEFT': self.rect.left = tank.rect.left - 25 self.rect.top = tank.rect.top + 17.5 elif self.direction == 'RIGHT': self.rect.left = tank.rect.left + 25 self.rect.top = tank.rect.top + 17.5 # 速度 self.accumulationMax: float = 0 self.accumulation = 0.25 self.speed = 10 # 销毁开关 self.isDestroy = False # 发射源 self.source = tank # 伤害 self.damage = tank.damage def move(self): if self.accumulation >= 1: self.accumulation = 0 if self.direction == 'LEFT': self.rect.left -= self.speed elif self.direction == 'UP': self.rect.top -= self.speed elif self.direction == 'DOWN': self.rect.top += self.speed elif self.direction == 'RIGHT': self.rect.left += self.speed # 检查子弹是否出界 self.checkBullet() else: self.accumulation += 0.20 def checkBullet(self): toDestroy = False # 如果出界,就设置为销毁 if self.rect.top < 0 or self.rect.top > 600: toDestroy = True if self.rect.left < 0 or self.rect.right > 900: toDestroy = True if toDestroy: self.isDestroy = True def draw(self, window): window.blit(self.image, self.rect)
有了子弹类,就可以让坦克发射子弹了
在主类中设置玩家子弹数量的最大值
... ...
class MainGame:
# 窗口Surface对象
window = None
# 指定的子弹个数,这里设置玩家的子弹最多只有3颗子弹可以同时在场
playerBulletNumber = 3
# 玩家坦克
playerTank = None
... ...
修改坦克的 shot() 函数
def shot(self):
return Bullet(self)
修改 getPlayingModeEvent() 函数
当 j键按下,发射子弹
def getPlayingModeEvent(self): # 获取所有事件 eventList = pygame.event.get() for event in eventList: if event.type == pygame.QUIT: sys.exit() """ stop属性用来控制坦克移动,当键盘按键按下时,坦克可以移动,一直按住一直移动,当按键抬起时,停止移动 如果没有该属性,按一下按键移动一次,按一下移动一下,不能一直按住一直移动 """ if event.type == pygame.KEYDOWN: print('键盘按键按下') if event.key == pygame.K_w: MainGame.playerTank.direction = 'UP' MainGame.playerTank.stop = False elif event.key == pygame.K_s: MainGame.playerTank.direction = 'DOWN' MainGame.playerTank.stop = False elif event.key == pygame.K_a: MainGame.playerTank.direction = 'LEFT' MainGame.playerTank.stop = False elif event.key == pygame.K_d: MainGame.playerTank.direction = 'RIGHT' MainGame.playerTank.stop = False elif event.key == pygame.K_j: # 判断子弹数量是否超过指定的个数 if len(MainGame.playerBulletList) < MainGame.playerBulletNumber: bullet = MainGame.playerTank.shot() MainGame.playerBulletList.append(bullet) if event.type == pygame.KEYUP: print('键盘按键抬起') if event.key == pygame.K_w: MainGame.playerTank.stop = True elif event.key == pygame.K_s: MainGame.playerTank.stop = True elif event.key == pygame.K_a: MainGame.playerTank.stop = True elif event.key == pygame.K_d: MainGame.playerTank.stop = True
子弹有了,但是没有显示在窗口,此时写一个函数让子弹在窗口显示出来
def drawPlayerBullet(self, playerBulletList):
# 遍历整个子弹列表,如果是没有被销毁的状态,就把子弹显示出来,否则从列表中删除
for bullet in playerBulletList:
if not bullet.isDestroy:
bullet.draw(MainGame.window)
bullet.move()
else:
playerBulletList.remove(bullet)
有了函数还需要调用,在while循环中加入该函数
while 1: # 设置背景颜色 MainGame.window.fill(BACKGROUND_COLOR) # 获取窗口事件 self.getPlayingModeEvent() # 显示我方坦克 MainGame.playerTank.draw(MainGame.window) # 我方坦克移动 if not MainGame.playerTank.stop: MainGame.playerTank.move() # 显示我方坦克子弹 self.drawPlayerBullet(MainGame.playerBulletList) # 更新窗口 pygame.display.update()
运行游戏看看结果
当我们按下开火键时,子弹就发射了
注意:MainGame.playerBulletList 需要定义出来,否则程序运行会报错
添加位置如下:
... ...
class MainGame:
# 窗口Surface对象
window = None
playerBulletList = []
playerBulletNumber = 3
# 玩家坦克
playerTank = None
... ...
现在我的坦克可以移动和开火,那么就要有点靶子给我们练习了,是时候实现敌方坦克类了
敌方坦克类的大部分代码跟我方坦克类一样,这里可以用继承,即父类是坦克类,实现两个类的一样的代码,然后我方坦克类和敌方坦克类继承这个类,不过我没有使用继承
import random import pygame import pygame.image from ParentObject import ParentObject from Bullet import Bullet class EnemyTank(ParentObject): def __init__(self, x, y): super().__init__() types = [(1, 3), (2, 1), (3, 2), (4, 10)] # 随机产生一种坦克 self.type = types[random.randint(0, len(types) - 1)] up = [] down = [] left = [] right = [] for i in range(1, self.type[1] + 1): up.append( pygame.image.load( '../Image/Enemy/EnemyTank' + str(self.type[0]) + '/EnemyTank'+ str(self.type[0]) + 'Lv' + str(i) + '(UP).png' ) ) down.append( pygame.image.load( '../Image/Enemy/EnemyTank' + str(self.type[0]) + '/EnemyTank'+ str(self.type[0]) + 'Lv' + str(i) + '(DOWN).png' ) ) left.append( pygame.image.load( '../Image/Enemy/EnemyTank' + str(self.type[0]) + '/EnemyTank' + str(self.type[0]) + 'Lv' + str( i) + '(LEFT).png' ) ) right.append( pygame.image.load( '../Image/Enemy/EnemyTank' + str(self.type[0]) + '/EnemyTank' + str(self.type[0]) + 'Lv' + str( i) + '(RIGHT).png' ) ) self.images = { 'UP': up, 'DOWN': down, 'LEFT': left, 'RIGHT': right } # 生命 self.life = self.type[1] # 方向 self.direction = 'DOWN' self.image: pygame.Surface = self.images[self.direction][self.life - 1] self.rect = self.image.get_rect() self.rect.left = x self.rect.top = y # 速度 self.accumulationMax: float = 0 self.accumulation = 0.1 speed = 0 maxBulletCount = 0 damage = 1 if self.type[0] == 1: speed = 3 self.level = 1 maxBulletCount = 1 elif self.type[0] == 2: speed = 5 self.level = 2 maxBulletCount = 1 damage = 3 elif self.type[0] == 3: speed = 7 self.level = 1 maxBulletCount = 3 damage = 2 elif self.type[0] == 4: speed = 6 self.level = 2 maxBulletCount = 3 damage = 1 self.speed = speed # 移动开关 self.stop = True # 开火开关 self.fire = True # 步数 self.step = 30 # 伤害 self.damage = damage # 子弹个数 self.bulletCount = 0 self.maxBulletCount = maxBulletCount def move(self): """ 新增步数变量, 当坦克移动时, 步数进行减少, 当步数小于等于0的时候, 修改地方坦克的方向 :return: None """ if self.stop: if self.step <= 0: self.direction = self.randDirection() self.step = 30 else: if self.accumulationMax >= 1: self.accumulationMax = 0 if self.direction == 'LEFT': if self.rect.left > 0: self.rect.left -= self.speed elif self.direction == 'UP': if self.rect.top > 0: self.rect.top -= self.speed elif self.direction == 'DOWN': if self.rect.top < 555: self.rect.top += self.speed elif self.direction == 'RIGHT': if self.rect.left < 855: self.rect.left += self.speed self.step -= 1 else: self.accumulationMax += self.accumulation def shot(self): if self.fire: if self.bulletCount < self.maxBulletCount: num = random.randint(0, 100) if num == 5 or num == 6: self.bulletCount += 1 return Bullet(self) return None def draw(self, window): # 获取展示的对象 self.image = self.images[self.direction][self.life - 1] window.blit(self.image, self.rect) def randDirection(self): directions = ['UP', 'DOWN', 'LEFT', 'RIGHT'] index = random.randint(0, 3) return directions[index]
我实际上设置了四种坦克的种类,下面types变量中记录着四种种类的序号和生命值,我规定,生命中不同坦克的样子也不同
types = [(1, 3), (2, 1), (3, 2), (4, 10)]
# 随机产生一种坦克
self.type = types[random.randint(0, len(types) - 1)]
元组中的第二个元素表示生命值, 直接获取
# 生命
self.life = self.type[1]
根据方向和生命值获取对应的图片
self.image: pygame.Surface = self.images[self.direction][self.life - 1]
坦克的属性
根据坦克种类的不同,伤害、等级、生命值也不同
等级是子弹的穿透性,1级只能打烂砖墙,2级可以打烂石墙,3级以上可以打烂黑曜石墙,这个黑曜石墙是我自己新加入的,我们以前玩的坦克大战是没有的,而且规则和我这个不太一样,当然你也可以修改,比如给坦克加入能量,当坦克在一定时间内连续击杀多个敌人,可以获得怒气,短时间伤害提升,这些都可以实现
speed = 0 maxBulletCount = 0 damage = 1 # 每种坦克都有不同的属性 if self.type[0] == 1: speed = 3 self.level = 1 maxBulletCount = 1 elif self.type[0] == 2: speed = 5 self.level = 2 maxBulletCount = 1 damage = 3 elif self.type[0] == 3: speed = 7 self.level = 1 maxBulletCount = 3 damage = 2 elif self.type[0] == 4: speed = 6 self.level = 2 maxBulletCount = 3 damage = 1
坦克的移动
step是步数,每次按照30次循环作为一次坦克的操作
if self.stop: if self.step <= 0: # 随机产生一个方向,接下来朝这个方向移动 self.direction = self.randDirection() self.step = 30 else: if self.accumulationMax >= 1: self.accumulationMax = 0 if self.direction == 'LEFT': if self.rect.left > 0: self.rect.left -= self.speed elif self.direction == 'UP': if self.rect.top > 0: self.rect.top -= self.speed elif self.direction == 'DOWN': if self.rect.top < 555: self.rect.top += self.speed elif self.direction == 'RIGHT': if self.rect.left < 855: self.rect.left += self.speed self.step -= 1 else: self.accumulationMax += self.accumulation
坦克开火
随机产生一个0到100的数字,当为5或者6时,坦克就开火
def shot(self):
if self.fire:
if self.bulletCount < self.maxBulletCount:
num = random.randint(0, 100)
if num == 5 or num == 6:
self.bulletCount += 1
return Bullet(self)
return None
在上面的代码中,下面的变量用来设置敌方坦克是否移动,是否开火
# 移动开关
self.stop = True
# 开火开关
self.fire = True
在主类中创建类变量
class MainGame: # 窗口Surface对象 window = None # 玩家坦克 playerTank = None # 玩家子弹 playerBulletList = [] playerBulletNumber = 3 # 敌人坦克 enemyTankList = [] enemyTankTotalCount = 5 # 用来给玩家展示坦克的数量 enemyTankCurrentCount = 5 # 敌人坦克子弹 enemyTankListBulletList = []
创建展示敌方坦克函数
这里我规定一次展示三辆敌方坦克,当全部被消灭后,再展示3辆,直到全部被消灭
def drawEnemyTank(self): # 如果当前坦克为0,那么就该重新生成坦克 if len(MainGame.enemyTankList) == 0: # 一次性产生三个,如果剩余坦克数量超过三,那只能产生三个 n = min(3, MainGame.enemyTankTotalCount) # 如果最小是0,就说明敌人坦克没有了,那么就赢了 if n == 0: print('赢了') return # 没有赢的话,就产生n个坦克 self.initEnemyTank(n) # 总个数减去产生的个数 MainGame.enemyTankTotalCount -= n # 遍历坦克列表,展示坦克并且移动 for tank in MainGame.enemyTankList: # 坦克还有生命值 if tank.life > 0: tank.draw(MainGame.window) tank.move() bullet = tank.shot() if bullet is not None: MainGame.enemyTankBulletList.append(bullet) # 坦克生命值为0,就从列表中剔除 else: MainGame.enemyTankCurrentCount -= 1 MainGame.enemyTankList.remove(tank)
坦克开火之后子弹加入敌方坦克子弹列表,把里面的子弹画出来,然后在while中调用它
def drawEnemyBullet(self):
for bullet in MainGame.enemyTankBulletList:
if not bullet.isDestroy:
bullet.draw(MainGame.window)
bullet.move()
else:
bullet.source.bulletCount -= 1
MainGame.enemyTankBulletList.remove(bullet)
while 1: # 设置背景颜色 MainGame.window.fill(BACKGROUND_COLOR) # 获取窗口事件 self.getPlayingModeEvent() # 显示我方坦克 MainGame.playerTank.draw(MainGame.window) # 我方坦克移动 if not MainGame.playerTank.stop: MainGame.playerTank.move() # 显示我方坦克子弹 self.drawPlayerBullet(MainGame.playerBulletList) # 展示敌方坦克 self.drawEnemyTank() # 展示敌方坦克子弹 self.drawEnemyBullet() # 更新窗口 pygame.display.update()
完整的主类代码
import pygame import sys from PlayerTank import PlayerTank from EnemyTank import EnemyTank SCREEN_WIDTH = 1100 SCREEN_HEIGHT = 600 BACKGROUND_COLOR = pygame.Color(0, 0, 0) FONT_COLOR = (255, 255, 255) PLAYER_TANK_POSITION = (325, 550) class MainGame: # 窗口Surface对象 window = None # 玩家坦克 playerTank = None # 玩家子弹 playerBulletList = [] playerBulletNumber = 3 # 敌人坦克 enemyTankList = [] enemyTankTotalCount = 5 # 用来给玩家展示坦克的数量 enemyTankCurrentCount = 5 # 敌人坦克子弹 enemyTankBulletList = [] def __init__(self): pass def startGame(self): # 初始化展示模块 pygame.display.init() # 设置窗口大小 size = (SCREEN_WIDTH, SCREEN_HEIGHT) # 初始化窗口 MainGame.window = pygame.display.set_mode(size) # 设置窗口标题 pygame.display.set_caption('Tank Battle') # 初始化我方坦克 MainGame.playerTank = PlayerTank(PLAYER_TANK_POSITION[0], PLAYER_TANK_POSITION[1], 1, 1) while 1: # 设置背景颜色 MainGame.window.fill(BACKGROUND_COLOR) # 获取窗口事件 self.getPlayingModeEvent() # 显示我方坦克 MainGame.playerTank.draw(MainGame.window) # 我方坦克移动 if not MainGame.playerTank.stop: MainGame.playerTank.move() # 显示我方坦克子弹 self.drawPlayerBullet(MainGame.playerBulletList) # 展示敌方坦克 self.drawEnemyTank() # 展示敌方坦克子弹 self.drawEnemyBullet() # 更新窗口 pygame.display.update() def getPlayingModeEvent(self): # 获取所有事件 eventList = pygame.event.get() for event in eventList: if event.type == pygame.QUIT: sys.exit() """ stop属性用来控制坦克移动,当键盘按键按下时,坦克可以移动,一直按住一直移动,当按键抬起时,停止移动 如果没有该属性,按一下按键移动一次,按一下移动一下,不能一直按住一直移动 """ if event.type == pygame.KEYDOWN: if event.key == pygame.K_w: MainGame.playerTank.direction = 'UP' MainGame.playerTank.stop = False elif event.key == pygame.K_s: MainGame.playerTank.direction = 'DOWN' MainGame.playerTank.stop = False elif event.key == pygame.K_a: MainGame.playerTank.direction = 'LEFT' MainGame.playerTank.stop = False elif event.key == pygame.K_d: MainGame.playerTank.direction = 'RIGHT' MainGame.playerTank.stop = False elif event.key == pygame.K_j: # 判断子弹数量是否超过指定的个数 if len(MainGame.playerBulletList) < MainGame.playerBulletNumber: bullet = MainGame.playerTank.shot() MainGame.playerBulletList.append(bullet) if event.type == pygame.KEYUP: if event.key == pygame.K_w: MainGame.playerTank.stop = True elif event.key == pygame.K_s: MainGame.playerTank.stop = True elif event.key == pygame.K_a: MainGame.playerTank.stop = True elif event.key == pygame.K_d: MainGame.playerTank.stop = True def drawPlayerBullet(self, playerBulletList): # 遍历整个子弹列表,如果是没有被销毁的状态,就把子弹显示出来,否则从列表中删除 for bullet in playerBulletList: if not bullet.isDestroy: bullet.draw(MainGame.window) bullet.move() else: playerBulletList.remove(bullet) def drawEnemyTank(self): # 如果当前坦克为0,那么就该重新生成坦克 if len(MainGame.enemyTankList) == 0: # 一次性产生三个,如果剩余坦克数量超过三,那只能产生三个 n = min(3, MainGame.enemyTankTotalCount) # 如果最小是0,就说明敌人坦克没有了,那么就赢了 if n == 0: print('赢了') return # 没有赢的话,就产生n个坦克 self.initEnemyTank(n) # 总个数减去产生的个数 MainGame.enemyTankTotalCount -= n # 遍历坦克列表,展示坦克并且移动 for tank in MainGame.enemyTankList: # 坦克还有生命值 if tank.life > 0: tank.draw(MainGame.window) tank.move() bullet = tank.shot() if bullet is not None: MainGame.enemyTankBulletList.append(bullet) # 坦克生命值为0,就从列表中剔除 else: MainGame.enemyTankCurrentCount -= 1 MainGame.enemyTankList.remove(tank) def initEnemyTank(self, number): y = 0 position = [0, 425, 850] index = 0 for i in range(number): x = position[index] enemyTank = EnemyTank(x, y) MainGame.enemyTankList.append(enemyTank) index += 1 def drawEnemyBullet(self): for bullet in MainGame.enemyTankBulletList: if not bullet.isDestroy: bullet.draw(MainGame.window) bullet.move() else: bullet.source.bulletCount -= 1 MainGame.enemyTankBulletList.remove(bullet) if __name__ == '__main__': MainGame().startGame()
运行一下,看看结果
哈哈,终于实现发射子弹啦
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。