卓越飞翔博客卓越飞翔博客

卓越飞翔 - 您值得收藏的技术分享站
技术文章11201本站已运行3223

[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个键 按其它键会报异常退出
卓越飞翔博客
上一篇: 【2022新版】微信域名拦截检测API源码,检测域名是否能在微信正常打开
下一篇: html一个简单的春节倒计时页面
留言与评论(共有 0 条评论)
   
验证码:
隐藏边栏