当前位置: 首页 > news >正文

学习 Python 之 Pygame 开发坦克大战(二)

学习 Python 之 Pygame 开发坦克大战(二)

    • 坦克大战的需求
    • 开始编写坦克大战
      • 1. 搭建主类框架
      • 2. 获取窗口中的事件
      • 3. 创建基类
      • 4. 初始化我方坦克类
      • 5. 完善我方坦克的移动
      • 5. 完善我方坦克的显示
      • 6. 在主类中加入我方坦克并完成坦克移动
      • 7. 初始化子弹类
      • 8. 完善子弹的移动
      • 9. 完善坦克开火
      • 10. 实现敌方坦克类
      • 11. 在主类中加入敌方坦克并完成坦克移动和开火

坦克大战的需求

坦克大战游戏包含很多个物体,现在要对这些物体进行总结

类名包含的操作包含的属性
敌方坦克类射击,移动,显示生命,速度,伤害,方向,类型
我方坦克类射击,移动,显示生命,速度,伤害,方向,装甲,等级
子弹类移动,显示方向,伤害,发射源,速度
墙壁类、草类、石砖类、河类显示是否可以摧毁
音效类播放,停止,设置音乐-
爆炸效果类显示是否可以摧毁
主类

物体总结完毕后,规划一下窗口的大小,下面是我设置的窗口大小
在这里插入图片描述
素材链接:百度网盘
链接:https://pan.baidu.com/s/19sCyH7rp37f6DzRj0iXDCA?pwd=tkdz
提取码:tkdz

开始编写坦克大战

一切都准备就绪啦,现在开始编写坦克大战的代码吧

1. 搭建主类框架

主类是整个游戏运作的类,当然你也可以不用使用类,直接创建一个函数也可以,这里使用了面向对象的思想

import pygameSCREEN_WIDTH = 1100
SCREEN_HEIGHT = 600
BACKGROUND_COLOR = pygame.Color(0, 0, 0)
FONT_COLOR = (255, 255, 255)
class MainGame:# 窗口Surface对象window = Nonedef __init__(self):passdef 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 开发坦克大战(一)中所包含的

2. 获取窗口中的事件

坦克大战关键是对玩家自己的坦克进行操控,消灭敌人的坦克,所以键盘事件响应是必不可少的

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 sysSCREEN_WIDTH = 1100
SCREEN_HEIGHT = 600
BACKGROUND_COLOR = pygame.Color(0, 0, 0)
FONT_COLOR = (255, 255, 255)
class MainGame:# 窗口Surface对象window = Nonedef __init__(self):passdef 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()

3. 创建基类

坦克操控事件完成后,现在就是实现坦克啦,首先场景中的物体都需要发生物体间的碰撞,简单来说就是检测两个屏幕上的图片是否发生了重叠,如果发生了,就要触发一些事件,这里创建ParentObject类,用于继承pygame.sprite.Sprite类

pygame.sprite.Sprite类可以用来检测物体碰撞,是pygame提供的一个类,非常的方便

import pygame.spriteclass ParentObject(pygame.sprite.Sprite):def __init__(self):super().__init__()

4. 初始化我方坦克类

创建我方坦克类,并且继承基类

import pygame as pg
import pygame.image
from ParentObject import ParentObjectclass 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 = xself.rect.top = y# 速度self.accumulation: float = 0self.speed = 2# 移动开关self.stop = True# 等级self.level = 1# 伤害self.damage = 1def move(self):passdef shot(self):passdef draw(self):pass

5. 完善我方坦克的移动

accumulation 可以更细的控制坦克的移动速度

当 accumulation 累加到 1 时,坦克移动一次,如果不设置这个属性,即使是速度每次 +1,坦克移动的也速度很快,所以增加这个属性,可以减慢坦克的移动速度

def move(self):if self.accumulation >= 1:self.accumulation = 0if self.direction == 'LEFT':if self.rect.left > 0:self.rect.left -= self.speedelif self.direction == 'UP':if self.rect.top > 0:self.rect.top -= self.speedelif self.direction == 'DOWN':if self.rect.top < 555:self.rect.top += self.speedelif self.direction == 'RIGHT':if self.rect.left < 855:self.rect.left += self.speedelse:self.accumulation += 0.20

这里需要设置坦克的边界范围
防止坦克跑出窗口

坦克的图片是45x45
在这里插入图片描述

5. 完善我方坦克的显示

坦克的显示就是把坦克的图片显示在窗口中

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 ParentObjectclass 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 = xself.rect.top = y# 速度self.accumulation: float = 0self.speed = 2# 移动开关self.stop = True# 重生self.isResurrecting = False# 碰撞前的坐标self.prvX = self.rect.leftself.prvY = self.rect.top# 等级self.level = 1# 伤害self.damage = 1def move(self):if self.accumulation >= 1:self.accumulation = 0if self.direction == 'LEFT':if self.rect.left > 0:self.rect.left -= self.speedelif self.direction == 'UP':if self.rect.top > 0:self.rect.top -= self.speedelif self.direction == 'DOWN':if self.rect.top < 555:self.rect.top += self.speedelif self.direction == 'RIGHT':if self.rect.left < 855:self.rect.left += self.speedelse:self.accumulation += 0.20def shot(self):passdef 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)

6. 在主类中加入我方坦克并完成坦克移动

我方坦克类中移动和显示函数实现后,就要让它们在主类中调用

添加类变量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 sysfrom PlayerTank import PlayerTankSCREEN_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 = Nonedef __init__(self):passdef 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 = Falseelif event.key == pygame.K_s:MainGame.playerTank.direction = 'DOWN'MainGame.playerTank.stop = Falseelif event.key == pygame.K_a:MainGame.playerTank.direction = 'LEFT'MainGame.playerTank.stop = Falseelif event.key == pygame.K_d:MainGame.playerTank.direction = 'RIGHT'MainGame.playerTank.stop = Falseelif event.key == pygame.K_j:print('j按下')if event.type == pygame.KEYUP:print('键盘按键抬起')if event.key == pygame.K_w:MainGame.playerTank.stop = Trueelif event.key == pygame.K_s:MainGame.playerTank.stop = Trueelif event.key == pygame.K_a:MainGame.playerTank.stop = Trueelif event.key == pygame.K_d:MainGame.playerTank.stop = Trueif __name__ == '__main__':MainGame().startGame()

运行结果
在这里插入图片描述

7. 初始化子弹类

现在已经实现了坦克的移动啦,下面就要实现坦克的发射子弹

实际上,子弹也是一幅图片,当我们按下开火按键后,就在坦克的正前方画出子弹,随着时间的流逝,要让子弹按照当前方向一直运动下去

import pygame
from ParentObject import ParentObjectclass 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.directionself.image: pygame.Surface = self.images[self.direction]self.rect = self.image.get_rect()# 坦克发射子弹的位置if self.direction == 'UP':self.rect.left = tank.rect.left + 17.5self.rect.top = tank.rect.top - 25elif self.direction == 'DOWN':self.rect.left = tank.rect.left + 17.5self.rect.top = tank.rect.top + 25elif self.direction == 'LEFT':self.rect.left = tank.rect.left - 25self.rect.top = tank.rect.top + 17.5elif self.direction == 'RIGHT':self.rect.left = tank.rect.left + 25self.rect.top = tank.rect.top + 17.5# 速度self.accumulationMax: float = 0self.accumulation = 0.25self.speed = 10# 销毁开关self.isDestroy = False# 发射源self.source = tank# 伤害self.damage = tank.damagedef move(self, explodeList):passdef draw(self, window):window.blit(self.image, self.rect)

下面是确定子弹的位置:

子弹图片是25x10,坦克发射子弹是在坦克中间位置发射

在这里插入图片描述

8. 完善子弹的移动

子弹的初始位置确定后,一旦创建出来,就要一直移动下去,实际上就是刷新屏幕,然后把原来位置上的子弹图片去掉,在新的位置上再画出子弹图片,坦克移动的原理也是这样

修改move函数,添加检查子弹出界函数

    def move(self):if self.accumulation >= 1:self.accumulation = 0if self.direction == 'LEFT':self.rect.left -= self.speedelif self.direction == 'UP':self.rect.top -= self.speedelif self.direction == 'DOWN':self.rect.top += self.speedelif self.direction == 'RIGHT':self.rect.left += self.speed# 检查子弹是否出界self.checkBullet()else:self.accumulation += 0.20def checkBullet(self):toDestroy = False# 如果出界,就设置为销毁if self.rect.top < 0 or self.rect.top > 600:toDestroy = Trueif self.rect.left < 0 or self.rect.right > 900:toDestroy = Trueif toDestroy:self.isDestroy = True

子弹类完整代码

import pygame
from ParentObject import ParentObjectclass 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.directionself.image: pygame.Surface = self.images[self.direction]self.rect = self.image.get_rect()# 坦克发射子弹的位置if self.direction == 'UP':self.rect.left = tank.rect.left + 17.5self.rect.top = tank.rect.top - 25elif self.direction == 'DOWN':self.rect.left = tank.rect.left + 17.5self.rect.top = tank.rect.top + 25elif self.direction == 'LEFT':self.rect.left = tank.rect.left - 25self.rect.top = tank.rect.top + 17.5elif self.direction == 'RIGHT':self.rect.left = tank.rect.left + 25self.rect.top = tank.rect.top + 17.5# 速度self.accumulationMax: float = 0self.accumulation = 0.25self.speed = 10# 销毁开关self.isDestroy = False# 发射源self.source = tank# 伤害self.damage = tank.damagedef move(self):if self.accumulation >= 1:self.accumulation = 0if self.direction == 'LEFT':self.rect.left -= self.speedelif self.direction == 'UP':self.rect.top -= self.speedelif self.direction == 'DOWN':self.rect.top += self.speedelif self.direction == 'RIGHT':self.rect.left += self.speed# 检查子弹是否出界self.checkBullet()else:self.accumulation += 0.20def checkBullet(self):toDestroy = False# 如果出界,就设置为销毁if self.rect.top < 0 or self.rect.top > 600:toDestroy = Trueif self.rect.left < 0 or self.rect.right > 900:toDestroy = Trueif toDestroy:self.isDestroy = Truedef draw(self, window):window.blit(self.image, self.rect)

9. 完善坦克开火

有了子弹类,就可以让坦克发射子弹了

修改坦克的 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 = Falseelif event.key == pygame.K_s:MainGame.playerTank.direction = 'DOWN'MainGame.playerTank.stop = Falseelif event.key == pygame.K_a:MainGame.playerTank.direction = 'LEFT'MainGame.playerTank.stop = Falseelif event.key == pygame.K_d:MainGame.playerTank.direction = 'RIGHT'MainGame.playerTank.stop = Falseelif 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 = Trueelif event.key == pygame.K_s:MainGame.playerTank.stop = Trueelif event.key == pygame.K_a:MainGame.playerTank.stop = Trueelif 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()

运行游戏看看结果

当我们按下开火键时,子弹就发射了

在这里插入图片描述

10. 实现敌方坦克类

现在我的坦克可以移动和开火,那么就要有点靶子给我们练习了,是时候实现敌方坦克类了

敌方坦克类的大部分代码跟我方坦克类一样,这里可以用继承,即父类是坦克类,实现两个类的一样的代码,然后我方坦克类和敌方坦克类继承这个类,不过我没有使用继承

import random
import pygame
import pygame.imagefrom ParentObject import ParentObject
from Bullet import Bulletclass 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 = xself.rect.top = y# 速度self.accumulationMax: float = 0self.accumulation = 0.1speed = 0maxBulletCount = 0damage = 1if self.type[0] == 1:speed = 3self.level = 1maxBulletCount = 1elif self.type[0] == 2:speed = 5self.level = 2maxBulletCount = 1damage = 3elif self.type[0] == 3:speed = 7self.level = 1maxBulletCount = 3damage = 2elif self.type[0] == 4:speed = 6self.level = 2maxBulletCount = 3damage = 1self.speed = speed# 移动开关self.stop = True# 开火开关self.fire = True# 步数self.step = 30# 伤害self.damage = damage# 子弹个数self.bulletCount = 0self.maxBulletCount = maxBulletCountdef loseLife(self, value = 1):self.life -= valuedef move(self):"""新增步数变量, 当坦克移动时, 步数进行减少, 当步数小于等于0的时候, 修改地方坦克的方向:return: None"""if self.stop:if self.step <= 0:self.direction = self.randDirection()self.step = 30else:if self.accumulationMax >= 1:self.accumulationMax = 0if self.direction == 'LEFT':if self.rect.left > 0:self.rect.left -= self.speedelif self.direction == 'UP':if self.rect.top > 0:self.rect.top -= self.speedelif self.direction == 'DOWN':if self.rect.top < 555:self.rect.top += self.speedelif self.direction == 'RIGHT':if self.rect.left < 855:self.rect.left += self.speedself.step -= 1else:self.accumulationMax += self.accumulationdef shot(self):if self.fire:if self.bulletCount < self.maxBulletCount:num = random.randint(0, 100)if num == 5 or num == 6:self.bulletCount += 1return Bullet(self)return Nonedef 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 = 3self.level = 1maxBulletCount = 1
elif self.type[0] == 2:speed = 5self.level = 2maxBulletCount = 1damage = 3
elif self.type[0] == 3:speed = 7self.level = 1maxBulletCount = 3damage = 2
elif self.type[0] == 4:speed = 6self.level = 2maxBulletCount = 3damage = 1

坦克的移动

step是步数,每次按照30次循环作为一次坦克的操作

 if self.stop:if self.step <= 0:# 随机产生一个方向,接下来朝这个方向移动self.direction = self.randDirection()self.step = 30else:if self.accumulationMax >= 1:self.accumulationMax = 0if self.direction == 'LEFT':if self.rect.left > 0:self.rect.left -= self.speedelif self.direction == 'UP':if self.rect.top > 0:self.rect.top -= self.speedelif self.direction == 'DOWN':if self.rect.top < 555:self.rect.top += self.speedelif self.direction == 'RIGHT':if self.rect.left < 855:self.rect.left += self.speedself.step -= 1else: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 += 1return Bullet(self)return None

11. 在主类中加入敌方坦克并完成坦克移动和开火

在主类中创建类变量

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 -= 1MainGame.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 -= 1MainGame.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 sysfrom PlayerTank import PlayerTank
from EnemyTank import EnemyTankSCREEN_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):passdef 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 = Falseelif event.key == pygame.K_s:MainGame.playerTank.direction = 'DOWN'MainGame.playerTank.stop = Falseelif event.key == pygame.K_a:MainGame.playerTank.direction = 'LEFT'MainGame.playerTank.stop = Falseelif event.key == pygame.K_d:MainGame.playerTank.direction = 'RIGHT'MainGame.playerTank.stop = Falseelif 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 = Trueelif event.key == pygame.K_s:MainGame.playerTank.stop = Trueelif event.key == pygame.K_a:MainGame.playerTank.stop = Trueelif event.key == pygame.K_d:MainGame.playerTank.stop = Truedef 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 -= 1MainGame.enemyTankList.remove(tank)def initEnemyTank(self, number):y = 0position = [0, 425, 850]index = 0for i in range(number):x = position[index]enemyTank = EnemyTank(x, y)MainGame.enemyTankList.append(enemyTank)index += 1def drawEnemyBullet(self):for bullet in MainGame.enemyTankBulletList:if not bullet.isDestroy:bullet.draw(MainGame.window)bullet.move()else:bullet.source.bulletCount -= 1MainGame.enemyTankBulletList.remove(bullet)if __name__ == '__main__':MainGame().startGame()

运行一下,看看结果
在这里插入图片描述

哈哈,终于实现发射子弹啦

相关文章:

学习 Python 之 Pygame 开发坦克大战(二)

学习 Python 之 Pygame 开发坦克大战&#xff08;二&#xff09;坦克大战的需求开始编写坦克大战1. 搭建主类框架2. 获取窗口中的事件3. 创建基类4. 初始化我方坦克类5. 完善我方坦克的移动5. 完善我方坦克的显示6. 在主类中加入我方坦克并完成坦克移动7. 初始化子弹类8. 完善子…...

短视频时代是靠什么赚钱的,介绍常见的5种方式,简单明了

目前&#xff0c;短视频越来越火热&#xff0c;大家都知道做短视频可以赚钱&#xff0c;那么究竟是靠什么赚钱的&#xff0c;又有几个人知道呢&#xff1f;短视频创业有个人、有团队&#xff0c;怎么实现团队的生存和发展。 常见的几种变现方式有&#xff1a; 1、平台分成 各…...

关于CentOS维护的几条简单命令

1、检查/etc/passwd这个文件里面有没有异常用户名2、通过命令top查看是否有异常进程&#xff0c;按M键对进程进行排序3、通过命令netstat -lnpt&#xff0c;查看是否有异常端口号4、通过命令ll -a /proc/PID&#xff0c;查看异常进程执行文件所在位置5、通过命令kill -9 PID&am…...

PoW 、PoS , DPoS 算法

PoW 、PoS &#xff0c; DPoS 算法 在区块链领域&#xff0c;多采用 PoW 工作量证明算法、PoS 权益证明算法&#xff0c;以及 DPoS 代理权 益证明算法&#xff0c;以上三种是业界主流的共识算法&#xff0c;这些算法与经典分布式一致性算法不同的是 融入了经济学博弈的概念。 …...

SpringCloud(PS)远程调用--Feign

远程调用RestTemplate远程调用RestTemplate方式调用存在的问题Http客户端Feign实现步骤自定义配置Feign优化Feign性能优化——连接池配置最佳实践RestTemplate远程调用 Bean // LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}Autowiredprivat…...

2023年全国最新二级建造师精选真题及答案1

百分百题库提供二级建造师考试试题、二建考试预测题、二级建造师考试真题、二建证考试题库等&#xff0c;提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 11.当事人未依照法律、行政法规规定办理租赁合同登记备案手续的&#xff0c;租赁合同&#xf…...

HydroD 实用教程(四)水动力模型

目 录一、前言二、Hydro Properties2.1 Compartment Properties2.2 Rudder and Thruster2.3 Wind Properties三、Hydro Structure3.1 Load Cross Sections四、Loading Conditions4.1 Mass Model4.2 Second Order Surface Model4.3 Wadam Offbody Points4.4 Additional Matrices…...

vue项目第七天

项目中模块操做业务使用ajax&#xff08;需要使用接口认证&#xff09;修改封装的findData发送ajax请求管理员列表内部搜索业务复用之前的findData 方法即可实现整个查询业务。实现退出业务在下拉菜单上添加事件以及属性。用户退出登录&#xff0c;二次登录系统菜单可能不存在的…...

拂晓·微信机器人

前言 本项目是基于千寻微信框架进行的功能开发&#xff0c;采用SpringBoot青云客机器人进行开发。 千寻初衷是想开源一个框架的写法&#xff0c;并不是为了用来运营&#xff0c;因此功能不全&#xff0c;所以使用和适配前请查看是否与自己需求匹配。 因此本文主要通过千寻客…...

React:Hooks工作机制

Hooks规则 React Hooks的使用,有两个规则: Hooks只能在函数组件中使用;不能在条件、循环或者嵌套函数中使用hook。确保每一次渲染中都按照同样的顺序被调用,import React, {useState } from "react"; export default function PersonalInfoComponent() {const […...

基于深度神经网络的3D模型合成【Transformer vs. CNN】

本文介绍用于3D模型合成的transformer网络与深度卷积网络。 推荐&#xff1a;使用 NSDT场景设计器 快速搭建 3D场景。 1、概述 从单一视角合成 3D 数据是一种基本的人类视觉功能&#xff0c;这对计算机视觉算法来说极具挑战性&#xff0c;这是一个共识。 但在 3D 传感器&#…...

前端面试题整理之HMTL篇(一)

HTML面试题&#xff08;一&#xff09; 前言&#xff1a; 面试题及答案解析&#xff0c;大部分来自网络整理&#xff0c;我自己做了一些简化&#xff0c;如果想了解的更多&#xff0c;可以搜索一下&#xff0c;前端面试题宝典微信公众号或者查百度&#xff0c;另外如果出现错误…...

【论文速递】ICLR2018 - 用于小样本语义分割的条件网络

【论文速递】ICLR2018 - 用于小样本语义分割的条件网络 【论文原文】&#xff1a;CONDITIONAL NETWORKS FOR FEW-SHOT SEMANTIC SEGMENTATION&#xff08;Workshop track - ICLR 2018&#xff09; 【作者信息】&#xff1a;Kate Rakelly Evan Shelhamer Trevor Darrell Alexe…...

本地生成动漫风格 AI 绘画 图像|Stable Diffusion WebUI 的安装和局域网部署教程

Stable Diffusion WebUI 的安装和部署教程1. 简介2. 安装环境2.1 Windows2.2 Linux3. 运行4. 模型下载链接5. 局域网部署5.1 Windows5.2 Linux6. 其他资源1. 简介 先放一张WebUI的图片生成效果图&#xff0c;以给大家学习的动力 &#xff1a;&#xff09; 怎么样&#xff0c;…...

用一行Python代码,为图片上水印版权!

今天一个朋友跟我吐槽&#xff1a;前段时间&#xff0c;我辛辛苦苦整理的一份XX攻略&#xff0c;分享给自己的一些朋友&#xff0c;结果今天看到有人堂而皇之地拿着这份攻略图片去引流&#xff0c;并声称是自己整理的&#xff0c;真是岂有此理&#xff01;他自己总结吃一堑长一…...

java中的lambda表达式

java中的lambda表达式java中的lambda表达式语法参数的不同写法代码块的不同写法函数式接口运用方法引用object::instanceMethodClass::staticMethodClass::instanceMethod什么是lambda表达式&#xff1f; 带参数变量的表达式。 java中的lambda表达式 我对java中lambda表达式是这…...

0.1opencv库VS环境配置

opencv环境配置 感谢大家学习这门教程。本系列文章首发于公众号【周旋机器视觉】。 这个这门课程的第一篇文章&#xff0c;主要是opencv环境配置。 本教程的环境为 Visual Studio 2019CMake 3.22.3opencv 4.6.0windows 10 1、opencv的源码下载与安装 直接访问opencv官网&…...

第五十七章 树状数组(二)

第五十七章 树状数组&#xff08;二&#xff09;一、差分的缺陷二、树状数组与差分三、例题题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1提示样例 1 解释&#xff1a;数据规模与约定代码一、差分的缺陷 差分的作用是能够在O(1)的时间内给一段区间加上相同的数字&am…...

比特币的网络

比特币的网络 1. DNS-seed 在比特币网络中,初始节点发现一共有两种方式。 第一种叫做 DNS-seed,又称 DNS 种子节点,DNS 就是中心化域名查询服务,比特币的 社区维护者会维护一些域名。 比如 seed.bitcoin.sipa.be 这个域名就是由比特币的核心开发者 Sipa 维护的,如果我…...

ChatGPT的模型介绍及GO语言实现API

ChatGPT除了大家熟悉的GPT3之外&#xff0c;还有其他辅助模型&#xff0c;比如处理代码的以及有害信息过滤的系统。总的来说是下面三个组成&#xff1a;GPT-3&#xff1a;一组能够理解和生成自然语言的模型CodexLimited beta&#xff1a;一组可以理解和生成代码的模型&#xff…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建

【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...

用鸿蒙HarmonyOS5实现中国象棋小游戏的过程

下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...

数据结构:递归的种类(Types of Recursion)

目录 尾递归&#xff08;Tail Recursion&#xff09; 什么是 Loop&#xff08;循环&#xff09;&#xff1f; 复杂度分析 头递归&#xff08;Head Recursion&#xff09; 树形递归&#xff08;Tree Recursion&#xff09; 线性递归&#xff08;Linear Recursion&#xff09;…...

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...

数据挖掘是什么?数据挖掘技术有哪些?

目录 一、数据挖掘是什么 二、常见的数据挖掘技术 1. 关联规则挖掘 2. 分类算法 3. 聚类分析 4. 回归分析 三、数据挖掘的应用领域 1. 商业领域 2. 医疗领域 3. 金融领域 4. 其他领域 四、数据挖掘面临的挑战和未来趋势 1. 面临的挑战 2. 未来趋势 五、总结 数据…...

Android Framework预装traceroute执行文件到system/bin下

文章目录 Android SDK中寻找traceroute代码内置traceroute到SDK中traceroute参数说明-I 参数&#xff08;使用 ICMP Echo 请求&#xff09;-T 参数&#xff08;使用 TCP SYN 包&#xff09; 相关文章 Android SDK中寻找traceroute代码 设备使用的是Android 11&#xff0c;在/s…...

中国政务数据安全建设细化及市场需求分析

(基于新《政务数据共享条例》及相关法规) 一、引言 近年来,中国政府高度重视数字政府建设和数据要素市场化配置改革。《政务数据共享条例》(以下简称“《共享条例》”)的发布,与《中华人民共和国数据安全法》(以下简称“《数据安全法》”)、《中华人民共和国个人信息…...