会员可以在此提问,百战程序员老师有问必答
对大家有帮助的问答会被标记为“推荐”
看完课程过来浏览一下别人提的问题,会帮你学得更全面
截止目前,同学们一共提了 132360个问题
Python 全系列/第二阶段:Python 深入与提高/GUI编程(隐藏) 1067楼
Python 全系列/第二阶段:Python 深入与提高/坦克大战 1069楼
Python 全系列/第二阶段:Python 深入与提高/文件处理 1071楼
Python 全系列/第二阶段:Python 深入与提高/坦克大战 1072楼
Python 全系列/第二阶段:Python 深入与提高/模块 1073楼
Python 全系列/第二阶段:Python 深入与提高/文件处理 1076楼

import pygame,time,random
#设置屏幕初始化宽高度
#定义常量
from pygame.sprite import Sprite

screen_width=700
screen_height=500
bg_color=pygame.Color('green')
Text_color=pygame.Color('black')
'''23新增功能
敌我双方坦克发生碰撞
1我方坦克与敌方坦克发生碰撞 不能移动也就是调用stay()方法
我方坦克不能继续移动
2敌方坦克与我方坦克发生碰撞
敌方坦克不能移动
'''
#www.pygame.org
# 分析坦克大战游戏中的需求
# 主类 定义初始化方法
class BaseItem(Sprite):
    def __init__(self,color,width,height):
        pygame.sprite.Sprite.__init__(self)
class MainGame():
    #定义一个窗口对象让pygame返回,定义一个window,初始化为None
#因为Window是类对象,所以我们在调用的时候要用类名MainGame.Window来接收
    Window=None
#和我们的Window对象一样,my_tank要在多个地方进行使用,所以把它定义成类变量
    my_tank=None
#生成一堆坦克创建存储敌方坦克的列表
    enemyTanklist=[]
# 还要定义生成的敌方坦克的数量,我们定义两个类变量,初始化时生成5个坦克
    enemyTankCount=5
    #存储我方坦克子弹的列表
    myBulletlist=[]
    #定义存储敌方子弹的列表
    enemyBulletlist=[]
    #存储爆炸效果的列表
    explodelist=[]
    #创建存储墙壁的列表,在下面创建初始化墙壁[敌我坦克初始化那里]
    walllist=[]
    def __init__(self):
        pass

    # 开始游戏
    def startGame(self):
        #初始化窗口
        pygame.display.init()
        # 加载主窗口
        MainGame.Window=pygame.display.set_mode([screen_width,screen_height])
        #循环一直进行窗口显示、捕获,窗口显示功能方法在pygame里
        #初始化我方坦克,只创建一次 不需要一直创建
        pygame.display.set_caption('杜春雨的坦克大战')
#屏幕的宽度和高度取一半,让它初始化在屏幕的中间
#MainGame.my_tank=Tank(350,250)这句话的意思就是创建我方坦克,出生地
        self.createmytank()
        MainGame.my_tank=Tank(350,290)
        # 初始化敌方坦克,并将敌方坦克添加到列表中
        self.createEnemyTank()
        #初始化墙壁
        self.createwall()
        while True:
            #使坦克的移动速度慢一点 睡眠
            time.sleep(0.02)
            #给当前窗口设置填充色
    #调用当前窗口,当前set_mode返回的就是一个surface对象
            #MainGame.Window是大的suiface
            MainGame.Window.fill('green')
            #绘制文字return textsurface是小的surface,
            #我们要将它存放在大的surface里也就是Window窗口
            #加载窗口时加载一次绘制一次,所以要在循环里面
            #调用绘制文字的方法blit添加主窗口
            #"剩余地方坦克数量:{}".format(6)
    #self.getTextSuface是一个源,也就是blit方法内的source,(10,10)是dest
            #优化敌方坦克剩余显示,%len列表进行数量显示
            MainGame.Window.blit(self.getTextSuface('敌方坦克剩余数量%d'%len(MainGame.enemyTanklist)),(10,10))
            #调用getEvent,实现关闭功能
            self.getEvent()
            #对my_tankan初始化用类名点,不停地进行显示
            #对我方坦克添加判断是否是存活,如果是存活就让他进行显示
            if MainGame.my_tank and MainGame.my_tank.live:
                MainGame.my_tank.displayTank()
            else:
                #删除我方坦克
                del MainGame.my_tank
                #再将它的值赋给None
                MainGame.my_tank=None
            #循环遍历敌方坦克列表,展示敌方坦克
            self.blitEnemyTank()
            #循环遍历我方子弹列表,展示我方子弹
            self.blitMyBullet()
#循环遍历敌方子弹列表,展示敌方子弹,再去定义一个blitEnemyBullet方法
            #与循环遍历我方子弹列表是一样的
            self.blitEnemyBullet()
            #循环遍历爆炸列表,展示爆炸效果
            self.blitExplode()
            #循环遍历墙壁列表,展示墙壁
            self.blitwall()
            #调用移动方法,但这里是一直移动,没有按下松开移动的效果
            #这里不能直接调用,要添加一个判断,
            #如果坦克的方向的开关开启,才可以移动
    #如果stop的值是True那么代表它是要停止的,所以我们要在前面加一个not
            #这里也需要加一个判断 坦克是否存活
            if MainGame.my_tank and MainGame.my_tank.live:
                if not MainGame.my_tank.stop:
    #什么时候要移动呢?就我们按下键的时候,我们去修改当前坦克的移动
                    MainGame.my_tank.move()
                    #检测我方坦克是否与墙壁发生碰撞
                    MainGame.my_tank.hitwall()
                    #检测我方坦克是否与敌方坦克发生碰撞
                    MainGame.my_tank.myTank_hit_enemyTank()
            pygame.display.update() #一直更新上面的配置
    #创建循环遍历墙壁列表,展示墙壁
    def blitwall(self):
        #循环遍历到列表
        for wall in MainGame.walllist:
            #判断墙壁是否存活
            if wall.live:
                #如果存活我们才调用墙壁的显示方法
                wall.displayWall()
            else:
                #从墙壁列表移除
                MainGame.walllist.remove(wall)
    #初始化墙壁
    def createwall(self):
    #我们要创建的墙壁是多个,所以要做一个循环,窗口宽度是700,我们要创建6个
        #那么i的值就是0-5
        for i in range(6):
        #初始化墙壁
            wall=Wall(i*130,220)
        #将墙壁添加到列表中,创建出的wall添加到列表中
            MainGame.walllist.append(wall)
    #创建初始化我方坦克的方法
    def createmytank(self):
        MainGame.my_tank=MyTank(350,290)
    # 初始化敌方坦克,并将敌方坦克添加到列表中
    def createEnemyTank(self):
        top=100
    #循环生成敌方坦克,这个比较好理解因为他的变量上面给赋值了写成5也是可以的
        for i in range(MainGame.enemyTankCount):
        #对left的值进行随机处理随机为0,600,因为不能超出我们的宽度
            left=random.randint(0,600)
            #将speed的值进行随机处理,随机为1,10
            speed=random.randint(1,10)
            enemy=EnemyTank(left,top,speed)
            #把敌方坦克存放到列表
            MainGame.enemyTanklist.append(enemy)
    #循环展示爆炸效果
    def blitExplode(self):
        #循环遍历爆炸效果的列表
        for explode in MainGame.explodelist:
            #判断是否活着,如果爆炸活着
            if explode.live:
                #就让它进行展示
                explode.displayExplode()
            else:
                #如果不是活着的状态就在爆炸列表中移除
                MainGame.explodelist.remove(explode)
    # 循环遍历敌方坦克列表,展示敌方坦克
    def blitEnemyTank(self):
    #循环遍历我们的列表,enemyTank是我们起的名字自定义的可以随意写
        for enemyTank in MainGame.enemyTanklist:
    #先判断当前敌方坦克是否活着,如果活着我们再让它进行显示
            if enemyTank.live:
            #调用它的显示,因为我们当前敌方坦克继承着我们的坦克类
                enemyTank.displayTank()
            #再去显示坦克里调用随机方法
                enemyTank.randmove()
            #检测敌方坦克是否与墙壁发生碰撞
                enemyTank.hitwall()
            #首先判断我方坦克是否为存在存活状态,再进行检测
            if MainGame.my_tank and MainGame.my_tank.live:
            #检测敌方坦克是否与我方坦克发生碰撞
                enemyTank.enemyTank_hit_MyTank()
            #移动完后调用坦克的射击,返回一个enemyBullet敌方的子弹
                enemyBullet=enemyTank.shot()
        #判断敌方坦克是否为None,如果不为None则添加到敌方子弹列表中
                if enemyBullet:
    #返回敌方的坦克同时也有多个子弹,所以我们要创建一个列表变量进行存储敌方子弹
            #存储后我们在遍历敌方坦克列表下面循环遍历敌方子弹的列表
                    MainGame.enemyBulletlist.append(enemyBullet)
            #如果不是存活状态,从敌方坦克列表中移除
            else:
                MainGame.enemyTanklist.remove(enemyTank)

    # 循环遍历我方坦克子弹列表,展示我方坦克子弹
    def blitMyBullet(self):
    # 循环遍历我们的列表,blitMyBullet是我们起的名字自定义的可以随意写
        for myBullet in MainGame.myBulletlist:
            #增加一个判断当前子弹是否是活着状态live=True
            #如果是True则进行显示和移动,
            if myBullet.live:
                #调用它的显示
                myBullet.displayBullet()
                #调用它的移动
                myBullet.move()
            #调用检测我方子弹是否与敌方坦克发生碰撞
                myBullet.myBullet_hit_enemyTank()
            #同理我方子弹检测与墙壁是否发生碰撞
                myBullet.hitWall()
            #否则在列表中删除
            else:
                MainGame.myBulletlist.remove(myBullet)
        #循环遍历敌方子弹列表,展示敌方子弹
    def blitEnemyBullet(self):
        for enemyBullet in MainGame.enemyBulletlist:
        #判断当前敌方子弹的状态,如果它是存活状态就让它进行展示
            if enemyBullet.live:
                enemyBullet.displayBullet()
                #并让子弹进行移动
                enemyBullet.move()
            #调用敌方子弹与我方坦克碰撞的方法
                enemyBullet.enemyBullet_hit_myTank()
            #移动完进行检测敌方子弹是否与墙壁发生碰撞
                enemyBullet.hitWall()
            else:
                #非存活状态就让它在列表内移除
                MainGame.enemyBulletlist.remove(enemyBullet)
    # 结束游戏
    def endGame(self):
        print('感谢使用,欢迎下次再玩')
        exit()
    def getTextSuface(self,text):
        #获取字符Foot对象
        #初始化字体模块
        pygame.font.init()
        #查看所有字体的名称
        #print(pygame.font.get_fonts())
    #获取字体Font对象
        font=pygame.font.SysFont('kaiti',18)
    #绘制文字信息,render()默认方法文本,抗锯齿,颜色,背景
        #textsurface作为接收render返回的surface
        textsurface=font.render(text,True,Text_color)
        #把textsurface方法直接返回
        return textsurface
    #获取事件
    def getEvent(self):
        #获取所有事件
        eventList=pygame.event.get()
        #遍历事件
        for event in eventList:
            #判断我们按下的是关闭还是键盘按键
            #如果按的是退出,则关闭窗口
            if event.type==pygame.QUIT:
                #被循环窗口调用窗口方法中退出
                self.endGame()
                #如果是键盘的按下
            if event.type==pygame.KEYDOWN:
                #当坦克不存在或者死亡
                if not MainGame.my_tank:
                    #判断按下的是否为esc键,如果是让坦克重生
                    if event.key==pygame.K_ESCAPE:
                        #让坦克重生
                        self.createmytank()
    #先判断坦克是否存活再去获取按键,如果非存活那么将无法按下方向键
                if MainGame.my_tank and MainGame.my_tank.live:
                    #判断按下的是上下左右?
                    if event.key==pygame.K_UP:
                    #如果按的是左键,那么我们就切换他的方向
                #切换方向直接调用获取当前坦克的方向并将它的方向改成向左的
                        MainGame.my_tank.direction='U'
                        MainGame.my_tank.stop = False
                        #以及要调用它的移动方法
                        #MainGame.my_tank.move()
                        print('按下的上键,坦克向上移动')
                    elif event.key==pygame.K_LEFT:
                        MainGame.my_tank.direction = 'L'
                        #修改坦克的开关状态
                        MainGame.my_tank.stop=False
                        #MainGame.my_tank.move()
                        print('按下的左键,坦克向左移动')
                    elif event.key==pygame.K_RIGHT:
                        MainGame.my_tank.direction = 'R'
                        MainGame.my_tank.stop = False
                        #MainGame.my_tank.move()
                        print('按下的右键,坦克向右移动')
                    elif event.key==pygame.K_DOWN:
                        MainGame.my_tank.direction = 'D'
                        MainGame.my_tank.stop = False
                        #MainGame.my_tank.move()
                        print('按下的下键,坦克向下移动')
                    elif event.key == pygame.K_SPACE:
                #但按下空格发射子弹后坦克就不能一直移动了
                #我们需要发射子弹时不影响按下的当下键坦克的移动
                        print('发射子弹')

                    #添加一个判断
                #如果当前我方坦克子弹列表的大小,小于等于3时才可以进行创建
                        if len(MainGame.myBulletlist)<3:
                    #创建我方坦克发射的子弹调用Bullte的my_tank并返回myBullte
                    #之后我们还要在MainGame主类里创建一个属性来存储子弹的列表
                            myBullte=Bullet(MainGame.my_tank)
                    #创建子弹后将当前子弹都添加到列表里面
                #添加我方子弹到我方存储的列表里
                #之后我们还要再创建一个方法到While里 与循环显示敌方坦克一样
                            MainGame.myBulletlist.append(myBullte)

        #松开方向键,坦克停止移动,修改坦克的开关状态
        #KEYUP就是弹起松开 KEYDOWN就是按下
            if event.type == pygame.KEYUP:
            #判断松开的键是上、下、左、右时才停止坦克的移动
            #当我们释放空格键的时候是不能影响坦克的移动的
                if event.key == pygame.K_UP or event.key==pygame.K_DOWN or event.key==pygame.K_LEFT or event.key==pygame.K_RIGHT:
                    #如果释放的是我们的上、下、左、右 这时候 我们才让坦克进行停止
#松开方向键的时候我们要修改开关按钮,
# 这时候我们松开按键它就停止移动了因为等于True了
                    #判断我们的坦克是否存在,如果存在判断是否存活
                    if MainGame.my_tank and MainGame.my_tank.live:
                        MainGame.my_tank.stop=True

# 坦克类
#添加初始化属性,距离左边,距离上边
class Tank(BaseItem):
    def __init__(self,left,top):
        #保存加载的图片,同时把加载好的图片放进images字典里面
        #udlr为KEY,值就是我们的图片
        self.images={
            'U':pygame.image.load('image/p1tankU.gif'),
            'D':pygame.image.load('image/p1tankD.gif'),
            'L':pygame.image.load('image/p1tankL.gif'),
            'R':pygame.image.load('image/p1tankR.gif')}
        #方向
        self.direction='U'
        #根据当前图片的方向获取图片  surface
        self.image=self.images[self.direction]
        #根据图片获取矩形区域
        self.rect=self.image.get_rect()
        #设置矩形区域的left和top
        self.rect.left=left
        self.rect.top=top
        #速度决定了移动的快慢
        self.speed=5 #一步走多少个像素
    #新增一个坦克移动的开关属性
        self.stop=True
    #新增坦克是否活着
        self.live=True
        #新增属性记录原来坐标,
        #首先赋值赋到它当前区域的left和top
        self.oldleft=self.rect.left
        self.oldtop=self.rect.top
    # 移动
    def move(self):
        #移动以后我们要将left重新赋在它新的坐标,所以在移动方法里面
        #我们要对oldleft和oldtop再次进行赋值
        #进行移动时修改的就是left和top的值
        #移动后记录原始坐标
        self.oldleft = self.rect.left
        self.oldtop = self.rect.top

        #判断坦克的方向来进行移动,如果当前对象是'l'向左
        if self.direction == 'L':
            if self.rect.left>0:
    #那么我们就向左移动,坦克向左右移动都是修改left的值
    #只不过+left是向右边,-left是向左同理top
    #什么时候让他们移动呢,这就是我们按上下左右键的时候了,也就是我们的事件
                self.rect.left -= self.speed
        elif self.direction == 'U':
    #向上移动时top会进行减少,减少到0的时候,我们就不能让它再移动了
    #所以向上移动,我们做一个判断,如果大于0我们才能让他进行移动
            if self.rect.top>0:
                self.rect.top -= self.speed
        elif self.direction == 'R':
            if self.rect.left + self.rect.height < screen_width:
                self.rect.left +=self.speed
        elif self.direction == 'D':
            if self.rect.top+self.rect.height<screen_height:
                self.rect.top += self.speed
    #定义检测坦克是否与墙壁发生碰撞的方法
    #在坦克类里面写的hitwall所以在我们当前self里面就是我们的坦克

    # 射击
    def shot(self):
        #在射击的方法中让它返回子弹
        #如果当前我这个self是敌方坦克,那么它返回的就是敌方的子弹
        #然后我们回MainGame里面显示敌方坦克列表下调用发射子弹
        return Bullet(self)
    #创建保持原来地方的方法
    def stay(self):
        #当前区域的left设置为我们记录下来的oldleft,top同理
        self.rect.left=self.oldleft
        self.rect.top=self.oldtop
    def hitwall(self):
        #因为墙壁存放在我们当前的列表,所以我们要遍历墙壁列表
        #遍历它逐个进行判断
        for wall in MainGame.walllist:
            # 调用是否发生碰撞,传入第一个坦克,第二个是墙壁
            #如果当前坦克和墙壁发生了碰撞
            if pygame.sprite.collide_rect(self,wall):
                #将坐标设置为移动之前的坐标,也就是将它保持在原来的地方
                self.stay()
    # 坦克的显示
    def displayTank(self):
        #获取展示的对象,根据它的当前方向进行获取带self.image
        self.image=self.images[self.direction]
        #调用blit方法进行展示,展示的对象和矩形区域
        MainGame.Window.blit(self.image,self.rect)

# 我方坦克继承Tank,父类就是Tank
class MyTank(Tank):
    def __init__(self,left,top):
        super(MyTank, self).__init__(left,top)
    #新增方法检测我方坦克与敌方坦克是否发生碰撞
    #写在myTank类里面self就是我方坦克
    #敌方坦克是放在敌方坦克列表的,所以我们要循环遍历敌方坦克列表
    #myTank_hit_enemyTank在坦克进行移动完以后进行检测
    def myTank_hit_enemyTank(self):
        for enemyTank in MainGame.enemyTanklist:
    #逐个进行判断精灵类,调用碰撞方法,当前我方坦克与每一个敌方坦克
            if pygame.sprite.collide_rect(self,enemyTank):
    #如果返回的是True,我们让我方坦克不能继续移动,调用stay方法
                self.stay()

# 敌方坦克,因为有继承关系,所有它们都有移动射击和展示
class EnemyTank(Tank):
    def __init__(self,left,top,speed):
        #调用父类的初始化方法
        super(EnemyTank, self).__init__(left,top)
        #加载图片集
        self.images={
            'U':pygame.image.load('image/enemy1U.gif'),
            'D':pygame.image.load('image/enemy1D.gif'),
            'R':pygame.image.load('image/enemy1R.gif'),
            'L':pygame.image.load('image/enemy1L.gif')}
 #有了图片集 我们还需要方向,敌方坦克每一个都是随机方向的,我们要随机生成
         #方向等于自定义的方法
        self.direction=self.randDirection()
        #从字典中进行获取,根据它的方向获取图片
        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=10
    #敌方坦克与我方坦克是否发生碰撞,
    #写在敌方坦克类self,就是敌方坦克,我方坦克就是MainGame里的对象
    #该方法调用MainGame里面blit坦克类移动完之后调用
    def enemyTank_hit_MyTank(self):
        #直接判断,如果发生碰撞
        if pygame.sprite.collide_rect(self,MainGame.my_tank):
            #敌方坦克则stay暂停
            self.stay()

    #随机生成坦克的方向
    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):
    #随机移动方法判断步数<=0,步数一开始要给定一个,所以要新增一个变量
    #一直在原地改方向:如果小于0就一直在修改方向没有让它进行移动
        if self.step<=0:
#小于等于0时要去修改它的方向,要用self.direction调用它的self.randDirection
        #随机重新赋一个方向
            self.direction=self.randDirection()
#我们还需要让步数复位 重新执行一下,修改方向速度太快,要调整步数大点再修改方向
            self.step=60
        else:
        #直接调用move方法让他进行移动,而且步数要进行递减
            self.move()
            self.step-=1
            #再去显示坦克里调用随机方法
#定义一个shot方法,重写shot,如果子类重写了父类的方法,它调用的就是敌方坦克
    def shot(self):
#随机生成100以内的数字,shot方法是一直被调用的如果小于10再去返回Bullet
        num=random.randint(1,100)
        if num<10:
            return Bullet(self)
#子弹类
class Bullet(BaseItem):
    def __init__(self,tank):
        #加载子弹的图片路径
        self.image=pygame.image.load('image/enemymissile.gif')
#坦克的方向决定了子弹的方向,所以我们创建子弹时要传一个坦克的参数
        #子弹的方向与坦克的方向相等一致
        self.direction=tank.direction
        #获取子弹的区域
        self.rect=self.image.get_rect()
        #子弹的left和top与tank的方向有关
        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 == '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
        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
        #设置一个子弹的速度,然后将子弹进行显示
        self.speed=6
        #设置子弹的状态,是否在墙壁边缘,如果在边缘则修改状态
        self.live=True

    # 子弹移动方法
    def move(self):
    #子弹由坦克方向所趋,所以子弹是由各个方向所移动的
#这是我们获取子弹的方向,子弹的方向是由当前tank方向赋予的
    #如果当前子弹方向是朝上的,我们应该做怎样的处理
        if self.direction == 'U':
            if self.rect.top>0:
                self.rect.top-=self.speed
    #子弹不能移动时修改它的状态,live也就是活着的意思
    #子弹碰撞到墙壁小于0时就进入else了也就消失了
    #回循环遍历去加一个判断MainGameblitMyBullet
            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 + self.rect.height < 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
    #子弹是否碰撞墙壁,self因为是在我们的子弹类,所以self就是我们的子弹
    #我们什么时候调用检测子弹是否与墙壁碰撞的方法呢?
    #展示完敌方子弹和展示完我方子弹都需要进行检测
    #首先打开MainGame里面的blitenemyBullet
    def hitWall(self):
        #因为墙壁存储在我们的列表里面,所以我们要循环遍历我们的墙壁列表
        for wall in MainGame.walllist:
        #在墙壁列表里面我们要判断每一个墙壁是否与当前的子弹进行碰撞
            if pygame.sprite.collide_rect(self,wall):
    #如果返回的是True那代表的是碰撞,碰撞到以后我们要让子弹消失,
    #也是修改子弹的存活状态
                self.live=False
                #每执行,墙壁的生命值减小
                wall.hp-=1
                #如果小于等于0,那么修改墙壁存活状态
                if wall.hp<=0:
                   #修改墙壁的存活状态
                    wall.live=False
    # 显示子弹方法
    def displayBullet(self):
        #将子弹进行显示将图片surface加载到窗口
        #Window大窗口进行blit,第一个目标image,第二个是区域
        MainGame.Window.blit(self.image,self.rect)
    #新增子弹类方法,我方子弹与敌方坦克的碰撞_hit_
    def myBullet_hit_enemyTank(self):
#因为敌方坦克是多个所以我们要循环遍历敌方坦克列表,判断是否发生碰撞
        for enemyTank in MainGame.enemyTanklist:
    #enemyTank与我方自己也就是我方子弹如果发生了碰撞让敌方坦克消失
            if pygame.sprite.collide_rect(enemyTank,self):
           #怎样让坦克消失,修改状态,修改敌方坦克和我方子弹的状态
#因为坦克类是没有live这个属性的,所以我们要在坦克类里添加这个属性
                enemyTank.live=False
                self.live=False
            #创建爆炸对象
                explode=Explode(enemyTank)
            #将爆炸对象添加到爆炸列表中
                MainGame.explodelist.append(explode)

    #定义敌方子弹与我方坦克的碰撞,self是敌方的子弹
    def enemyBullet_hit_myTank(self):
        #如果我方坦克没有了,那么它还需要进行判断是否碰撞
        if MainGame.my_tank and MainGame.my_tank.live:
            if pygame.sprite.collide_rect(MainGame.my_tank,self):
                #如果碰撞了,我们应该产生爆炸对象,位置是我方坦克的位置
                explode=Explode(MainGame.my_tank)
                #将爆炸对象添加到爆炸列表中
                MainGame.explodelist.append(explode)
                #修改敌方子弹与我方坦克的状态
                self.live=False
                MainGame.my_tank.live=False
# 墙壁类
class Wall():
    #墙壁也是一张图片,在加载时都是需要它的坐标的我们要给它指定left和top
    def __init__(self,left,top):
    #加载图片
        self.image=pygame.image.load('image/steels.gif')
    #获取墙壁的区域
        self.rect=self.image.get_rect()
    #设置位置left,top
        self.rect.left=left
        self.rect.top=top
    #墙壁与坦克一样都有是否活着的属性,一开始默认为True
        self.live=True
    #给墙壁设置生命值,这是初始化方法,接下来去显示方法显示
        self.hp=3
    # 显示墙壁类的方法
    def displayWall(self):
    #调用MainGame里面的大窗口对象调用blit,
    # 第一个参数要显示的对象,第二个参数显示的位置
    #因为墙壁是多个,所以我们要创建一个列表
        MainGame.Window.blit(self.image,self.rect)



# 爆炸效果的类
class Explode():
    def __init__(self,tank):
        #爆炸的位置由当前子弹打中的坦克位置决定
        #将坦克的位置给了self.rect也就是爆炸效果这个位置
        self.rect=tank.rect
        #加载爆炸效果
        self.images=[
            pygame.image.load('image/blast0.gif'),
            pygame.image.load('image/blast1.gif'),
            pygame.image.load('image/blast2.gif'),
            pygame.image.load('image/blast3.gif'),
            pygame.image.load('image/blast4.gif'),
        ]
        #定义一个step,初始化是0
        self.step=0
        #获取图片从列表里面获取它的索引,根据索引获取当前要获取的图片
        self.image=self.images[self.step]
        #添加是否活着的状态
        self.live=True
    # 展示爆炸效果的方法
    def displayExplode(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
# 音效类
class Music():
    def __init__(self):
        pass

    # 播放音乐的方法
    def play(self):
        pass
MainGame().startGame()
#MainGame().getTextSuface()

image.png

image.png

老师,我这个代码执行后移动就报错,被敌人打中 就全屏消失这是为啥

Python 全系列/第二阶段:Python 深入与提高/游戏开发-坦克大战 1077楼
Python 全系列/第二阶段:Python 深入与提高/文件处理 1078楼

import pygame
screen_width = 700
screen_height = 400
BG_color = pygame.Color(0, 0, 0)
Text_COLOR = pygame.Color(255, 0, 0)

class MainGame():
    window = None

    def __init__(self):
        pass

    def startGame(self):
        # 初始化显示模块
        pygame.display.init()
        # 初始化显示窗口
        MainGame.window = pygame.display.set_mode([screen_width, screen_height])
        pygame.display.set_caption("坦克大战1.0")
        while True:
            # 给窗口设置填充色
            self.getEvent()
            MainGame.window.blit(self.getTextSurface('剩余敌方坦克数量%d'%6), (10, 10))
            MainGame.window.fill(BG_color)
            pygame.display.update()

    def endGame(self):
        pass

    def getTextSurface(self, text):
# 初始化字体模块
        pygame.font.init()
        # 获取字体font对象
        pygame.font.get_fonts()

        s= pygame.font.SysFont("kaiti", 18)
        #绘制文本信息
        textSurface = s.render(text, True, Text_COLOR)
        return textSurface

    def getEvent(self):
        #获取所有事件
        eventList = pygame.event.get()
        #遍历事件
        for event in eventList:
# 判断按下的
            if event.type == pygame.QUIT:
                exit()



class Tank():
    def __init__(self):
        pass

    def move(self):
        pass

    def shot(self):
        pass

    def display(self):
        pass


# 我方坦克
class MyTank(Tank):
    def __init__(self):
        pass


class EnmeyTank(Tank):
    def __init__(self):
        pass


class Bullet():
    def __init__(self):
        pass

    def move(self):
        pass

    def displayBullet(self):
        pass


class Wall():
    def __init__(self):
        pass

    def displayWall(self):
        pass


class Explode():
    def __init__(self):
        pass

    def displayExplode(self):
        pass


class Music():
    def __init__(self):
        pass

    def playMusic(self):
        pass


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

image.png老师我这段代码没有报错,但是左上角却没有文本信息的显示,新surface没出来啊,帮忙看看,谢谢

Python 全系列/第二阶段:Python 深入与提高/游戏开发-坦克大战 1080楼

课程分类

百战程序员微信公众号

百战程序员微信小程序

©2014-2025百战汇智(北京)科技有限公司 All Rights Reserved 北京亦庄经济开发区科创十四街 赛蒂国际工业园
网站维护:百战汇智(北京)科技有限公司
京公网安备 11011402011233号    京ICP备18060230号-3    营业执照    经营许可证:京B2-20212637