Python学习笔记(四)之坦克大战
第一章 Python 基本概念
第二章 Python 序列 控制语句 函数
第三章 Python 面向编程 异常处理 文件处理
第四章 Python 坦克大战
第五章 Python 并发编程 网络通信
第六章 Python 函数式编程
第七章 Python Linux编程
文章目录
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、前期规划
1.pygame的介绍与环境搭建
在Vscode开发环境里进行对应模块安装和前期准备,主要是创建一个虚拟环境用来开发坦克大战游戏以及安装pyganme模块。
首先创建对应文件夹和py文件后,ctrl+~打开终端命令行创建虚拟环境,安装pygame2.3.0版本。
ps:创建成功后需选择对应虚拟环境重新打开命令行生效。
至此,pygame已安装成功。
2.创建窗口
import pygame
#初始函数,使用pygame的第一步;
pygame.init()
#生成主屏幕screen
pygame.display.set_mode((600,500))
#设置标题
pygame.display.set_caption('Hello Pygame')
while True: #游戏的主循环是一个无限循环,直到用户退出。在这个主循环里面做的事情就是不停的刷新新画面。
#刷新屏幕
pygame.display.update()
二、需求分析
本游戏主要分为两个对象,分别是我方坦克和敌方坦克。用户可以通过控制我方的坦克来摧毁敌方的坦克保护自己的“家”,把所有的敌方坦克消灭完达到胜利。敌方的坦克在初始的时候是默认5个的(这可以自己设置),当然,如果我方坦克被敌方坦克的子弹打中,游戏结束。
主要的需求分析为以下:
- 坦克类
我方坦克
敌方坦克
坦克的显示 移动 射击 - 子弹类
显示 移动 - 墙壁类
显示 - 爆炸效果类
显示 - 音效类
播放音效 - 游戏主窗口类
开始 结束
主窗口类,主要包括开始游戏、结束游戏的功能。
class MainGame:
'''
游戏主窗口类
'''
def __init__(self) -> None:
pass
def start_game(self) -> None:
'''
开始游戏
'''
pass
def end_game(self) -> None:
'''
结束游戏
'''
pass
坦克类:主要包括坦克的创建、显示、移动及射击的功能
class Tank():
def __init__(self):
pass
#坦克的移动方法
def move(self):
pass
#碰撞墙壁的方法
def hitWalls(self):
pass
#射击方法
def shot(self):
pass
#展示坦克
def displayTank(self):
pass
我方坦克类继承坦克类,主要包括创建、与敌方坦克的碰撞方法。
class MyTank(Tank):
def __init__(self):
pass
#碰撞敌方坦克的方法
def hitEnemyTank(self):
pass
敌方坦克类继承坦克类,主要包括创建、与我方坦克碰撞方法。
class EnemyTank(Tank):
'''
敌方坦克类
'''
def __init__(self) -> None:
pass
子弹类:主要包括子弹的创建、显示及移动的功能。
class Bullet:
'''
子弹类
'''
def __init__(self) -> None:
pass
def display_bullet(self) -> None:
'''
显示子弹
'''
pass
def move(self) -> None:
'''
子弹的移动
'''
pass
墙壁类:主要包括墙壁的创建、显示的功能。
class Wall:
'''
墙壁类
'''
def __init__(self) -> None:
pass
def display_wall(self) -> None:
'''
显示墙壁
'''
pass
爆炸效果类:主要展示爆炸效果。
class Explode:
'''
爆炸效果类
'''
def __init__(self) -> None:
pass
def display_explode(self) -> None:
'''
显示爆炸效果
'''
pass
音效类:主要播放音乐。
class Music:
'''
音效类
'''
def __init__(self) -> None:
pass
def play_music(self) -> None:
'''
播放音效
'''
pass
三、项目搭建
1.显示游戏窗口
主要改进点:
1.在全局将背景颜色以及窗口宽高设置通用属性,在后期方便进行修改
2.设置一个类属性windows是空对象在下面调用
import pygame
# 设置通用属性
BG_COLOR = pygame.Color(255,255,255)
SCREEN_WIDTH = 700
SCREEN_HEIGHT = 500
class MainGame:
'''
游戏主窗口类
'''
# 游戏主窗口对象,默认是空值
window =None
def __init__(self) -> None:
pass
def start_game(self) -> None:
'''
开始游戏
'''
# 初始化游戏窗口
pygame.display.init()
# 创建一个窗口
MainGame.window = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
# 设置窗口标题
pygame.display.set_caption('坦克大战1.0')
# 刷新窗口
while True:
# 给窗口设置填充色
MainGame.window.fill(BG_COLOR)
pygame.display.update()
def end_game(self) -> None:
'''
结束游戏
'''
pass
if __name__ == "__main__":
# 调用MainGame类中的start_game方法,开始游戏
MainGame().start_game()
实现效果:
2.添加提示文字
在主屏幕上需要添加对应的提示文字 需要创建对应的函数类def get_text_surface,主要是需要获取初始化字体模块以及可以使用的字体,将内容添加上去。
需要进行测试可以添加的字体:
在类中初始化字体并且在主窗口循环中进行打印:
while True:
# 给窗口设置填充色
MainGame.window.fill(BG_COLOR)
#增加提示文字 要增加的文字内容以及如何把文字加上
self.get_text_surface('info')
pygame.display.update()
def get_text_surface(self,text:str) -> None:
'''
获取文字的图片
'''
# 初始化字体模块
pygame.font.init()
# 获取可以使用的字体
print(pygame.font.get_fonts())
在终端进行循环打印自带的字体:
def get_text_surface(self,text:str) -> None:
'''
获取文字的图片
'''
# 初始化字体模块
pygame.font.init()
# 获取可以使用的字体
# print(pygame.font.get_fonts())
# 创建字体
font = pygame.font.SysFont('kaiti',18)
# 绘制文字信息
text_surface = font.render(text,True,TEXT_COLOR)
# 将绘制的文字信息返回
return text_surface
在开始游戏方法中调用添加提示文字方法
# 1.要增加文字内容
num = 6
text = self.get_text_surface(f'敌方坦克剩余数量{num}')
# 2.如何把文字加上
MainGame.window.blit(text,(10,10))
3.增加事件监听
事件监听用于在程序中监听特定的事件,以便在事件发生时能够执行相应的代码。事件可以是用户交互、系统消息等。
添加事件监听,控制上、下、左、右四个方向键,实现针对不同的键改变坦克的方向及移动功能,点击关闭退出游戏。
需要从文档中查看所支持的事件及说明:
https://www.pygame.org/docs/ref/event.html#pygame.event.get
增加判断关闭和键盘移动事件:
def get_event(self) -> None:
'''
获取事件
'''
# 获取所有事件
event_list = pygame.event.get()
# 遍历事件
for event in event_list:
# 判断是什么事件,然后做出相应的处理
if event.type == pygame.QUIT:
# 点击关闭按钮
self.end_game()
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('坦克向下移动')
def end_game(self) -> None:
'''
结束游戏
'''
print('谢谢使用,欢迎再次使用')
exit()
#主循环中增加
self.get_event()
4.加载我方坦克
需要考虑加载初始化坦克图片加入到主窗口中,以及按下上下左右坦克会朝向不同的方向,还有初始化的时候坦克需要处于的位置。
class Tank:
'''
坦克类
'''
def __init__(self,left:int,top:int) -> None:
# 设置我方坦克的图片资源
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'
# 获取图片信息
self.image = self.images.get(self.direction)
# 获取图片的矩形
self.rect = self.image.get_rect()
# 设置我方坦克位置
self.rect.left = left
self.rect.top = top
def display_tank(self) -> None:
'''
显示坦克
'''
MainGame.window.blit(self.image,self.rect)
#开始游戏方法,创建坦克,将坦克添加到窗口。
def start_game(self) -> None:
# 创建一个我方 坦克
my_tank = Tank(350,200)
# 刷新窗口
while True:
# 显示 我方坦克
my_tank.display_tank()
5.修改我方坦克朝向
触发按键事件来进行坦克方向转换,通过self.image = self.images.get(self.direction)把最新的值渲染出来
class Tank:
'''
坦克类
'''
def __init__(self,left:int,top:int) -> None:
# 设置我方坦克的方向
self.direction = 'L'
# 获取图片信息
self.image = self.images.get(self.direction)
def display_tank(self) -> None:
'''
显示坦克
'''
# 获取最新坦克的朝向位置图片
self.image = self.images.get(self.direction)
MainGame.window.blit(self.image,self.rect)
class MainGame:
#设置我方坦克
my_tank = None
def start_game(self) -> None:
# 创建一个我方 坦克
MainGame.my_tank = Tank(350,250)
# 显示 我方坦克
MainGame.my_tank.display_tank()
def get_event(self) -> None:
'''
获取事件
'''
# 获取所有事件
event_list = pygame.event.get()
# 遍历事件
for event in event_list:
# 判断是什么事件,然后做出相应的处理
if event.type == pygame.QUIT:
# 点击关闭按钮
self.end_game()
if event.type == pygame.KEYDOWN:
# 按下键盘
if event.key == pygame.K_LEFT:
print('坦克向左移动')
# 修改方向
MainGame.my_tank.direction = 'L'
# 通过坦克对象调用即可
MainGame.my_tank.move()
elif event.key == pygame.K_RIGHT:
print('坦克向右移动')
# 修改方向
MainGame.my_tank.direction = 'R'
MainGame.my_tank.move()
elif event.key == pygame.K_UP:
print('坦克向上移动')
# 修改方向
MainGame.my_tank.direction = 'U'
MainGame.my_tank.move()
elif event.key == pygame.K_DOWN:
# 修改方向
MainGame.my_tank.direction = 'D'
print('坦克向下移动')
MainGame.my_tank.move()
6.移动我方坦克
在移动类中用if语句判定:
def move(self):
'''
坦克的移动
'''
if self.direction =="L":
self.rect.left = self.rect.left - 5
elif self.direction =="R":
self.rect.left = self.rect.left + 5
elif self.direction =="U":
self.rect.left = self.rect.left - 5
elif self.direction =="D":
self.rect.left = self.rect.left + 5
但是在之后代码进行修改时 若需要修改对应每次的移动值较麻烦,可设置移动速度调用,并且判断坦克移动是否超出窗口,判断的临界点是窗口的宽度或者高度-坦克的宽度
class Tank:
'''
坦克类
'''
def __init__(self,left:int,top:int) -> None:
# 设置我方坦克位置
self.rect.left = left
self.rect.top = top
# 设置移动速度
self.speed = 10
def display_tank(self) -> None:
'''
显示坦克
'''
# 获取最新坦克的朝向位置图片
self.image = self.images.get(self.direction)
MainGame.window.blit(self.image,self.rect)
def move(self) -> None:
'''
坦克的移动
'''
if self.direction == "L":
# 判断坦克的位置是否已左边界
if self.rect.left > 0:
# 修改坦克的位置 离左边的距离 - 操作
self.rect.left = self.rect.left - self.speed
elif self.direction == "R":
# 判断坦克的位置是否已右边界
if self.rect.left + self.rect.width < SCREEN_WIDTH:
# 修改坦克的位置 离左边的距离 + 操作
self.rect.left = self.rect.left + self.speed
elif self.direction == "U":
# 判断坦克的位置是否已上边界
if self.rect.top > 0:
# 修改坦克的位置 离上边的距离 - 操作
self.rect.top = self.rect.top - self.speed
elif self.direction == "D":
# 判断坦克的位置是否已下边界
if self.rect.top + self.rect.height < SCREEN_HEIGHT:
# 修改坦克的位置 离上边的距离 + 操作
self.rect.top = self.rect.top + self.speed
但是上面方法中,按一下坦克移动一下,想按下键时候,坦克一直移动,弹起坦克停止移动。可以在坦克类中添加移动开关属性,按下上、下、左、右四个方向键修改坦克的方向及开关状态stop = False。松开方向键,更改移动开关状态stop = True。
主要需要增加移动开关,在事件里判断,如果为true就去移动
class Tank():
#设置移动开关,True 表示移动
self.remove = False
class MainGame:
while True:
sleep(0.02)
#移动坦克
if MainGame.my_tank.remove:
MainGame.my_tank.move()
def get_event(self) -> None:
'''
获取事件
'''
# 获取所有事件
event_list = pygame.event.get()
# 遍历事件
for event in event_list:
# 判断是什么事件,然后做出相应的处理
if event.type == pygame.QUIT:
# 点击关闭按钮
self.end_game()
if event.type == pygame.KEYDOWN:
# 按下键盘
if event.key == pygame.K_LEFT:
print('坦克向左移动')
# 修改方向
MainGame.my_tank.direction = 'L'
#修改坦克移动的状态为True
MainGame.my_tank.remove = True
elif event.key == pygame.K_RIGHT:
print('坦克向右移动')
# 修改方向
MainGame.my_tank.direction = 'R'
MainGame.my_tank.remove = True
elif event.key == pygame.K_UP:
print('坦克向上移动')
# 修改方向
MainGame.my_tank.direction = 'U'
MainGame.my_tank.remove = True
elif event.key == pygame.K_DOWN:
print('坦克向下移动')
# 修改方向
MainGame.my_tank.direction = 'D'
MainGame.my_tank.remove = True
if event.type == pygame.KEYUP and event.key in (pygame.K_LEFT,pygame.K_RIGHT , pygame.K_UP , pygame.K_DOWN):
# 修改坦克的移动状态
MainGame.my_tank.remove = False
在这里插入代码片
7.加载敌方坦克
主要需要渲染敌方坦克图片和位置 随机生成敌方坦克的数量和方向,注意点是随机生成敌方坦克的数量及方向
class EnemyTank(Tank):
'''
敌方坦克类
'''
def __init__(self,left,top,speed):
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.rand_direction()
self.image = self.images.get(self.direction)
# 坦克所在的区域 Rect->
self.rect = self.image.get_rect()
# 指定坦克初始化位置 分别距x,y轴的位置
self.rect.left = left
self.rect.top = top
# 新增速度属性
self.speed = speed #方便调整 若增加游戏难度 速度则加快;
def rand_direction(self) ->str:
'''
生成随机方向
'''
chice = random.randint(1,4)
if chice == 1:
return 'U'
elif chice == 2:
return 'D'
elif chice == 3:
return 'L'
elif chice == 4:
return 'R'
class MainGame:
#存储敌方坦克列表
enemy_tank_list = []
#设置敌方坦克数量
enemy_tank_count = 6
def start_game(self) -> None:
# 创建一个敌方坦克
self.create_enemy_tank()
# 刷新窗口
while True:
# 显示敌方坦克
self.display_enemy_tank()
def create_enemy_tank(self):
'''
创建敌方坦克
'''
self.enemy_top = 100
self.enemy_speed = 10
for i in range(self.enemy_tank_count):
#生成坦克的位置
left = random.randint(0,600)
#speed = random.randint(1,15)
#创建敌方坦克
e_tank = EnemyTank(left,self.enemy_top,self.enemy_speed)
#将敌方坦克增加至列表
self.enemy_tank_list.append(e_tank)
def display_enemy_tank(self) ->None:
#显示坦克
for e_tank in self.enemy_tank_list:
e_tank.display_tank()
8.敌方坦克随机移动
设置敌方坦克可以随机移动并显示,主要逻辑为在EnemyTank类中定义函数rand_move判断敌方坦克移动步长,根据大小来变换方向在主窗口来显示。
class EnemyTank(Tank):
'''
敌方坦克类
'''
def rand_move(self):
'''
随机移动
'''
# 判断步长是否为0
if self.step <= 0:
# 如果小于0,更换方向
self.direction = self.rand_direction()
# 重置步长
self.step = 20
else:
# 如果大于0,移动
self.move()
self.step -=1
class MainGame:
def display_enemy_tank(self) ->None:
#显示坦克
for e_tank in self.enemy_tank_list:
# 显示敌方坦克
e_tank.display_tank()
# 移动敌方坦克
e_tank.rand_move()
9.完善子弹类
需要判断清楚子弹的位置
'''
子弹类
'''
def __init__(self,tank) -> None:
# 加载图片
self.image = pygame.image.load('./img/enemymissile.gif')
# 获取子弹的方向
self.direction = tank.direction
# 获取子弹的图形
self.rect = self.image.get_rect()
# 设置子弹的位置
if self.direction == "L":
# 子弹的位置 = 坦克的位置 - 子弹的宽度
self.rect.left = tank.rect.left - self.rect.width
# 子弹的位置 = 坦克的位置 + 坦克的高度/2 - 子弹的高度/2
self.rect.top = tank.rect.top + tank.rect.height/2 - self.rect.height/2
elif self.direction == "R":
# 子弹的位置 = 坦克的位置 + 坦克的宽度
self.rect.left = tank.rect.left + tank.rect.width
# 子弹的位置 = 坦克的位置 + 坦克的高度/2 - 子弹的高度/2
self.rect.top = tank.rect.top + tank.rect.height/2 - self.rect.height/2
elif self.direction == "U":
# 子弹的位置 = 坦克的位置 + 坦克的宽度/2 - 子弹的宽度/2
self.rect.left = tank.rect.left + tank.rect.width/2 - self.rect.width/2
# 子弹的位置 = 坦克的位置 - 子弹的高度
self.rect.top = tank.rect.top - self.rect.height
elif self.direction == "D":
# 子弹的位置 = 坦克的位置 + 坦克的宽度/2 - 子弹的宽度/2
self.rect.left = tank.rect.left + tank.rect.width/2 - self.rect.width/2
# 子弹的位置 = 坦克的位置 + 坦克的高度
self.rect.top = tank.rect.top + tank.rect.height
# 设置子弹的速度
self.speed = 10
10.我方坦克发射子弹
主要是在子弹类中调用显示
def display_bullet(self) -> None:
'''
显示子弹
'''
MainGame.window.blit(self.image,self.rect)
class MainGame:
#存储我方子弹
my_bullet_list = []
while True:
# 显示我方子弹
self.display_my_bullet()
pygame.display.update()
def display_my_bullet(self) ->None:
'''
显示我方子弹
'''
for my_bullet in MainGame.my_bullet_list:
#显示我方子弹
my_bullet.display_bullet()
def get_event(self) -> None:
for event in event_list:
elif event.key == pygame.K_SPACE:
#发射子弹
print("发射子弹")
# 创建子弹
m_bullet = Bullet(MainGame.my_tank)
# 将子弹添加到列表中
MainGame.my_bullet_list.append(m_bullet)
11.我方子弹移动
修改子弹类
#子弹的移动方法
def move(self) -> None:
'''
子弹的移动
'''
# 根据子弹生成的方向来的移动
if self.direction == "L":
# 判断子弹是否超出屏幕
if self.rect.left > 0:
self.rect.left -= self.speed
elif self.direction == "R":
# 判断子弹是否超出屏幕
if self.rect.left + self.rect.width < SCREEN_WIDTH:
self.rect.left += self.speed
elif self.direction == "U":
# 判断子弹是否超出屏幕
if self.rect.top > 0:
self.rect.top -= self.speed
elif self.direction == "D":
# 判断子弹是否超出屏幕
if self.rect.top + self.rect.height < SCREEN_HEIGHT:
self.rect.top += self.speed
修改MainGame类,显示子弹方法
def display_my_bullet(self) -> None:
'''
显示我方子弹
'''
for my_bullet in MainGame.my_bullet_list:
# 显示我方子弹
my_bullet.display_bullet()
# 移动我方子弹
my_bullet.move()
12.子弹的消亡与数量控制
设置一个 self.live = True来进行判断和控制数量
class Bullet:
'''
子弹类
'''
def __init__(self,tank) -> None:
# 设置子弹的状态
self.live = True
def move(self) -> None:
'''
子弹的移动
'''
# 根据子弹生成的方向来的移动
if self.direction == "L":
# 判断子弹是否超出屏幕
if self.rect.left > 0:
self.rect.left -= self.speed
else:
self.live = False
def display_my_bullet(self) -> None:
'''
显示我方子弹
'''
for my_bullet in MainGame.my_bullet_list:
# 判断子弹是否存活
if my_bullet.live:
# 显示我方子弹
my_bullet.display_bullet()
# 移动我方子弹
my_bullet.move()
else:
# 从列表中移除
MainGame.my_bullet_list.remove(my_bullet)
def get_event(self) -> None:
'''
获取事件
'''
# 获取所有事件
event_list = pygame.event.get()
# 遍历事件
for event in event_list:
elif event.key == pygame.K_SPACE:
# 判断子弹是否上限
if len(MainGame.my_bullet_list) < 5:
# 发射子弹
print('发射子弹')
# 创建子弹
m_bullet = Bullet(MainGame.my_tank)
# 将子弹添加到列表中
MainGame.my_bullet_list.append(m_bullet)
13.敌方坦克发射子弹
实现发射子弹方法
def shot(self):
'''
敌方坦克的射击
'''
num = random.randint(1,100)
if num < 5:
return Bullet(self)
敌方坦克加入窗口后,发射子弹,并将子弹添加到敌方子弹列表中
#将敌方坦克加入到窗口中
def display_enemy_tank(self) -> None:
for e_tank in self.enemy_tank_list:
# 判断是否有子弹
if e_bullet:
# 将子弹增加到列表中
MainGame.enemy_bullet_list.append(e_bullet)
将敌方发射的子弹添加到窗口
def display_my_bullet(self) ->None:
'''
显示我方子弹
'''
for my_bullet in MainGame.my_bullet_list:
# 判断子弹是否存活
if my_bullet.live:
# 显示我方子弹
my_bullet.display_bullet()
# 移动我方子弹
my_bullet.move()
else:
# 从列表中移除
MainGame.my_bullet_list.remove(my_bullet)
def display_enemy_bullet(self) -> None:
'''
显示敌方子弹
'''
for e_bullet in MainGame.enemy_bullet_list:
#判断子弹是否存活
if e_bullet.live:
#显示子弹
e_bullet.display_bullet()
e_bullet.move()
else:
#如果子弹不存活,从列表中移除
MainGame.enemy_bullet_list.remove(e_bullet)
14.我方子弹与敌方坦克的碰撞检测
在游戏开发中,通常把显示图像的对象叫做精灵Spire,精灵需要有两个属性,image要显示的图像,rect图像要显示在屏幕的位置。在Pygame框架中,使用pygame. sprite模块中的内置函数可以实现碰撞检测。
在子弹类中增加我方子弹碰撞敌方坦克的方法,如果发生碰撞,修改我方子弹及敌方坦克live属性的状态值。
def hit_enemy_tank(self):
for e_tank in MainGame.enemy_tank_list:
# 判断子弹是否击中坦克
if collide_rect(self,e_tank):
# 修改子弹的状态
self.live = False
e_tank.live = False
修改坦克类,增加是否存活状态
class Tank:
'''
坦克类
'''
def __init__(self) -> None:
self.live = True
在我方子弹移动后判断子弹是否与敌方坦克碰撞。
def display_my_bullet(self) -> None:
'''
显示我方子弹
'''
for my_bullet in MainGame.my_bullet_list:
# 判断子弹是否存活
if my_bullet.live:
# 判断我方子弹是否击中敌方坦克
my_bullet.hit_enemy_tank()
else:
# 从列表中移除
MainGame.my_bullet_list.remove(my_bullet)
修改MainGame类敌方坦克显示逻辑,根据敌方坦克是否存活
def display_enemy_tank(self) -> None:
for e_tank in self.enemy_tank_list:
# 判断敌方坦克是否存活
if e_tank.live:
# 判断是否有子弹
if e_bullet:
# 将子弹增加到列表中
MainGame.enemy_bullet_list.append(e_bullet)
else:
# 从列表中移除
self.enemy_tank_list.remove(e_tank)
15.爆炸效果
初始化爆炸类,和坦克一样加载图片渲染
def __init__(self,tank:Tank) -> None:
# 加载爆炸效果的图片
self.images = [
pygame.image.load('./img/blast0.gif'),
pygame.image.load('./img/blast1.gif'),
pygame.image.load('./img/blast2.gif'),
pygame.image.load('./img/blast3.gif'),
pygame.image.load('./img/blast4.gif'),
]
# 设置爆炸效果的位置
self.rect = tank.rect
# 设置爆炸效果的索引
self.step = 0
# 获取需要渲染的图像
self.image = self.images[self.step]
# 设置爆炸的状态
self.live = True
展示爆炸效果。
def display_explode(self) -> None:
'''
显示爆炸效果
'''
# 判断当前爆照的效果是否播放完毕
if self.step < len(self.images):
# 获取当前爆炸效果的图像
self.image = self.images[self.step]
# 获取下一张爆炸效果的图像的索引
self.step += 1
# 绘制爆炸效果
MainGame.window.blit(self.image,self.rect)
else:
# 初始化爆炸效果的索引
self.step = 0
# 设置爆炸效果的状态,代表爆炸过了
self.live = False
在我方子弹碰撞敌方坦克的方法中,如果检测到碰撞,产生爆炸类,并将爆炸效果添加到爆炸列表。
def hit_enemy_tank(self):
for e_tank in MainGame.enemy_tank_list:
# 判断子弹是否击中坦克
if collide_rect(self,e_tank):
# 爆炸效果
explode = Explode(e_tank)
MainGame.explode_list.append(explode)
# 修改子弹的状态
self.live = False
e_tank.live = False
将爆炸效果添加到窗口。
#新增方法: 展示爆炸效果列表
def display_explode(self) -> None:
'''
显示爆炸效果
'''
for explode in MainGame.explode_list:
# 判断是否活着
if explode.live:
# 显示爆炸效果
explode.display_explode()
else:
# 从列表中移除
MainGame.explode_list.remove(explode)
16.敌方子弹与我方坦克碰撞检测
子弹类中,新增敌方子弹与我方坦克的碰撞。如果发生碰撞,修改敌方子弹、我方坦克的状态及产生爆炸效果。
#新增敌方子弹与我方坦克的碰撞方法
def hit_my_tank(self):
# 判断我方坦克是否活着
if MainGame.my_tank and MainGame.my_tank.live:
# 判断字段是否击中我方坦克
if collide_rect(self,MainGame.my_tank):
# 爆炸效果
explode = Explode(MainGame.my_tank)
MainGame.explode_list.append(explode)
# 修改子弹的状态
self.live = False
MainGame.my_tank.live = False
添加敌方子弹到窗口中时候,如果子弹还活着,显示子弹、调用子弹移动并判断敌方子弹是否与我方坦克发生碰撞。
#将敌方子弹加入到窗口中
def display_my_bullet(self) -> None:
'''
显示我方子弹
'''
for my_bullet in MainGame.my_bullet_list:
# 判断子弹是否存活
if my_bullet.live:
# 显示我方子弹
my_bullet.display_bullet()
# 移动我方子弹
my_bullet.move()
# 判断我方子弹是否击中敌方坦克
my_bullet.hit_enemy_tank()
else:
# 从列表中移除
MainGame.my_bullet_list.remove(my_bullet)
以及在主窗口进行判定我方是否存活:
def get_event(self) -> None:
'''
获取事件
'''
# 获取所有事件
event_list = pygame.event.get()
# 遍历事件
for event in event_list:
# 判断是什么事件,然后做出相应的处理
if event.type == pygame.QUIT:
# 点击关闭按钮
self.end_game()
if event.type == pygame.KEYDOWN:
if MainGame.my_tank and MainGame.my_tank.live :
# 按下键盘
if event.key == pygame.K_LEFT:
print('坦克向左移动')
if event.type == pygame.KEYUP and event.key in (pygame.K_LEFT,pygame.K_RIGHT , pygame.K_UP , pygame.K_DOWN):
if MainGame.my_tank and MainGame.my_tank.live :
# 修改坦克的移动状态
MainGame.my_tank.remove = False
while True:
#判断我方坦克是否死亡
if MainGame.my_tank and MainGame.my_tank.live:
# 显示我方坦克
MainGame.my_tank.display_tank()
else:
MainGame.my_tank = None
if MainGame.my_tank and MainGame.my_tank.live :
#移动坦克
if MainGame.my_tank.remove:
MainGame.my_tank.move()
17.我方坦克无线重生
坦克大战游戏中一般我方坦克有重生的功能,当按下键盘的Esc键时候,让我方坦克重生。重生指的就是重新创建我方坦克。
def create_my_tank(self) -> None:
'''
创建我方坦克
'''
MainGame.my_tank = MyTank(350,200)
#获取事件
def getEvent(self):
#获取所有事件
eventList= pygame.event.get()
#遍历事件
for event in event_list:
if event.type == pygame.KEYDOWN:
# 如果我方坦克死亡,按下esc键,重新生成我方坦克
if not MainGame.my_tank and event.key == pygame.K_ESCAPE:
print('重新生成我方坦克')
# 按下esc键,重新生成我方坦克
self.create_my_tank()
18.加载墙壁
初始化墙壁类
class Wall:
'''
墙壁类
'''
def __init__(self,left,top) -> None:
# 加载图片
self.image = pygame.image.load('./img/steels.gif')
# 获取墙壁的图形
self.rect = self.image.get_rect()
# 设置墙壁的位置
self.rect.left = left
self.rect.top = top
def display_wall(self) -> None:
'''
显示墙壁
'''
MainGame.window.blit(self.image,self.rect)
创建墙壁
def create_wall(self) -> None:
'''
创建墙壁
'''
top = 200
for i in range(6):
# 创建墙壁
wall = Wall(i*128,top)
# 添加到墙壁列表中
MainGame.wall_list.append(wall)
墙壁加入到窗口
#存储墙壁的列表
wall_list = []
# 创建墙壁
self.create_wall()
#显示墙壁
self.display_wall()
def display_wall(self) -> None:
'''
显示墙壁
'''
for wall in MainGame.wall_list:
# 显示墙壁
wall.display_wall()
19.子弹不能穿墙
子弹不能穿墙指子弹碰到墙壁后消失。因此,子弹类中新增方法,子弹与墙壁的碰撞,如果子弹与墙壁碰撞,修改子弹的状态。另外还需要将墙壁的生命值减少,如果墙壁的生命值小于等于零时候修改墙壁的状态。
#新增子弹与墙壁的碰撞
def hit_wall(self):
'''
碰撞墙壁
'''
for wall in MainGame.wall_list:
# 判断是否碰撞
if collide_rect(self,wall):
# 修改子弹的状态
self.live = False
设置我方与敌方坦克子弹移动时,增加碰撞检测
def display_enemy_bullet(self) -> None:
for e_bullet in MainGame.enemy_bullet_list:
if e_bullet.live:
# 判断是否击中墙壁
e_bullet.hit_wall()
def display_my_bullet(self) -> None:
for my_bullet in MainGame.my_bullet_list:
if my_bullet.live:
# 判断我方子弹是否击中墙壁
my_bullet.hit_wall()
20.设置子弹耐久值
设置墙壁生命值与存活状态
class Wall:
# 设置墙壁的生命值
self.hp = 3
# 设置墙壁的状态
self.live = True
修改子弹碰撞墙壁逻辑
def hit_wall(self):
for wall in MainGame.wall_list:
# 修改墙壁的生命值
wall.hp -= 1
# 判断墙壁是否依然显示
if wall.hp <= 0:
wall.live = False
修改显示墙壁逻辑
def display_wall(self) -> None:
'''
显示墙壁
'''
for wall in MainGame.wall_list:
if wall.live:
# 显示墙壁
wall.display_wall()
else:
# 从列表中移除
MainGame.wall_list.remove(wall)
21.坦克不能穿墙
坦克不能穿墙指坦克一旦碰到墙壁则不能再移动,也就是需要修改坦克的坐标为移动之前的。因此在坦克类中新增属性oldLeft、oldTop记录移动之前的坐标,新增stay()、hitWalls()方法。
# 记录坦克原来的位置
self.old_left = 0
self.old_top = 0
def move(self) -> None:
# 记录坦克原来的位置,为了方便还原碰撞后的位置
self.old_left = self.rect.left
self.old_top = self.rect.top
def tank_hit_wall(self) -> None:
for wall in MainGame.wall_list:
# 检测当前坦克是否能和墙壁发生碰撞
if pygame.sprite.collide_rect(self,wall):
# 将位置还原到碰撞前的位置
self.rect.left = self.old_left
self.rect.top = self.old_top
坦克移动时,检测是否碰撞
def display_enemy_tank(self) -> None:
for e_tank in self.enemy_tank_list:
if e_tank.live:
# 判断是否与墙壁发生碰撞
e_tank.tank_hit_wall()
# 判断我方坦克是否死亡
if MainGame.my_tank and MainGame.my_tank.live:
# 移动坦克
if MainGame.my_tank.remove:
MainGame.my_tank.move()
# 检测我方坦克是否与墙壁发生碰撞
MainGame.my_tank.tank_hit_wall()
22.双方坦克之间的碰撞检测
如果我方坦克碰撞到敌方坦克,则我方坦克再不能继续移动。同理如果敌方坦克碰撞到我方坦克也不能继续移动。
在坦克类中新增坦克与坦克碰撞的检测方法
def tank_collide_tank(self,tank):
'''
检测2个坦克是否碰撞
'''
# 记录坦克原来的位置,为了方便还原碰撞后的位置
self.old_left = self.rect.left
self.old_top = self.rect.top
# 判断是否都存活
if self.live and tank.live:
if pygame.sprite.collide_rect(self,tank):
# 将位置还原到碰撞前的位置
self.rect.left = self.old_left
self.rect.top = self.old_top
def display_enemy_tank(self) ->None:
for e_tank in self.enemy_tank_list:
if e_tank.live:
#判断是否和我方坦克碰撞
e_tank.tank_collide_tank(MainGame.my_tank)
总结
111