坦克大战(python)
1、Pygame模块

2、创建窗口
import pygame
#初始化pygame
pygame.init()
#创建一个窗口
pygame.display.set_mode((800,600))
#设置窗口标题
pygame.display.set_caption("坦克大战1.0")
while True:
#刷新显示窗口
pygame.display.update()
3、需求分析
1.坦克类
1.1我方坦克类
1.2敌方坦克类
坦克的显示
坦克的移动
坦克的射击
2.子弹类
显示子弹
子弹的移动
3.墙壁类
显示墙壁
4.爆炸效果类
显示爆炸效果
5.音效类
播放音效
6.游戏主窗口类
开始游戏
结束游戏
4、基本结构的编写
本游戏主要分为两个对象,分别是我方坦克和敌方坦克。用户可以通过控制我方的坦克来摧毁敌方的坦克保护自己的“家”,把所有的敌方坦克消灭完达到胜利。敌方的坦克在初始的时候是默认5个的(这可以自己设置),当然,如果我方坦克被敌方坦克的子弹打中,游戏结束。从面向对象分析该项目有以下类组成:
坦克类
class Tank():
def __init__(self) -> None:
pass
def display_tank(self) -> None:
"""
显示坦克
"""
pass
def move(self) -> None:
"""
移动坦克
"""
pass
def shot(self) -> None:
"""
坦克的射击
"""
pass
class Mytank(Tank):
"""
我方坦克类
"""
def __init__(self) -> None:
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 diaplay_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(self) -> None:
"""
播放音效
"""
pass
游戏主窗口类
class Main():
"""
游戏主窗口类
"""
def __init__(self) -> None:
pass
def start_Game(self) -> None:
"""
开始游戏
"""
pass
def end_Game(self) -> None:
"""
结束游戏
"""
pass
5、显示游戏窗口
在游戏设计的前期,要先创建游戏的界面,也就是要为所设计的游戏创建一个窗口
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()
6、添加提示文字
import pygame
#设置通用属性
GB_COLOR = pygame.Color(0,0,0)
SCREEN_WIDTH = 700
SCREEN_HEIGHT = 500
TEXT_COLOR = pygame.Color(255,0,0)
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(GB_COLOR)
#增加提示文字
#1.要增加文字内容
num = 6
text = self.get_text_surface(f'敌方坦克剩余数量{num}')
#2.如何吧文字加上
MainGame.window.blit(text,(10,10))
pygame.display.update()
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
7、增加事件监听
事件监听用于在程序中监听特定的事件,以便在事件发生时能够执行相应的代码。事件可以是用户交互、系统消息等。
添加事件监听,控制上、下、左、右四个方向键,实现针对不同的键改变坦克的方向及移动功能,点击关闭退出游戏。
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()
8、加载我方坦克
通过加载图片来表示游戏中的坦克,此坦克代表我方坦克,完善坦克类。
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:
'''
开始游戏
'''
# 初始化游戏窗口
pygame.display.init()
# 创建一个窗口
MainGame.window = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
# 设置窗口标题
pygame.display.set_caption('坦克大战1.0')
# 创建一个我方 坦克
my_tank = Tank(350,200)
# 刷新窗口
while True:
# 给窗口设置填充色
MainGame.window.fill(BG_COLOR)
# 增加提示文字
# 1.要增加文字内容
num = 6
text = self.get_text_surface(f'敌方坦克剩余数量{num}')
# 2.如何把文字加上
MainGame.window.blit(text,(10,10))
# 增加事件
self.get_event()
# 显示 我方坦克
my_tank.display_tank()
pygame.display.update()
9、修改我方坦克朝向
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:
'''
显示坦克
'''
# 获取最新坦克的朝向位置图片
self.image = self.images.get(self.direction)
MainGame.window.blit(self.image,self.rect)
class MainGame:
'''
游戏主窗口类
'''
# 游戏主窗口对象
window =None
# 设置我放坦克
my_tank = 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')
# 创建一个我方 坦克
MainGame.my_tank = Tank(350,200)
# 刷新窗口
while True:
# 给窗口设置填充色
MainGame.window.fill(BG_COLOR)
# 增加提示文字
# 1.要增加文字内容
num = 6
text = self.get_text_surface(f'敌方坦克剩余数量{num}')
# 2.如何把文字加上
MainGame.window.blit(text,(10,10))
# 增加事件
self.get_event()
# 显示 我方坦克
MainGame.my_tank.display_tank()
pygame.display.update()
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
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()
10、移动我方坦克
坦克类中添加速度属性,实现我方坦克移动。
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
# 设置移动速度
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。
#获取程序期间所有事件(鼠标事件,键盘事件)
def getEvent(self):
#1.获取所有事件
eventList = pygame.event.get()
#2.对事件进行判断处理(1、点击关闭按钮 2、按下键盘上的某个按键)
for event in eventList:
#判断event.type 是否QUIT,如果是退出的话,直接调用程序结束方法
if event.type == pygame.QUIT:
self.endGame()
#判断事件类型是否为按键按下,如果是,继续判断按键是哪一个按键,来进行对应的处理
if event.type == pygame.KEYDOWN:
#具体是哪一个按键的处理
if event.key == pygame.K_LEFT:
print("坦克向左调头,移动")
#修改坦克方向
MainGame.TANK_P1.direction = 'L'
MainGame.TANK_P1.stop = False
elif event.key == pygame.K_RIGHT:
print("坦克向右调头,移动")
# 修改坦克方向
MainGame.TANK_P1.direction = 'R'
MainGame.TANK_P1.stop = False
elif event.key == pygame.K_UP:
print("坦克向上调头,移动")
# 修改坦克方向
MainGame.TANK_P1.direction = 'U'
MainGame.TANK_P1.stop = False
elif event.key == pygame.K_DOWN:
print("坦克向下掉头,移动")
# 修改坦克方向
MainGame.TANK_P1.direction = 'D'
MainGame.TANK_P1.stop = False
elif event.key == pygame.K_SPACE:
print("发射子弹")
#结束游戏方法
if event.type == pygame.KEYUP:
#松开的如果是方向键,才更改移动开关状态
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_UP or event.key == pygame.K_DOWN:
# 修改坦克的移动状态
MainGame.TANK_P1.stop = True
11、移动我方坦克类的优化
一直按一个方向的键盘可以一直移动
class MainGame:
"""
游戏主窗口类
"""
#游戏主窗口对象
window = None
#设置我方坦克
my_tank = 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")
#创建我方坦克
MainGame.my_tank = Tank(350,200)
#
# 刷新游戏窗口
while True:
sleep(0.02)
#给窗口设置填充色
MainGame.window.fill(GB_COLOR)
#增加提示文字
#1.要增加文字内容
num = 6
text = self.get_text_surface(f'敌方坦克剩余数量{num}')
#2.如何把文字加上
MainGame.window.blit(text,(10,10))
#增加事件
self.get_event()
#显示我方坦克
MainGame.my_tank.display_tank()
#移动我方坦克
if MainGame.my_tank.remove:
MainGame.my_tank.move()
pygame.display.update()
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
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"
#修改坦克移动的状态为True
MainGame.my_tank.remove = True
elif event.key == pygame.K_UP:
print("坦克向上移动")
#修改方向
MainGame.my_tank.direction = "U"
#修改坦克移动的状态为True
MainGame.my_tank.remove = True
elif event.key == pygame.K_DOWN:
print("坦克向下移动")
#修改方向
MainGame.my_tank.direction = "D"
#修改坦克移动的状态为True
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
def end_game(self) -> None:
"""
结束游戏
"""
print("谢谢使用,欢迎再次使用")
exit()
12、加载敌方坦克
初始化敌方坦克。
class EnemyTank(Tank):
"""
敌方坦克类
"""
def __init__(self,left,top,speed) -> None:
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)
#获取图片的矩形信息
self.rect = self.image.get_rect()
#设置敌方坦克位置
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"
创建敌方坦克
def create_enemy_tank(self) -> None:
"""
创建敌方坦克
"""
self.enemy_top = 100
self.enemy_speed = 10
for i in range(self.enemy_tanks_count):
#创建敌方坦克
left = random.randint(0,600)
#生成敌方坦克的位置
e_tank = EnemyTank(left,self.enemy_top,self.enemy_speed)
#将敌方坦克添加到列表中
self.enemy_tanks_list.append(e_tank)
显示敌方坦克
def display_enemy_tank(self) -> None:
"""
显示敌方坦克
"""
for e_tank in self.enemy_tanks_list:
e_tank.display_tank()
13、坦克类的优化
class Tank:
'''
坦克类
'''
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
def shot(self) -> None:
'''
坦克的射击
'''
pass
class MyTank(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
# 设置移动速度
self.speed = 10
# 设置移动开关, False 表示不移动, True 表示移动
self.remove = False
class MainGame:
'''
游戏主窗口类
'''
# 游戏主窗口对象
window =None
# 设置我放坦克
my_tank = None
# 存储敌方坦克的列表
enemy_tank_list = []
# 设置敌方坦克的数量
enemy_tank_count = 6
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')
# 创建一个我方 坦克
MainGame.my_tank = MyTank(350,200)
# 创建敌方坦克
self.create_enemy_tank()
# 刷新窗口
while True:
sleep(0.02)
# 给窗口设置填充色
MainGame.window.fill(BG_COLOR)
# 增加提示文字
# 1.要增加文字内容
# num = 6
text = self.get_text_surface(f'敌方坦克剩余数量{MainGame.enemy_tank_count}')
# 2.如何把文字加上
MainGame.window.blit(text,(10,10))
# 增加事件
self.get_event()
# 显示 我方坦克
MainGame.my_tank.display_tank()
# 显示敌方坦克
self.display_enemy_tank()
# 移动坦克
if MainGame.my_tank.remove:
MainGame.my_tank.move()
pygame.display.update()
14、敌方坦克随机移动
def rand_move(self):
'''
随机移动
'''
# 判断步长是否为0
if self.step <= 0:
# 如果小于0,更换方向
self.direction = self.rand_direction()
# 重置步长
self.step = 20
else:
# 如果大于0,移动
self.move()
# 步长减1
self.step -=1
将敌方坦克加到窗口中
def display_enemy_tank(self) -> None:
'''
显示敌方坦克
'''
for e_tank in self.enemy_tank_list:
# 显示敌方坦克
e_tank.display_tank()
# 移动敌方坦克
e_tank.rand_move()
在开始游戏方法,加载敌方坦克
#循环展示敌方坦克
self.display_enemy_tank()
15、完善子弹类
子弹位置的计算方式:

初始化子弹
'''
子弹类
'''
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
16、我方坦克发射子弹
添加显示子弹
class Bullet:
'''
子弹类
'''
def display_bullet(self) -> None:
'''
显示子弹
'''
MainGame.window.blit(self.image,self.rect)
按空格键产生子弹,并将子弹添加到子弹列表中
class MainGame:
'''
游戏主窗口类
'''
# 游戏主窗口对象
window =None
# 设置我放坦克
my_tank = None
# 存储敌方坦克的列表
enemy_tank_list = []
# 设置敌方坦克的数量
enemy_tank_count = 6
# 存储我方子弹的列表
my_bullet_list = []
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.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:
# 修改方向
MainGame.my_tank.direction = 'D'
print('坦克向下移动')
# 修改坦克移动的状态
MainGame.my_tank.remove = True
elif event.key == pygame.K_SPACE:
# 发射子弹
print('发射子弹')
# 创建子弹
m_bullet = Bullet(MainGame.my_tank)
# 将子弹添加到列表中
MainGame.my_bullet_list.append(m_bullet)
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
将子弹添加到窗口
def start_game(self) -> None:
'''
开始游戏
'''
# 初始化游戏窗口
pygame.display.init()
# 创建一个窗口
MainGame.window = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
# 设置窗口标题
pygame.display.set_caption('坦克大战1.0')
# 创建一个我方 坦克
MainGame.my_tank = MyTank(350,200)
# 创建敌方坦克
self.create_enemy_tank()
# 刷新窗口
while True:
sleep(0.02)
# 给窗口设置填充色
MainGame.window.fill(BG_COLOR)
# 增加提示文字
# 1.要增加文字内容
# num = 6
text = self.get_text_surface(f'敌方坦克剩余数量{MainGame.enemy_tank_count}')
# 2.如何把文字加上
MainGame.window.blit(text,(10,10))
# 增加事件
self.get_event()
# 显示 我方坦克
MainGame.my_tank.display_tank()
# 显示敌方坦克
self.display_enemy_tank()
# 移动坦克
if MainGame.my_tank.remove:
MainGame.my_tank.move()
# 显示我方子弹
self.display_my_bullet()
pygame.display.update()
17、我方子弹移动
修改子弹类
#子弹的移动方法
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()
18、子弹的消亡与数量控制
修改子弹类,创建live属性,与根据移动位置修改live状态
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
elif self.direction == "R":
# 判断子弹是否超出屏幕
if self.rect.left + self.rect.width < SCREEN_WIDTH:
self.rect.left += self.speed
else:
self.live = False
elif self.direction == "U":
# 判断子弹是否超出屏幕
if self.rect.top > 0:
self.rect.top -= self.speed
else:
self.live = False
elif self.direction == "D":
# 判断子弹是否超出屏幕
if self.rect.top + self.rect.height < SCREEN_HEIGHT:
self.rect.top += self.speed
else:
self.live = False
修改MainGame类,修改显示子弹类,与事件监听
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:
# 判断是什么事件,然后做出相应的处理
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.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:
# 修改方向
MainGame.my_tank.direction = 'D'
print('坦克向下移动')
# 修改坦克移动的状态
MainGame.my_tank.remove = True
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)
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
19、敌方坦克发射子弹
实现发射子弹方法
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:
# 显示敌方坦克
e_tank.display_tank()
# 移动敌方坦克
e_tank.rand_move()
# 发射子弹
e_bullet = e_tank.shot()
# 判断是否有子弹
if e_bullet:
# 将子弹增加到列表中
MainGame.enemy_bullet_list.append(e_bullet)
将敌方发射的子弹添加到窗口
def start_game(self) -> None:
'''
开始游戏
'''
# 初始化游戏窗口
pygame.display.init()
# 创建一个窗口
MainGame.window = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
# 设置窗口标题
pygame.display.set_caption('坦克大战1.0')
# 创建一个我方 坦克
MainGame.my_tank = MyTank(350,200)
# 创建敌方坦克
self.create_enemy_tank()
# 刷新窗口
while True:
sleep(0.02)
# 给窗口设置填充色
MainGame.window.fill(BG_COLOR)
# 增加提示文字
# 1.要增加文字内容
# num = 6
text = self.get_text_surface(f'敌方坦克剩余数量{MainGame.enemy_tank_count}')
# 2.如何把文字加上
MainGame.window.blit(text,(10,10))
# 增加事件
self.get_event()
# 显示 我方坦克
MainGame.my_tank.display_tank()
# 显示敌方坦克
self.display_enemy_tank()
# 移动坦克
if MainGame.my_tank.remove:
MainGame.my_tank.move()
# 显示我方子弹
self.display_my_bullet()
# 显示敌方子弹
self.display_enemy_bullet()
pygame.display.update()
20、我方子弹与敌方坦克的碰撞检测
在游戏开发中,通常把显示图像的对象叫做精灵Spire,精灵需要有两个属性,image要显示的图像,rect图像要显示在屏幕的位置。
在Pygame框架中,使用pygame. sprite模块中的内置函数可以实现碰撞检测。代码如下:
pygame.sprite.collide_rect(first, second) #返回布尔值
修改坦克类,增加是否存活状态
class Tank:
'''
坦克类
'''
def __init__(self) -> None:
self.live = True
在子弹类中增加我方子弹碰撞敌方坦克的方法,如果发生碰撞,修改我方子弹及敌方坦克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
在我方子弹移动后判断子弹是否与敌方坦克碰撞。
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)
修改MainGame类敌方坦克显示逻辑,根据敌方坦克是否存活
def display_enemy_tank(self) -> None:
'''
显示敌方坦克
'''
for e_tank in self.enemy_tank_list:
# 判断敌方坦克是否存活
if e_tank.live:
# 显示敌方坦克
e_tank.display_tank()
# 移动敌方坦克
e_tank.rand_move()
# 发射子弹
e_bullet = e_tank.shot()
# 判断是否有子弹
if e_bullet:
# 将子弹增加到列表中
MainGame.enemy_bullet_list.append(e_bullet)
else:
# 从列表中移除
self.enemy_tank_list.remove(e_tank)
21、爆炸效果
初始化爆炸类
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)
22、敌方子弹与我方坦克碰撞检测
子弹类中,新增敌方子弹与我方坦克的碰撞。如果发生碰撞,修改敌方子弹、我方坦克的状态及产生爆炸效果。
#新增敌方子弹与我方坦克的碰撞方法
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)
23、我方坦克无线重生
坦克大战游戏中一般我方坦克有重生的功能,当按下键盘的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()
24、加载墙壁
初始化墙壁类
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)
墙壁加入到窗口
def display_wall(self) -> None:
'''
显示墙壁
'''
for wall in MainGame.wall_list:
# 显示墙壁
wall.display_wall()
25、子弹不能穿墙
子弹不能穿墙指子弹碰到墙壁后消失。因此,子弹类中新增方法,子弹与墙壁的碰撞,如果子弹与墙壁碰撞,修改子弹的状态。另外还需要将墙壁的生命值减少,如果墙壁的生命值小于等于零时候修改墙壁的状态。
#新增子弹与墙壁的碰撞
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.display_bullet()
e_bullet.move()
# 判断是否击中我方坦克
e_bullet.hit_my_tank()
# 判断是否击中墙壁
e_bullet.hit_wall()
else:
# 如果子弹不存活,从列表中移除
MainGame.enemy_bullet_list.remove(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()
# 判断我方子弹是否击中敌方坦克
my_bullet.hit_enemy_tank()
# 判断我方子弹是否击中墙壁
my_bullet.hit_wall()
else:
# 从列表中移除
MainGame.my_bullet_list.remove(my_bullet)
26、设置子弹耐久值
设置墙壁生命值与存活状态
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
# 设置墙壁的生命值
self.hp = 3
# 设置墙壁的状态
self.live = True
修改子弹碰撞墙壁逻辑
class Bullet:
'''
子弹类
'''
def hit_wall(self):
'''
碰撞墙壁
'''
for wall in MainGame.wall_list:
# 判断是否碰撞
if collide_rect(self,wall):
# 修改子弹的状态
self.live = False
# 修改墙壁的生命值
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)
27、坦克不能穿墙功能
坦克不能穿墙指坦克一旦碰到墙壁则不能再移动,也就是需要修改坦克的坐标为移动之前的。因此在坦克类中新增属性oldLeft、oldTop记录移动之前的坐标,新增stay()、hitWalls()方法。
class Tank:
'''
坦克类
'''
def __init__(self) -> None:
self.live = True
# 记录坦克原来的位置
self.old_left = 0
self.old_top = 0
def move(self) -> None:
'''
坦克的移动
'''
# 记录坦克原来的位置,为了方便还原碰撞后的位置
self.old_left = self.rect.left
self.old_top = self.rect.top
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
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.display_tank()
# 移动敌方坦克
e_tank.rand_move()
# 判断是否与墙壁发生碰撞
e_tank.tank_hit_wall()
# 发射子弹
e_bullet = e_tank.shot()
# 判断是否有子弹
if e_bullet:
# 将子弹增加到列表中
MainGame.enemy_bullet_list.append(e_bullet)
else:
# 从列表中移除
self.enemy_tank_list.remove(e_tank)
# 判断我方坦克是否死亡
if MainGame.my_tank and MainGame.my_tank.live:
# 移动坦克
if MainGame.my_tank.remove:
MainGame.my_tank.move()
# 检测我方坦克是否与墙壁发生碰撞
MainGame.my_tank.tank_hit_wall()
28、双方坦克之间碰撞检测
如果我方坦克碰撞到敌方坦克,则我方坦克再不能继续移动。同理如果敌方坦克碰撞到我方坦克也不能继续移动。
在坦克类中新增坦克与坦克碰撞的检测方法
class Tank:
def tank_collide_tank(self,tank):
'''
检测2个坦克是否碰撞
'''
# 判断是否都存活
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
我方坦克移动后,调用是否与敌方坦克发生碰撞。
#根据坦克的开关状态调用坦克的移动方法
if MainGame.TANK_P1 and not MainGame.TANK_P1.stop:
MainGame.TANK_P1.move()
#调用碰撞墙壁的方法
MainGame.TANK_P1.hitWalls()
MainGame.TANK_P1.hitEnemyTank()
在敌方坦克类中,新增敌方坦克碰撞我方坦克的方法。
def hitMyTank(self):
if MainGame.TANK_P1 and MainGame.TANK_P1.live:
if pygame.sprite.collide_rect(self, MainGame.TANK_P1):
# 让敌方坦克停下来 stay()
self.stay()
敌方坦克添加到窗口时候,调用是否与我方坦克碰撞。
#将敌方坦克加入到窗口中
def blitEnemyTank(self):
for eTank in MainGame.EnemyTank_list:
if eTank.live:
eTank.displayTank()
# 坦克移动的方法
eTank.randMove()
#调用敌方坦克与墙壁的碰撞方法
eTank.hitWalls()
#敌方坦克是否撞到我方坦克
eTank.hitMyTank()
# 调用敌方坦克的射击
eBullet = eTank.shot()
# 如果子弹为None。不加入到列表
if eBullet:
# 将子弹存储敌方子弹列表
MainGame.Enemy_bullet_list.append(eBullet)
else:
MainGame.EnemyTank_list.remove(eTank)
29、音效处理
music是pygame中控制流音频的pygame模块,音乐模块与pygame.mixer紧密相连, pygame.mixer是一个用来处理声音的模块,其含义为“混音器”。游戏中对声音的处理一般包括制造声音和播放声音两部分。
初始化混合器
pygame.mixer.init()
加载一个播放音乐的文件
pygame.mixer.music.load()
开始播放音乐流
pygame.mixer.music.play()
初始化音效类
class Music():
def __init__(self,fileName):
self.fileName = fileName
#先初始化混合器
pygame.mixer.init()
pygame.mixer.music.load(self.fileName)
#开始播放音乐
def play(self):
pygame.mixer.music.play()
创建坦克时,添加音效。
#创建我方坦克的方法
def creatMyTank(self):
# 创建我方坦克
MainGame.TANK_P1 = MyTank(400, 300)
#创建音乐对象
music = Music('img/start.wav')
#调用播放音乐方法
music.play()
我方坦克发射子弹时,添加音效。
elif event.key == pygame.K_SPACE:
print("发射子弹")
if len(MainGame.Bullet_list) < 3:
# 产生一颗子弹
m = Bullet(MainGame.TANK_P1)
# 将子弹加入到子弹列表
MainGame.Bullet_list.append(m)
music = Music('img/fire.wav')
music.play()
30、项目完整代码
https://gitee.com/bitwli-luyao/tank.git
import pygame,time,random
_display = pygame.display
COLOR_BLACK = pygame.Color(0, 0, 0)
COLOR_RED = pygame.Color(255, 0, 0)
version = 'v1.25'
class MainGame():
#游戏主窗口
window = None
SCREEN_HEIGHT = 500
SCREEN_WIDTH = 800
#创建我方坦克
TANK_P1 = None
#存储所有敌方坦克
EnemyTank_list = []
#要创建的敌方坦克的数量
EnemTank_count = 5
#存储我方子弹的列表
Bullet_list = []
#存储敌方子弹的列表
Enemy_bullet_list = []
#爆炸效果列表
Explode_list = []
#墙壁列表
Wall_list = []
#开始游戏方法
def startGame(self):
_display.init()
#创建窗口加载窗口(借鉴官方文档)
MainGame.window = _display.set_mode([MainGame.SCREEN_WIDTH,MainGame.SCREEN_HEIGHT])
self.creatMyTank()
self.creatEnemyTank()
self.creatWalls()
#设置一下游戏标题
_display.set_caption("坦克大战"+version)
#让窗口持续刷新操作
while True:
#给窗口完成一个填充颜色
MainGame.window.fill(COLOR_BLACK)
#在循环中持续完成事件的获取
self.getEvent()
#将绘制文字得到的小画布,粘贴到窗口中
MainGame.window.blit(self.getTextSurface("剩余敌方坦克%d辆"%len(MainGame.EnemyTank_list)),(5,5))
#调用展示墙壁的方法
self.blitWalls()
if MainGame.TANK_P1 and MainGame.TANK_P1.live:
# 将我方坦克加入到窗口中
MainGame.TANK_P1.displayTank()
else:
del MainGame.TANK_P1
MainGame.TANK_P1 = None
#循环展示敌方坦克
self.blitEnemyTank()
#根据坦克的开关状态调用坦克的移动方法
if MainGame.TANK_P1 and not MainGame.TANK_P1.stop:
MainGame.TANK_P1.move()
#调用碰撞墙壁的方法
MainGame.TANK_P1.hitWalls()
MainGame.TANK_P1.hitEnemyTank()
#调用渲染子弹列表的一个方法
self.blitBullet()
#调用渲染敌方子弹列表的一个方法
self.blitEnemyBullet()
#调用展示爆炸效果的方法
self.displayExplodes()
time.sleep(0.02)
#窗口的刷新
_display.update()
#创建我方坦克的方法
def creatMyTank(self):
# 创建我方坦克
MainGame.TANK_P1 = MyTank(400, 300)
#创建音乐对象
music = Music('img/start.wav')
#调用播放音乐方法
music.play()
#创建敌方坦克
def creatEnemyTank(self):
top = 100
for i in range(MainGame.EnemTank_count):
speed = random.randint(3,6)
#每次都随机生成一个left值
left = random.randint(1, 7)
eTank = EnemyTank(left*100,top,speed)
MainGame.EnemyTank_list.append(eTank)
#创建墙壁的方法
def creatWalls(self):
for i in range(6):
wall = Wall(130*i,240)
MainGame.Wall_list.append(wall)
def blitWalls(self):
for wall in MainGame.Wall_list:
if wall.live:
wall.displayWall()
else:
MainGame.Wall_list.remove(wall)
#将敌方坦克加入到窗口中
def blitEnemyTank(self):
for eTank in MainGame.EnemyTank_list:
if eTank.live:
eTank.displayTank()
# 坦克移动的方法
eTank.randMove()
#调用敌方坦克与墙壁的碰撞方法
eTank.hitWalls()
#敌方坦克是否撞到我方坦克
eTank.hitMyTank()
# 调用敌方坦克的射击
eBullet = eTank.shot()
# 如果子弹为None。不加入到列表
if eBullet:
# 将子弹存储敌方子弹列表
MainGame.Enemy_bullet_list.append(eBullet)
else:
MainGame.EnemyTank_list.remove(eTank)
#将我方子弹加入到窗口中
def blitBullet(self):
for bullet in MainGame.Bullet_list:
#如果子弹还活着,绘制出来,否则,直接从列表中移除该子弹
if bullet.live:
bullet.displayBullet()
# 让子弹移动
bullet.bulletMove()
# 调用我方子弹与敌方坦克的碰撞方法
bullet.hitEnemyTank()
# 调用判断我方子弹是否碰撞到墙壁的方法
bullet.hitWalls()
else:
MainGame.Bullet_list.remove(bullet)
#将敌方子弹加入到窗口中
def blitEnemyBullet(self):
for eBullet in MainGame.Enemy_bullet_list:
# 如果子弹还活着,绘制出来,否则,直接从列表中移除该子弹
if eBullet.live:
eBullet.displayBullet()
# 让子弹移动
eBullet.bulletMove()
#调用是否碰撞到墙壁的一个方法
eBullet.hitWalls()
if MainGame.TANK_P1 and MainGame.TANK_P1.live:
eBullet.hitMyTank()
else:
MainGame.Enemy_bullet_list.remove(eBullet)
#新增方法: 展示爆炸效果列表
def displayExplodes(self):
for explode in MainGame.Explode_list:
if explode.live:
explode.displayExplode()
else:
MainGame.Explode_list.remove(explode)
#获取程序期间所有事件(鼠标事件,键盘事件)
def getEvent(self):
#1.获取所有事件
eventList = pygame.event.get()
#2.对事件进行判断处理(1、点击关闭按钮 2、按下键盘上的某个按键)
for event in eventList:
#判断event.type 是否QUIT,如果是退出的话,直接调用程序结束方法
if event.type == pygame.QUIT:
self.endGame()
#判断事件类型是否为按键按下,如果是,继续判断按键是哪一个按键,来进行对应的处理
if event.type == pygame.KEYDOWN:
#点击ESC按键让我方坦克重生
if event.key == pygame.K_ESCAPE and not MainGame.TANK_P1:
#调用创建我方坦克的方法
self.creatMyTank()
if MainGame.TANK_P1 and MainGame.TANK_P1.live:
# 具体是哪一个按键的处理
if event.key == pygame.K_LEFT:
print("坦克向左调头,移动")
# 修改坦克方向
MainGame.TANK_P1.direction = 'L'
MainGame.TANK_P1.stop = False
elif event.key == pygame.K_RIGHT:
print("坦克向右调头,移动")
# 修改坦克方向
MainGame.TANK_P1.direction = 'R'
MainGame.TANK_P1.stop = False
elif event.key == pygame.K_UP:
print("坦克向上调头,移动")
# 修改坦克方向
MainGame.TANK_P1.direction = 'U'
MainGame.TANK_P1.stop = False
elif event.key == pygame.K_DOWN:
print("坦克向下掉头,移动")
# 修改坦克方向
MainGame.TANK_P1.direction = 'D'
MainGame.TANK_P1.stop = False
elif event.key == pygame.K_SPACE:
print("发射子弹")
if len(MainGame.Bullet_list) < 3:
# 产生一颗子弹
m = Bullet(MainGame.TANK_P1)
# 将子弹加入到子弹列表
MainGame.Bullet_list.append(m)
music = Music('img/fire.wav')
music.play()
else:
print("子弹数量不足")
print("当前屏幕中的子弹数量为:%d" % len(MainGame.Bullet_list))
#结束游戏方法
if event.type == pygame.KEYUP:
#松开的如果是方向键,才更改移动开关状态
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_UP or event.key == pygame.K_DOWN:
if MainGame.TANK_P1 and MainGame.TANK_P1.live:
# 修改坦克的移动状态
MainGame.TANK_P1.stop = True
#左上角文字绘制的功能
def getTextSurface(self,text):
# 初始化字体模块
pygame.font.init()
#查看系统支持的所有字体
# fontList = pygame.font.get_fonts()
# print(fontList)
# 选中一个合适的字体
font = pygame.font.SysFont('kaiti',18)
# 使用对应的字符完成相关内容的绘制
textSurface = font.render(text,True,COLOR_RED)
return textSurface
def endGame(self):
print("谢谢使用")
#结束python解释器
exit()
class BaseItem(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class Tank(BaseItem):
def __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 = 'U'
self.image = self.images[self.direction]
#坦克所在的区域 Rect->
self.rect = self.image.get_rect()
#指定坦克初始化位置 分别距x,y轴的位置
self.rect.left = left
self.rect.top = top
#新增速度属性
self.speed = 5
#新增属性: 坦克的移动开关
self.stop = True
#新增属性 live 用来记录,坦克是否活着
self.live = True
#新增属性: 用来记录坦克移动之前的坐标(用于坐标还原时使用)
self.oldLeft = self.rect.left
self.oldTop = self.rect.top
#坦克的移动方法
def move(self):
#先记录移动之前的坐标
self.oldLeft = self.rect.left
self.oldTop = self.rect.top
if self.direction == 'L':
if self.rect.left > 0:
self.rect.left -= self.speed
elif self.direction == 'R':
if self.rect.left + self.rect.height < MainGame.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 < MainGame.SCREEN_HEIGHT:
self.rect.top += self.speed
def stay(self):
self.rect.left = self.oldLeft
self.rect.top = self.oldTop
#新增碰撞墙壁的方法
def hitWalls(self):
for wall in MainGame.Wall_list:
if pygame.sprite.collide_rect(wall,self):
self.stay()
#射击方法
def shot(self):
return Bullet(self)
#展示坦克(将坦克这个surface绘制到窗口中 blit())
def displayTank(self):
#1.重新设置坦克的图片
self.image = self.images[self.direction]
#2.将坦克加入到窗口中
MainGame.window.blit(self.image,self.rect)
class MyTank(Tank):
def __init__(self,left,top):
super(MyTank, self).__init__(left,top)
#新增主动碰撞到敌方坦克的方法
def hitEnemyTank(self):
for eTank in MainGame.EnemyTank_list:
if pygame.sprite.collide_rect(eTank,self):
self.stay()
class EnemyTank(Tank):
def __init__(self,left,top,speed):
super(EnemyTank, self).__init__(left,top)
# self.live = True
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]
# 坦克所在的区域 Rect->
self.rect = self.image.get_rect()
# 指定坦克初始化位置 分别距x,y轴的位置
self.rect.left = left
self.rect.top = top
# 新增速度属性
self.speed = speed
self.stop = True
#新增步数属性,用来控制敌方坦克随机移动
self.step = 30
def randDirection(self):
num = random.randint(1,4)
if num == 1:
return 'U'
elif num == 2:
return 'D'
elif num == 3:
return 'L'
elif num == 4:
return 'R'
# def displayEnemtTank(self):
# super().displayTank()
#随机移动
def randMove(self):
if self.step <= 0:
self.direction = self.randDirection()
self.step = 50
else:
self.move()
self.step -= 1
def shot(self):
num = random.randint(1,1000)
if num <= 20:
return Bullet(self)
def hitMyTank(self):
if MainGame.TANK_P1 and MainGame.TANK_P1.live:
if pygame.sprite.collide_rect(self, MainGame.TANK_P1):
# 让敌方坦克停下来 stay()
self.stay()
class Bullet(BaseItem):
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':
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':
self.rect.left = tank.rect.left + tank.rect.width / 2 - self.rect.width / 2
self.rect.top = tank.rect.top + tank.rect.height
elif self.direction == 'L':
self.rect.left = tank.rect.left - self.rect.width / 2 - self.rect.width / 2
self.rect.top = tank.rect.top + tank.rect.width / 2 - self.rect.width / 2
elif self.direction == 'R':
self.rect.left = tank.rect.left + tank.rect.width
self.rect.top = tank.rect.top + tank.rect.width / 2 - self.rect.width / 2
#速度
self.speed = 7
#用来记录子弹是否活着
self.live = True
#子弹的移动方法
def bulletMove(self):
if self.direction == 'U':
if self.rect.top > 0:
self.rect.top -= self.speed
else:
#修改状态值
self.live = False
elif self.direction == 'D':
if self.rect.top < MainGame.SCREEN_HEIGHT - self.rect.height:
self.rect.top += self.speed
else:
# 修改状态值
self.live = False
elif self.direction == 'L':
if self.rect.left > 0:
self.rect.left -= self.speed
else:
# 修改状态值
self.live = False
elif self.direction == 'R':
if self.rect.left < MainGame.SCREEN_WIDTH - self.rect.width:
self.rect.left += self.speed
else:
# 修改状态值
self.live = False
#展示子弹的方法
def displayBullet(self):
MainGame.window.blit(self.image,self.rect)
#新增我方子弹碰撞敌方坦克的方法
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 = False
eTank.live = False
#新增敌方子弹与我方坦克的碰撞方法
def hitMyTank(self):
if pygame.sprite.collide_rect(self,MainGame.TANK_P1):
# 产生爆炸效果,并加入到爆炸效果列表中
explode = Explode(MainGame.TANK_P1)
MainGame.Explode_list.append(explode)
#修改子弹状态
self.live = False
#修改我方坦克状态
MainGame.TANK_P1.live = False
#新增子弹与墙壁的碰撞
def hitWalls(self):
for wall in MainGame.Wall_list:
if pygame.sprite.collide_rect(wall,self):
#修改子弹的live属性
self.live = False
wall.hp -= 1
if wall.hp <= 0:
wall.live = False
class Explode():
def __init__(self,tank):
self.rect = tank.rect
self.step = 0
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.image = self.images[self.step]
self.live = True
#展示爆炸效果
def displayExplode(self):
if self.step < len(self.images):
MainGame.window.blit(self.image, self.rect)
self.image = self.images[self.step]
self.step += 1
else:
self.live = False
self.step = 0
class Wall():
def __init__(self,left,top):
self.image = pygame.image.load('img/steels.gif')
self.rect = self.image.get_rect()
self.rect.left = left
self.rect.top = top
#用来判断墙壁是否应该在窗口中展示
self.live = True
#用来记录墙壁的生命值
self.hp = 3
#展示墙壁的方法
def displayWall(self):
MainGame.window.blit(self.image,self.rect)
#我方坦克出生
class Music():
def __init__(self,fileName):
self.fileName = fileName
#先初始化混合器
pygame.mixer.init()
pygame.mixer.music.load(self.fileName)
#开始播放音乐
def play(self):
# pygame.mixer.music.play()
pass
MainGame().startGame()
更多推荐
所有评论(0)