坦克大战小游戏的实现

简介: 坦克大战小游戏的实现

坦克大战小游戏的实现

1 设计任务

1.1设计目的

运用所学Python知识,完成坦克大战小游戏,通过实践加强对所学知识的理解和巩固。

1.2设计内容

坦克大战小游戏

1.3设计指标或者要求

坦克可以自由的移动和进行射击,敌方坦克消灭完即为胜利,已方坦克被击毁或者己方大本营被摧毁,即为游戏失败。

2 设计过程

游戏基本规则:按上下左右键移动我方坦克,按空格键进行发射子弹,击中坦克,坦克爆炸消失。若我方坦克被子弹击中或撞上,我方坦克死亡按ESC键可以重生。

敌方坦克功能:白色敌方坦克为一般坦克。白色较小敌方坦克速度快,射击子弹频繁。绿色坦克为我方坦克。

地图:白色“铁”墙壁,子弹不能穿过,坦克不能穿过。黑色“地图”子弹和坦克均可以穿过此地图。

程序包含六个类:主逻辑类(MainGame)、坦克类(Tank1包含敌方坦克类(EnemyTank)和我方坦克类(myTank))、子弹类(Bullet)、 爆炸效果类(Explode),墙壁类(Wall)、音效类(Music)。

2.1 开发环境

1、开发工具:pycharm 2020

2、开发环境:python 3.7.9

3、第三方模块:pygame

在联网的情况下,打开终端,输入pip install pygame,即可安装成功。

2.2程序基本流程

1、运行:run “Main_Game.py”,进入初始化界面

2、初始化:显示窗口大小及内容、加载图片和背景音乐,开始游戏。

3、游戏控件:玩家可以通过键盘和空格键来完成移动坦克,射击子弹。还可通过按ESC键重生

4、游戏结束:关闭窗口

2.3程序界面的展示

2.3.1开始游戏界面

2.3.2结束游戏界面

3各功能模块代码实现

模块导入:import random

import pygame,time

图片素材文件存入项目下的img文件夹

.1主逻辑类(MainGame)
主要是游戏窗口的创建和调用其他类中方法的实现,并定义getEvent方法来获取程序期间的所有事件(鼠标事件,键盘事件),通过键盘操作不同的按键来执行不同的操作。
class MainGame():
    # 显示主窗口
    window = None
    SCREEN_height = 700
    SCREEN_width = 1000
    #创建我方坦克
    Tank_P1=None
    #存储所有敌方坦克
    EnemyTank_list=[]
    #要创建的地方坦克的数量
    EnemyTank_count=5
    #存储我方子弹的列表
    Bullet_list=[]
    #存储敌方坦克列表
    Enemy_Bullet_list=[]
    #爆炸效果列表
    Explode_list=[]
    #创建墙壁列表
    Wall_list=[]
    #创建我方老鹰
    Glede_P1=None
    #我方坦克的生命值
    MyT_liveCount=5
    # 开始游戏方法
    def startGame(self):
        pygame.display.init()
        #创建窗口加载窗口(借鉴官方文档)
        MainGame.window = pygame.display.set_mode([MainGame.SCREEN_width, MainGame.SCREEN_height])
        #创建我方坦克
        self.CreatMyTank()
        #创建敌方坦克
        self.creatEnemyTank()
        #创建墙壁
        self.creatWall()
        #初始化glede方法
        MainGame.Glede_P1=glede()
        # 设置一下游戏标题
        pygame.display.set_caption("坦克大战v1.0")
        # 让窗口持续刷新
        while True:
            # 给窗口一个刷新的颜色
            MainGame.window.fill(COLOR_BLACK)
            #在循环中持续完成事件的获取
            self.getEvent()
            #将绘制文字的小画布黏贴到窗口中
            MainGame.window.blit(self.getTextSurface("剩余敌方坦克%d辆"%len(MainGame.EnemyTank_list)),(5,5))
            if len(MainGame.EnemyTank_list)==0:
                MainGame.window.blit(self.getTextSurface2("你赢了!"), (420, 240))
            if MainGame.Glede_P1 and MainGame.Glede_P1.live==True:
                # 将我方的老鹰展示到窗口中
                self.Glede_P1.displayGlede()
            else:
                del MainGame.Glede_P1
                MainGame.Glede_P1 = None
                 # 展示结束图片效果
                self.displayEndGame()
            if MainGame.Tank_P1 and MainGame.Tank_P1.live==True:
                # 将我方坦克加入到窗口中
                MainGame.Tank_P1.displayTank()
            else:
                del MainGame.Tank_P1
                MainGame.Tank_P1=None
                if MainGame.Glede_P1 and MainGame.Glede_P1.live and MainGame.MyT_liveCount>0 and len(MainGame.EnemyTank_list)>0:
                    MainGame.window.blit(self.getTextSurface1("剩余生命数%d,按ESC键重生!" %MainGame.MyT_liveCount ),(330, 250))
                else:
                    # 展示结束图片效果
                    self.displayEndGame()
#判断事件类型是否为按键按下,如果是,继续判断是哪一个按键,来进行对应的处理    if event.type==pygame.KEYDOWN:
                  if MainGame.Tank_P1 and MainGame.Tank_P1.live and MainGame.Glede_P1 and MainGame.Glede_P1.live:
                    # 具体按哪一个键的处理
                    if event.key == pygame.K_LEFT:
                        print("坦克向左调头移动")
                        # 修改坦克方向
                        MainGame.Tank_P1.direction = 'L'
                        # 完成移动操作(调用坦克移动方法)
                        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("子弹数量不足")
            # 松开按键时坦克停止移动
            if event.type == pygame.KEYUP:
                #松开的是方向键才停止移动
                if event.key==pygame.K_LEFT or event.key==pygame.K_UP or event.key==pygame.K_DOWN or event.key==pygame.K_RIGHT:
                    if MainGame.Tank_P1 and MainGame.Tank_P1.live:
                        # 修改坦克的状态
                        MainGame.Tank_P1.stop = True
    #左上角文字绘制功能
    def getTextSurface(self,text):
        #初始化字体模块
        pygame.font.init()
        #选中一个合适的字体
        font=pygame.font.SysFont('kaiti',18)
        #使用对应的字符完成相关内容的绘制
        textSurface=font.render(text,True,COLOR_RED)
        return textSurface
    def getTextSurface1(self, text):
        # 初始化字体模块
        pygame.font.init()
        # 选中一个合适的字体
        font = pygame.font.SysFont('kaiti', 28)
        # 使用对应的字符完成相关内容的绘制
        textSurface1 = font.render(text, True, COLOR_BLUE)
        return textSurface1
    def getTextSurface2(self, text):
        # 初始化字体模块
        pygame.font.init()
        # 选中一个合适的字体
        font = pygame.font.SysFont('kaiti', 35)
        # 使用对应的字符完成相关内容的绘制
        textSurface1 = font.render(text, True, COLOR_RED)
        return textSurface1
    # 结束游戏方法
    def endGame(self):
        print("Game over!!!")
        # 结束python解释器
        exit()
    #展示结束游戏图片
    def displayEndGame(self):
        self.image1=pygame.image.load("img/GameOver.jpg")
        #图片所在区域
        self.rect=self.image1.get_rect()
        self.rect.left=210
        self.rect.top=110
        MainGame.window.blit(self.image1, self.rect)
3.2坦克类(Tank1,myTank,EnemyTank)
class Tank1(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]
        #坦克所在区域
        self.rect=self.image.get_rect()
        #指定坦克初始化位置 分别距X,Y轴的位置
        self.rect.left=left
        self.rect.top=top
        #速度属性
        self.speed=5
        #坦克的移动开关
        self.stop=True
        #新增步数属性
        self.step=15
        #新增属性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
        【省略其他方向移动的代码】
    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(Tank1):
    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(Tank1):
    def __init__(self,left,top,speed):
        super(EnemyTank,self).__init__(left,top)
        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]
        # 坦克所在区域
        self.rect = self.image.get_rect()
        # 指定坦克初始化位置 分别距X,Y轴的位置
        self.rect.left = left
        self.rect.top = top
        # 速度属性
        self.speed = speed
        # 坦克的移动开关
        self.stop = True
        #步数属性
        self.step=35
    #判断方向
    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 randMove(self):
        if self.step <= 0:
            self.direction = self.randDirection()
            self.step = 35
        else:
            self.move()
            self.step -= 1
    #展示敌方坦克
    def displayEnemyTank(self):
        super().displayTank()
    #敌方坦克发射子弹的概率
    def shot(self):
        num=random.randint(0,1000)
        if num<=20:
            return Bullet(self)
    #敌方坦克碰到我方坦克时让其停下来
    def hitMyTank(self):
        if MainGame.Tank_P1 and MainGame.Tank_P1.live:
            if pygame.sprite.collide_rect(selfMainGame.Tank_P1):
                self.stay()
3.3子弹类(Bullet)
class Bullet(BaseItem):
    def __init__(self,tank):
        #子弹速度属性
        self.speed=7
        #子弹是否活着
        self.live=True
        #图片
        self.image=pygame.image.load("img/enemymissile.gif")
        #方向
        self.direction=tank.direction
        #位置
        self.rect=self.image.get_rect()
    #子弹的移动方法
    def BulletMove(self):
    跟坦克移动方法类似
    #展示子弹的方法
    def dispalyBullet(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
3.4爆炸效果类(Explode)
class Explode():
    def __init__(self,tank):
        self.rect=tank.rect
        self.step=0
        self.live=True
        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]
    #展示爆炸效果
    def displayExplode(self):
        if self.step<len(self.images):
            MainGame.window.blit(self.image,self.rect)
            self.step+=1
        else:
            self.live=False
            self.step=0
3.5墙壁类(Wall)
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)
3.6音效类(Music)
class Music():
    def __init__(self, fileName):
        self.fileName = fileName
        # 初始化混合器
        pygame.mixer.init()
  #导入音效文件
        pygame.mixer.music.load(self.fileName)
    # 开始播放音乐
    def play(self):
        pygame.mixer.music.load(self.fileName)

4 软件设计过程中遇到的问题以及解决办法

4.1我方子弹发射数量问题

如果只定义一个子弹属性的话,则玩来玩去只是一枚子弹,我们这时需要用容器。

在MainGame类属性中添加一个Bullet_list=[]用于存储子弹列表,然后在MainGame中的blitBullet方法中将其遍历,并将子弹加入到窗口中。

当然,我们也要在blitmyTank方法中遍历MainGame.myTank_list列表,并将子弹存储在我方坦克列表,其代码为MainGame.my_Bullet_list.append(eBullet),即可发射多枚子弹,但我们就游戏体验来说最好将子弹发射数量设置为每次只能发送3颗,以维持游戏的平衡。


4.2坦克移动问题

先用pygame.event.get()方法获取到程序期间的所有事件,然后赋值给eventList,遍历这个列表,对不同的键盘按键操作进行不同的处理。当按下上下左右键时,调用不同的方法,根据按键的不同,展示不同方向的坦克,当持续按一个方向键时,让坦克朝着这个方向按给定的速度进行平移,以达到坦克移动方法的实现。

4.3我方子弹与敌方坦克碰撞问题

我方子弹碰撞敌方坦克时,我方子弹和敌方坦克应均处于死亡(属性live=False)状态,要实现这个效果,即要调用pygame模块里的精灵类sprite,首先创建一个类BaseItem使其继承于精灵类,然后让Tank1类和Bullet类继承于BaseItem类,并用模块中的pygame.sprite.collide_rect方法检测两个精灵的碰撞,如果我方子弹,碰撞到了敌方坦克,即将敌方坦克的live属性改成False,即敌方坦克便不会显示在窗口中。


这里是引用

程序源码下载链接:https://download.csdn.net/download/qq_41787812/19967878


相关文章
|
2月前
|
Java Android开发
大鱼吃小鱼【小游戏】
大鱼吃小鱼【小游戏】
101 0
|
10月前
|
Python
实现一个2048小游戏
要实现一个2048小游戏,你需要使用Python编程语言和图形用户界面(GUI)库。下面是一个使用Tkinter库来创建2048小游戏的基本步骤
446 3
|
12月前
10点小游戏 2021-04-22
10点小游戏 2021-04-22
113 0
点这里,玩小蚂蚁的小游戏
对于很多人来说(比如说我自己),平时没有大段的时间和精力去玩一个大游戏,这些人需要一些简单好玩的小游戏,拿起来就能玩几下,在忙碌的生活中寻求片刻的放松,随时又可以放下,继续回归到生活。如果你也是这些人的话,那么这些小游戏就是为你而做的,希望你能够喜欢。
89 0
点这里,玩小蚂蚁的小游戏
小蚂蚁的小游戏系列
对于很多人来说(比如说我自己),平时没有大段的时间和精力去玩一个大游戏,这些人需要一些简单好玩的小游戏,拿起来就能玩几下,在忙碌的生活中寻求片刻的放松,随时又可以放下,继续回归到生活。如果你也是这些人的话,那么这些小游戏就是为你而做的,希望你能够喜欢。
83 0
小蚂蚁的小游戏系列
|
算法
2048小游戏(变态版哦)
2048小游戏(变态版哦)
207 0
推箱子小游戏(c++实现)
推箱子小游戏(c++实现)
做个不一样的小游戏
,我发布了“微信小游戏实战系列”的第一篇文章,也是我的第一个小游戏正式开始制作的时间,之前它只是一个脑袋中的想法,大概类似于这样:我能不能试着做这样的一系列的游戏呢?它们有着经典的玩法,不会过时,仍然有着很多的受众,如果我把一个经典的小游戏做成一个精品的小游戏,是否是有价值的,甚至能产生商业价值?
121 0
|
C语言
QAQ的小游戏
QAQ的小游戏
|
小程序
如何制作一个塔防小游戏(三)
嗨!大家好,我是小蚂蚁。今天我们继续分享制作一个塔防小游戏的第三节,如何创建不同类型的敌人,以及如何利用表格来编辑数据以及创建敌人。
110 0