[Python] 坦克大战小游戏
@author: 时光不与歌
"""
import random
import pygame
from pygame.sprite import Sprite
import pygame.base
'''
坦克大战游戏的需求
1.项目中有哪些类
2.每个类中有哪些方法
1.坦克类(我方坦克和敌方坦克)
射击
移动
显示坦克
2.子弹类
移动
显示子弹
3.墙壁类
属性:是否可以通过
4.爆炸效果类
展示爆炸效果
5.音效类
播放音乐
6.主类
开始游戏
结束游戏
'''
SCREEN_WIDTH = 700
SCREEN_HEIGHT = 500
BG_COLOR = pygame.Color(0, 0, 0)
TEXT_COLOR = pygame.Color(255, 0, 0)
# 定义一个基类
class BaseItem(Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class MainGame:
window = None
my_tank = None
# 存储敌方坦克的列表
enemy_tank = []
# 存储我方子弹的列表
my_bullet_list = []
# 存储敌方子弹的列表
enemy_bullet_list = []
# 存储爆炸效果的列表
explode_list = []
# 定义敌方坦克的数量
enemy_tank_count = 5
def __init__(self):
pass
# 开始游戏
def start_game(self):
# 加载主窗口
# 初始化窗口
pygame.display.init()
# 设置窗口的大小及显示
MainGame.window = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
# 初始化我方坦克
MainGame.my_tank = Tank(350, 250)
# 初始化敌方坦克, 并将敌方坦克添加到列表中
self.create_enemy_tank()
# 设置窗口
pygame.display.set_caption('坦克大战小游戏')
while True:
# 给窗口设置填充色
MainGame.window.fill(BG_COLOR)
# 获取事件
self.get_event()
# 绘制文字 (10, 10)是坐标
MainGame.window.blit(self.get_text(f'敌方坦克剩余数量{len(MainGame.enemy_tank)}'), (10, 10))
MainGame.window.blit(self.get_text(f'我方子弹数量{len(MainGame.my_bullet_list)}'), (10, 30))
MainGame.window.blit(self.get_text(f'敌方子弹数量{len(MainGame.enemy_bullet_list)}'), (10, 50))
# 循环遍历敌方坦克列表 展示敌方坦克
self.blit_enemy_tank()
# 循环遍历显示我方坦克的子弹
self.blit_my_bullet()
# 循环遍历显示敌方子弹
self.blit_enemy_bullet()
# 调用坦克显示的方法
MainGame.my_tank.display_tank()
# 循环遍历爆炸列表 展示爆炸效果
self.blit_explode()
# 调用移动方法
# 如果坦克的开关是开启 才可以移动
if not MainGame.my_tank.stop:
MainGame.my_tank.move()
pygame.display.update()
# 初始化敌方坦克, 并将敌方坦克添加到列表中
@staticmethod
def create_enemy_tank():
top = 100
# 循环生成敌方坦克
for i in range(MainGame.enemy_tank_count):
left = random.randint(0, 600)
speed = 1
enemy = EnemyTank(left, top, speed)
MainGame.enemy_tank.append(enemy)
# 循环展示爆炸效果
@staticmethod
def blit_explode():
for i in MainGame.explode_list:
# 判断是否活着
if i.live:
# 展示
i.display_explode()
else:
# 在爆炸列表中移除
MainGame.explode_list.remove(i)
# 循环遍历敌方坦克列表 展示敌方坦克
@staticmethod
def blit_enemy_tank():
for i in MainGame.enemy_tank:
# 判断当前敌方坦克是否活着
if i.live:
i.display_tank()
i.rand_move()
# 发射子弹
enemy_bullet = i.shot()
# 判断敌方子弹是否是none 如果不为none则添加到敌方子弹列表中
if enemy_bullet:
# 将敌方子弹存储到敌方子弹列表中
MainGame.enemy_bullet_list.append(enemy_bullet)
else:
MainGame.enemy_tank.remove(i)
# 循环遍历我方子弹存储列表
@staticmethod
def blit_my_bullet():
for i in MainGame.my_bullet_list:
# 判断当前的子弹是否是活着状态 如果是则进行显示和移动 否则删除
if i.live:
i.display_bullet()
# 调用子弹的移动方法
i.move()
# 调用检测我方子弹是否与敌方坦克发生碰撞
i.my_bullet_hit_enemy_tank()
else:
MainGame.my_bullet_list.remove(i)
# 循环遍历敌方子弹存储列表
@staticmethod
def blit_enemy_bullet():
for i in MainGame.enemy_bullet_list:
# 判断当前的子弹是否是活着状态 如果是则进行显示和移动 否则删除
if i.live:
i.display_bullet()
# 调用子弹的移动方法
i.move()
else:
MainGame.enemy_bullet_list.remove(i)
# 结束游戏
@staticmethod
def end_game():
print('退出游戏')
exit()
# 左上角文字的绘制
@staticmethod
def get_text(text):
# 初始化字体模块
pygame.font.init()
# 查看所有的字体名称
# print(pygame.font.get_fonts())
# 获取字体font对象
font = pygame.font.SysFont('kaiti', 18)
# 绘制文字信息 参数1是文本 参数2是抗锯齿
text_surface = font.render(text, True, TEXT_COLOR)
return text_surface
# 获取事件
def get_event(self):
# 获取所有事件
event_list = pygame.event.get()
# 遍历事件
for i in event_list:
# 判断按下的键是关闭还是键盘按下
# 如果按的是退出, 关闭窗口
if i.type == pygame.QUIT:
self.end_game()
# 如果是键盘按下事件 坦克开始移动
if i.type == pygame.KEYDOWN:
if i.key == pygame.K_UP:
# 切换方向
MainGame.my_tank.direction = 'U'
# 修改坦克的开关状态
MainGame.my_tank.stop = False
# MainGame.my_tank.move()
print('按下上键, 坦克向上移动')
elif i.key == pygame.K_DOWN:
MainGame.my_tank.direction = 'D'
MainGame.my_tank.stop = False
# MainGame.my_tank.move()
print('按下下键, 坦克向下移动')
elif i.key == pygame.K_LEFT:
MainGame.my_tank.direction = 'L'
MainGame.my_tank.stop = False
# MainGame.my_tank.move()
print('按下左键, 坦克向左移动')
elif i.key == pygame.K_RIGHT:
MainGame.my_tank.direction = 'R'
MainGame.my_tank.stop = False
# MainGame.my_tank.move()
print('按下右键, 坦克向右移动')
elif i.key == pygame.K_SPACE:
# 空格键停止移动
MainGame.my_tank.stop = True
elif chr(i.key) == 'w':
# w键射击
print('射击')
# 如果当前我方子弹列表的大小 小于等于3的时候才可以创建
if len(MainGame.my_bullet_list) <= 10:
# 创建我方坦克发射的子弹
my_bullet = Bullet(MainGame.my_tank)
MainGame.my_bullet_list.append(my_bullet)
# 坦克类
class Tank(BaseItem):
# 添加距离左边left 距离上边top
def __init__(self, left, top):
# 保存的加载图片
super().__init__()
self.top = None
self.images = {
'U': pygame.image.load('img/tankU.gif'),
'D': pygame.image.load('img/tankD.gif'),
'L': pygame.image.load('img/tankL.gif'),
'R': pygame.image.load('img/tankR.gif')
}
# 方向 默认朝上
self.direction = 'U'
# 根据当前图片的方向获取图片
self.image = self.images[self.direction]
# 根据图片获取区域
self.rect = self.image.get_rect()
self.rect.left = left
self.rect.top = top
# 速度 决定移动的快慢
self.speed = 1
# 坦克移动的开关
self.stop = True
# 是否活着
self.live = True
# 移动
def move(self):
# 判断坦克的方向进行移动
if self.direction == 'L':
if self.rect.left > 0:
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
elif self.direction == 'R':
if self.rect.left + self.rect.height < SCREEN_WIDTH:
self.rect.left += self.speed
# 射击
def shot(self):
return Bullet(self)
# 显示
def display_tank(self):
# 获取展示的对象
self.image = self.images[self.direction]
# 调用blit方法展示
MainGame.window.blit(self.image, self.rect)
# 敌方坦克
def rand_direction():
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'
class EnemyTank(Tank):
def __init__(self, left, top, speed):
self.live = True
super(EnemyTank, self).__init__(left, top)
# 加载图片集
self.images = {
'U': pygame.image.load('img/p2tankU.gif'),
'D': pygame.image.load('img/p2tankD.gif'),
'L': pygame.image.load('img/p2tankL.gif'),
'R': pygame.image.load('img/p2tankR.gif')
}
# 方向
self.direction = rand_direction()
# 根据方向获取图片
self.image = self.images[self.direction]
# 区域
self.rect = self.image.get_rect()
# 对left和top进行赋值
self.rect.left = left
self.rect.top = top
# 速度
self.speed = speed
# 移动开关键
self.flag = True
# 新增加一个步数变量
self.step = 200
# 敌方坦克随机移动的方法
def rand_move(self):
# 如果步数小于等于0
if self.step <= 0:
# 修改方向
self.direction = rand_direction()
# 让步数复位
self.step = 200
else:
self.move()
# 递减步数
var = random.randint(0, 4)
self.step -= var
# 重写shot()
def shot(self):
# 随机生成100的数
num = random.randint(1, 100)
if num < 2:
return Bullet(self)
# 子弹类
class Bullet(BaseItem):
def __init__(self, tank):
# 加载图片
super().__init__()
self.image = pygame.image.load('img/bulletD.png')
# 坦克的方向决定子弹的方向
self.direction = tank.direction
# 获取区域
self.rect = self.image.get_rect()
# 子弹的left和top与方向有关
if self.direction == 'U':
self.rect = self.image.get_rect()
self.image = pygame.image.load('img/bulletU.png')
self.rect.left = tank.rect.left + tank.rect.width / 2 - self.rect.width / 2
self.rect.top = tank.rect.top - self.rect.height + 5
elif self.direction == 'D':
self.rect = self.image.get_rect()
self.image = pygame.image.load('img/bulletD.png')
self.rect.left = tank.rect.left + tank.rect.width / 2 - self.rect.width / 2
self.rect.top = tank.rect.top + self.rect.height + 10
elif self.direction == 'L':
self.rect = self.image.get_rect()
self.image = pygame.image.load('img/bulletL.png')
self.rect.left = tank.rect.left + 15 - tank.rect.width / 2 - self.rect.width / 2
self.rect.top = tank.rect.top + 10 + self.rect.width / 2 - self.rect.width / 2
elif self.direction == 'R':
self.rect = self.image.get_rect()
self.image = pygame.image.load('img/bulletR.png')
self.rect.left = tank.rect.left - 3 + tank.rect.width
self.rect.top = tank.rect.top + 10 + self.rect.width / 2 - self.rect.width / 2
# 子弹的速度
self.speed = 3
# 子弹的状态 是否碰到墙壁 如果碰到墙壁 修改此状态
self.live = True
# 移动
def move(self):
if self.direction == 'U':
if self.rect.top > 0:
self.rect.top -= 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 == 'D':
if self.rect.top + self.rect.height < SCREEN_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
# 显示
def display_bullet(self):
# 将图片surface加载到窗口
MainGame.window.blit(self.image, self.rect)
# 我方子弹与敌方坦克碰撞
def my_bullet_hit_enemy_tank(self):
# 循环遍历敌方坦克列表
for i in MainGame.enemy_tank:
# 如果坦克与子弹发生碰撞
if pygame.sprite.collide_rect(i, self):
# 修改敌方坦克和我方子弹的状态
i.live = False
self.live = False
# 创建爆炸对象
explode = Explode(i)
# 将爆炸对象添加到爆炸列表中
MainGame.explode_list.append(explode)
# 爆炸效果类
class Explode:
def __init__(self, tank):
# 爆炸的位置由当前子弹中的坦克位置决定
self.rect = tank.rect
self.images = [
pygame.image.load('img/e1.gif'),
pygame.image.load('img/e2.gif'),
pygame.image.load('img/e3.gif'),
pygame.image.load('img/e4.gif'),
pygame.image.load('img/e5.gif'),
pygame.image.load('img/e6.gif'),
pygame.image.load('img/e7.gif'),
pygame.image.load('img/e8.gif'),
pygame.image.load('img/e9.gif'),
pygame.image.load('img/e10.gif'),
pygame.image.load('img/e11.gif'),
pygame.image.load('img/e12.gif'),
pygame.image.load('img/e13.gif'),
pygame.image.load('img/e14.gif'),
pygame.image.load('img/e15.gif'),
pygame.image.load('img/e16.gif'),
]
self.step = 1
self.image = self.images[self.step]
# 是否活着
self.live = True
# 显示爆炸效果的方法
def display_explode(self):
if self.step < len(self.images):
# 根据索引获取爆炸对象
self.image = self.images[self.step]
self.step += 1
# 添加到主窗口
MainGame.window.blit(self.image, self.rect)
else:
# 修改状态
self.live = False
self.step = 0
if __name__ == '__main__':
MainGame().start_game()
成品 ---> https://wwng.lanzoub.com/iuNSd0hk7g9a
方向键控制移动 按W开火 在游戏里只能按这5个键 按其它键会报异常退出
相关推荐
标签:Python
留言与评论(共有 0 条评论) |