IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> python坦克大战 -> 正文阅读

[Python知识库]python坦克大战


前言

《坦克大战》,1985年由日本开发商南梦宫(Namco)开发,是第一款可以双打的红白机游戏。当时使用的还是小霸王。如何用python实现这个游戏


资源获取

图片音频等素材资源包括源代码(ps:源代码可能后面会改可能跟下方不一样)我放在了GitHub上了,有想法的xd可以去下载下来完善或者玩一下也行,https://github.com/fbozhang/python/tree/master/pygame/tank

一、项目介绍

1.pygame是什么?

Pygame是跨平台Pyth,Pygame 作者是 Pete Shinners, 协议为 GNU Lesser General Public License。

pygame是跨平台Python模块,专为电子游戏设计。包含图像、声音。建立在SDL基础上,允许实时电子 游戏研发而无需被低级语言(如机器语言和汇编语言)束缚。基于这样一个设想,所有需要的游戏功能和理念都(主要是图像方面)都完全简化为游戏逻辑本身,所有的资源结构都可以由高级语言提供,如Python。我们这个游戏主要就是使用pygame的模块实现。

2.操作指南

玩家:上下左右 移动 空格 射击
F1: 复活玩家
F2: 复活我方老鹰
F3: 复活敌方坦克
F4: 外挂模式——子弹自动追踪敌方

3.项目演示

演示视频:

演示gif(利用下面网站转换):
在这里插入图片描述

二、项目实现

1.安装库

pip install pygame

2.引入库

代码如下(示例):

import math
import random
import sys
import time
import pygame

3.项目代码

PS: 以下代码以尽量都注释了,如还有哪里不明白可以call me添加注解

本质上这是一个贴图游戏

3.1 主逻辑类

开始游戏,结束游戏,获取事件(比如鼠标事件、键盘事件)并处理

class MainGame():
    # 游戏主窗口
    window = None
    SCREEN_WIDTH = 800
    SCREEN_HEIGHT = 500
    # 背景
    background = "images/background.gif"
    # 创建我方水晶
    Home = None
    # 创建我方坦克
    TANK_P1 = None
    # 存储所有的敌方坦克
    EnemyTank_List = []
    # 要创建的敌方坦克的数量
    EnemyTank_count = 3
    # 存储我方子弹的列表
    Bullet_List = []
    # 存储敌方子弹的列表
    Enemy_bullet_List = []
    # 爆炸效果列表
    Explode_List = []
    # 墙壁列表
    Wall_List = []
    # 外挂模式
    cheat = False

    # 开始游戏
    def startGame(self):
        # 初始化显示模块
        pygame.display.init()
        # 创建窗口加载窗口
        MainGame.window = pygame.display.set_mode([MainGame.SCREEN_WIDTH, MainGame.SCREEN_HEIGHT])
        # 创建我方坦克
        self.creatMyTank()
        # 创建敌方坦克
        self.creatEnemyTank()
        # 创建水晶
        self.creatHome()
        # 创建墙壁
        self.creatWalls()
        # 设置游戏标题
        pygame.display.set_caption("坦克大战" + version)
        # 创建音乐对象
        music = Music("audios/start.wav")
        # 调用播放音乐方法
        music.play()
        # 让窗口持续刷新操作
        while True:
            # 给窗口填充颜色
            MainGame.window.fill(COLOR_BLACK)
            # 显示背景
            self.blitBackground()
            # 在循环中持续完成事件的获取
            self.getEvent()
            # 将绘制文字得到的小画布粘贴到窗口中
            MainGame.window.blit(self.getTextSurface("剩余敌方坦克%d辆" % len(MainGame.EnemyTank_List)), (5, 5))
            # 调用展示墙壁的方法
            self.blitWalls()
            # 展示水晶
            self.blitHome()
            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)
            if not MainGame.Home.live:
                # 将绘制文字得到的小画布粘贴到窗口中
                MainGame.window.blit(self.getTextSurface_Tips("Game Over!!"),
                                     (200, MainGame.SCREEN_HEIGHT / 2 - 60))
            if len(MainGame.EnemyTank_List) == 0:
                MainGame.window.blit(self.getTextSurface_Tips("victory!!"),
                                     (250, MainGame.SCREEN_HEIGHT / 2 - 60))
            # 窗口的刷新
            pygame.display.update()

    # 创建我方坦克
    def creatMyTank(self):
        MainGame.TANK_P1 = MyTank(275, 440)

'''
在纵坐标100以上的位置随机创建敌方坦克
'''

    # 创建敌方坦克
    def creatEnemyTank(self):
        top = 100
        for i in range(MainGame.EnemyTank_count):
            speed = random.randint(3, 6)
            left = random.randint(1, int(MainGame.SCREEN_WIDTH / 100 - 1))
            eTank = EnemyTank(left * 100, top, speed)
            MainGame.EnemyTank_List.append(eTank)


'''
因只是案例所以随便设置了一些墙,如果想完善ui可以在这设计墙壁
'''
    # 创建墙壁
    def creatWalls(self):
        # 创建障碍物
        for i in range(6):
            for j in range(2):
                for k in range(2):
                    wall = Wall(140 * i + 31 * j, MainGame.SCREEN_HEIGHT / 2 - 31 * k)
                    MainGame.Wall_List.append(wall)

        # 创建水晶保护墙
        for i in range(3):
            for j in range(4):
                if i != 0:
                    if j == 0 or j == 4 - 1:
                        wall = Wall(MainGame.Home.rect.left - 31 + 30 * j, MainGame.SCREEN_HEIGHT - 30 * i)
                        MainGame.Wall_List.append(wall)
                else:
                    wall = Wall(MainGame.Home.rect.left - 31 + 30 * j, MainGame.SCREEN_HEIGHT - 30 * 3)
                    MainGame.Wall_List.append(wall)

    # 创建我方水晶
    def creatHome(self):
        MainGame.Home = Home()

    # 将墙壁加入到窗口中
    def blitWalls(self):
        for wall in MainGame.Wall_List:
            if wall.live:
                wall.displayWall()
            else:
                MainGame.Wall_List.remove(wall)

    # 展示背景
    def blitBackground(self):
        Background(MainGame.background).displayBackground()

    # 将水晶标志加入到窗口中
    def blitHome(self):
        MainGame.Home.displayHome()

    # 将敌方坦克加入到窗口中
    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()
                print(bullet.cheat)
                bullet.cheat = MainGame.cheat
                if bullet.cheat:
                    # 子弹追踪
                    if len(MainGame.EnemyTank_List) > 0:
                        bullet.bulletFollowMove(MainGame.EnemyTank_List[0].rect.left,
                                                MainGame.EnemyTank_List[0].rect.top)
                else:
                    # 让子弹移动
                    bullet.bulletMove()
                # 判断我方子弹与敌方坦克是否碰撞
                bullet.hitEnemyTank()
                # 判断子弹是否碰撞到墙壁
                bullet.hitWalls()
                # 判断子弹是否碰撞
                bullet.hitBullet()
                # 判断子弹是否打到水晶
                bullet.hitHome()
            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()
                # 判断子弹是否打到水晶
                eBullet.hitHome()
                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:
                # 点击F1按键让我方坦克重生
                if event.key == pygame.K_F1 and not MainGame.TANK_P1:
                    # 调用创建我方坦克方法
                    self.creatMyTank()
                # 点击F2按键让我方水晶重生
                if event.key == pygame.K_F2 and not MainGame.Home.live:
                    MainGame.Home.live = True
                # 点击F3按键让敌方坦克重生
                if event.key == pygame.K_F3 and len(MainGame.EnemyTank_List) == 0:
                    self.creatEnemyTank()
                if event.key == pygame.K_F4:
                    MainGame.cheat = True
                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
                        # 完成移动操作
                        # MainGame.TANK_P1.move()
                    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 = MainGame.TANK_P1.shot()
                            # 将子弹加入到子弹列表
                            MainGame.Bullet_List.append(m)
                            # 添加射击音效
                            music = Music("audios/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
       """
        # 获取键盘的第二种方法,考虑后面用该方法控制2P
        key = pygame.key.get_pressed()
        if MainGame.TANK_P1 and MainGame.TANK_P1.live:
            if key[pygame.K_a]:
                print("坦克向左调头, 移动")
                MainGame.TANK_P1.direction = "L"
                MainGame.TANK_P1.move()
            elif key[pygame.K_w]:
                print("坦克向上调头, 移动")
                MainGame.TANK_P1.direction = "U"
                MainGame.TANK_P1.move()
            elif key[pygame.K_s]:
                print("坦克向下调头, 移动")
                MainGame.TANK_P1.direction = "D"
                MainGame.TANK_P1.move()
            elif key[pygame.K_d]:
                print("坦克向右调头, 移动")
                MainGame.TANK_P1.direction = "R"
                MainGame.TANK_P1.move()
            # 这个方法暂未解决边移动边设计
            elif key[pygame.K_KP0]:
                print("射击")
                # 产生一颗子弹
                m = Bullet(MainGame.TANK_P1)
                # 将子弹加入到子弹列表
                MainGame.Bullet_List.append(m)
		"""
    # 左上角文字绘制
    def getTextSurface(self, text):
        # 字体初始化
        pygame.font.init()
        """"如果需要改其他系统字体可以先查询,下面选择的楷体"""
        # 查看系统支持的所有字体
        # fontList = pygame.font.get_fonts()
        # print(fontList)
        # 选择一个合适的字体
        font = pygame.font.SysFont("kaiti", 18)  # pygame.font.SysFont("字体名称", 字号, 默认不粗体, 默认不斜体)
        # 使用对应的字符完成相关内容的绘制
        textSurface = font.render(text, True, COLOR_RED)  # font.render(文字, 是否抗锯齿, 颜色, 背景默认没有)
        return textSurface

    # 游戏结束提示
    def getTextSurface_Tips(self, text):
        # 字体初始化
        pygame.font.init()
        font = pygame.font.SysFont("kaiti", 60, bold=True, italic=True)  # pygame.font.SysFont("字体名称", 字号, 默认不粗体, 默认不斜体)
        # 使用对应的字符完成相关内容的绘制
        textSurface = font.render(text, True, COLOR_RED)  # font.render(文字, 是否抗锯齿, 颜色, 背景默认没有)
        return textSurface

    # 结束游戏
    def endGame(self):
        print("谢谢使用")
        # 结束python解释器
        # exit()
        # 结束程序
        sys.exit()

3.2 背景类

加载游戏背景(也可以写成主逻辑类的方法)

class Background():
    def __init__(self, image):
        self.image = pygame.image.load(image)
        self.rect = self.image.get_rect()
        self.rect.left = 0
        self.rect.top = 0

    def displayBackground(self):
        MainGame.window.blit(self.image, self.rect)

3.3 基类

继承精灵类,用于作为需要做碰撞测试的父类,详细参考API文档

class BaseItem(pygame.sprite.Sprite):
    def __int__(self):
        pygame.sprite.Sprite.__init__(self)

3.4 坦克类

坦克的移动,射击以及坦克的展示。因为需要做碰撞测试所以继承基类

class Tank(BaseItem):
    def __init__(self, left, top):
        self.images = {
            "U": pygame.image.load("images/p1tankU.gif"),
            "D": pygame.image.load("images/p1tankD.gif"),
            "L": pygame.image.load("images/p1tankL.gif"),
            "R": pygame.image.load("images/p1tankR.gif"),
        }
        # 初始方向
        self.direction = "U"
        self.image = self.images[self.direction]
        # 坦克所在的区域
        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.width < 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)

3.5 MyTank类

我方坦克,撞到敌方坦克不能移动

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()

3.6 EnemyTank类

重写了移动和射击方法,让敌方坦克随机移动射击

class EnemyTank(Tank):
    def __init__(self, left, top, speed):
        super(EnemyTank, self).__init__(left, top)
        # self.live = True
        self.images = {
            "U": pygame.image.load("images/enemy1U.gif"),
            "D": pygame.image.load("images/enemy1D.gif"),
            "L": pygame.image.load("images/enemy1L.gif"),
            "R": pygame.image.load("images/enemy1R.gif"),
        }
        self.direction = self.randDirection()
        self.image = self.images[self.direction]
        # 坦克所在的区域
        self.rect = self.image.get_rect()
        # 指定坦克初始化位置 分别距x,y轴的位置
        self.rect.left = left
        self.rect.top = top
        # 新增速度属性
        self.speed = speed
        # 坦克的移动开关
        self.stop = True
        # 新增步数属性,用来控制敌方坦克随机移动
        self.step = 20

    def randDirection(self):
        num = random.randint(1, 4)
        if num == 1:
            # self.direction = 'U' # 写成方法则不需要直接改变属性值
            return 'U'
        elif num == 2:
            return 'D'
        elif num == 3:
            return 'L'
        elif num == 4:
            return 'R'

    # 随机移动
    def randMove(self):
        if self.step <= 0:
            self.direction = self.randDirection()
            self.step = 20
        else:
            self.move()
            self.step -= 1

    def shot(self):
        num = random.randint(1, 100)
        if num <= 2:
            return Bullet(self)

    def hitMyTank(self):
        if MainGame.TANK_P1 and MainGame.TANK_P1.live:
            if pygame.sprite.collide_rect(self, MainGame.TANK_P1):
                # 让敌方坦克停下来
                self.stay()

3.7 子弹类

子弹的移动,碰撞以及展示子弹

class Bullet(BaseItem):
    def __init__(self, tank):
        # 图片
        self.image = pygame.image.load("images/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
            self.rect.top = tank.rect.top + tank.rect.width / 2 - self.rect.height / 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.height / 2
        # 速度
        self.speed = 7
        # 用来记录子弹是否活着
        self.live = True
        # 记录是否开挂
        self.cheat = False
	
    # 子弹的移动
    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 bulletFollowMove(self, x, y):
        velocity = 10000
        time = 1 / 1000
        space = velocity * time
        clock = pygame.time.Clock()  # 创建时钟对象
        clock.tick(120)  # 每秒最多循环60次,即设置帧率为60

        distance = math.sqrt(pow(x - self.rect.left, 2) + pow(y - self.rect.top, 2))
        sina = (y - self.rect.top) / distance
        cosa = (x - self.rect.left) / distance
        self.rect.left = self.rect.left + space * cosa
        self.rect.top = self.rect.top + space * sina
        print(self.rect.left,self.rect.top, x, y)
    # 展示子弹
    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(self, wall):
                # 修改子弹状态
                self.live = False
                wall.hp -= 1
                # 没血就挂掉了
                if wall.hp <= 0:
                    wall.live = False

    # 双方子弹碰撞
    def hitBullet(self):
        for bullet in MainGame.Enemy_bullet_List:
            if pygame.sprite.collide_rect(bullet, self):  # 监测两个精灵的矩形是否碰撞返回布尔值
                # 如果打中子弹修改状态值
                self.live = False
                bullet.live = False

    # 子弹碰撞水晶
    def hitHome(self):
        if pygame.sprite.collide_rect(self, MainGame.Home):
            # 修改子弹状态
            self.live = False
            # 修改我方水晶状态
            MainGame.Home.live = False

3.8 爆炸类

展示子弹命中后的爆炸效果

class Explode():
    def __init__(self, tank):
        self.rect = tank.rect
        self.step = 0
        self.images = [
            pygame.image.load("images/blast0.gif"),
            pygame.image.load("images/blast1.gif"),
            pygame.image.load("images/blast2.gif"),
            pygame.image.load("images/blast3.gif"),
            pygame.image.load("images/blast4.gif")
        ]
        self.image = self.images[self.step]
        self.live = True

    # 展示爆炸效果
    def displayExplode(self):
        if self.step < len(self.images):
            self.image = self.images[self.step]
            MainGame.window.blit(self.image, self.rect)
            time.sleep(0.03)
            self.step += 1
        else:
            self.live = False
            self.step = 0

3.9 墙壁类

展示墙壁(如想要做红白机中的砖墙和石墙的效果可以参考坦克类实现,素材中也有)

class Wall():
    def __init__(self, left, top):
        self.image = pygame.image.load("images/cement_wall.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)

3.10 水晶类

展示我方小鸟

class Home():
    def __init__(self):
        self.image_symbol = pygame.image.load("images/symbol.gif")
        self.image_symbol_destoryed = pygame.image.load("images/symbol_destoryed.gif")
        self.rect = self.image_symbol.get_rect()
        self.rect.left = MainGame.SCREEN_WIDTH / 2 - self.rect.width / 2
        self.rect.top = MainGame.SCREEN_HEIGHT - self.rect.height
        # 用来判断水晶还在吗
        self.live = True

    def displayHome(self):
        if self.live:
            MainGame.window.blit(self.image_symbol, self.rect)
        else:
            MainGame.window.blit(self.image_symbol_destoryed, self.rect)

3.11 音乐类

播放音乐

class Music():
    def __init__(self, fileName):
        self.fileName = fileName
        # 先初始化混响器
        pygame.mixer.init()
        # 加载音乐文件进行播放
        pygame.mixer.music.load(self.fileName)

    # 开始播放音乐
    def play(self):
        # loops是一个可选的整数参数,默认情况下为0,表示重复音乐的次数(lopps=5,即播放一次重复5次一共6次)。如果此参数设置为-1,则音乐无限重复
        pygame.mixer.music.play(loops=0)

最后调用主类的开始方法即可

if __name__ == '__main__':
    MainGame().startGame()

4. 项目打包

写完之后想给别人玩,但是除了计算机专业很少人会安装python的运行环境,于是将该py文件打包为exe程序
打包问题可以参考我上一个博客,python打包exe

参考文档

官方API: https://www.pygame.org/docs/
c语言中文网: http://c.biancheng.net/pygame/sprite.html


总结

此次项目主要是了解pygame的使用,了解了pygame小游戏的总体运行情况,熟悉了python的一些语法还有一些库并且明白面向对象是什么,提升了编程能力还提高了使用Photoshop的能力。
以下是挺有用的网站:
坦克大战介绍:https://www.retrowan.com/battle-city/
画图的网站:https://mastergo.com/(那些提示图片的制作)
消除图片背景:https://www.remove.bg/zh/upload
视频转gif:https://www.apowersoft.cn/video-to-gif-online
png,jpg,gif转ico:http://www.ico51.cn/ ,https://www.butterpig.top/icopro
当然还有很多。
因为时间有限,很多功能并未完善
游戏的不足:
1)未加菜单功能
2)玩家2P功能没有开通
3)游戏中还有一些小bug由于时间原因没有完善,例如敌方复活位置刚好与我方坦克重叠会卡住双方移动(在演示中有体现)
4)未加分数机制
5)游戏ui较丑
6)地图墙壁设计太差,没有参考坦克大战的地图设计
7)未加关卡功能
8)未加奖励机制,例如吃到道具可以强化强化墙壁或者使用其他类型子弹
9)游戏结束界面比较潦草,仅仅是显示文字而已

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-07-04 22:49:56  更:2022-07-04 22:50:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 11:40:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码