• python图形界面化编程GUI(六)坦克大战(二)


    坦克大战(二)

    完善子弹类

    子弹出现的方向要跟坦克的方向一致,也就是子弹要从坦克的炮嘴里发射出去。
    在这里插入图片描述

    坦克方向朝上的时候:
    子弹出现的左侧位置是坦克距离左边界的位置加上坦克自身宽度的一半,再减去子弹宽度值得一半,也就是挨着炮嘴的位置;
    子弹出现的上侧位置是坦克距离上边界的位置减去子弹的高度值
    坦克方向朝下的时候:
    子弹距离左侧的位置不变
    子弹距离上侧的位置是坦克距离上边界的位置加上坦克的高度值
    坦克方向朝左的时候:
    子弹距离左侧的位置是坦克距离左边界的距离减去子弹高度值
    子弹距离上侧的位置是坦克距离上边界的位置加上坦克自身宽度的一半,再减去子弹宽度值得一半
    坦克方向朝右得时候:
    子弹距离左侧的位置是坦克距离左边界的距离加上坦克的高度值
    子弹距离上侧的位置是上边界的位置加上坦克自身宽度的一半,再减去子弹宽度值得一半
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    # 子弹类
    class Buttet():
        def __init__(self, tank):
            self.image = pygame.image.load('img/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.height
                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.height
                self.rect.top = tank.rect.top + tank.rect.width / 2 - self.rect.width / 2
    
            # 子弹的速度
            self.speed = 6
    
        # 移动
        def move(self):
            if self.direction == 'U':
                if self.rect.top > 0:
                    self.rect.top -= self.speed
                # else:
                #     pass
            elif self.direction == 'D':
                if self.rect.top < MainGame.SCREEN_HEIGHT - self.rect.height:
                    self.rect.top += self.speed
            elif self.direction == 'L':
                if self.rect.left > 0:
                    self.rect.left -= self.speed
            elif self.direction == 'R':
                if self.rect.left < SCREEN_WIDTH - self.rect.width:
                    self.rect.left += self.speed
    
        # 显示子弹
        def displayButtet(self):
            MainGame.window.blit(self.image,self.rect)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    我方坦克发射子弹

    坦克不可能只发射一个子弹,需要先创建子弹的列表
    实现的功能:
    1.我方坦克发射子弹
    2.子弹移动在这里插入图片描述

    # 主类
    class MainGame():
    	# 存储我方子弹的列表
        myBulletList = []
         while True:
         	# 调用显示子弹的方法
                self.showBullet()
            # 展示子弹的方法
        def showBullet(self):
            for myBullet in MainGame.myBulletList:
                myBullet.displayBullet()
                myBullet.move()
       # 获取事件
        def getEvent(self)
        	# 获取所有的事件
            eventList = pygame.event.get() # 获取的是事件列表,并不是唯一的事件,比如上下左右
            # 遍历出每一个事件
            for event in eventList:
                # 判断按下的是关闭键还是键盘
                if event.type == pygame.QUIT:
                    self.endGame()  # 执行退出操作
        		elif event.key == pygame.K_SPACE:
                 	print('发射子弹')
                 	# 我方坦克发射子弹
                 	myBullet = Buttet(MainGame.my_tank)
                 	MainGame.myBulletList.append(myBullet)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    子弹消失和数量控制

    刚才代码中,子弹碰到窗口边界并未消失,坦克可以一直发射子弹
    下面代码要实现的功能:
    1.子弹碰到窗口边界后消失
    2.最多可以发射3个子弹,不能一直发射子弹
    需要在代码中增加子弹的状态,正常状态下子弹存活,碰到边界时子弹消失。

    class MainGame():
    	# 展示子弹的方法
        def showBullet(self):
            for myBullet in MainGame.myBulletList:
                # 增加对子弹状态的判断,是否应该消失
                if myBullet.live: # 如果子弹存活,就正常显示
                    myBullet.displayBullet()
                    myBullet.move()
                else:
                    # 否则,子弹碰到窗口边界,就从列表中删除子弹
                    MainGame.myBulletList.remove(myBullet)
        # 获取事件
        def getEvent(self):
            # 获取所有的事件
            eventList = pygame.event.get() # 获取的是事件列表,并不是唯一的事件,比如上下左右
            # 遍历出每一个事件
            for event in eventList:
                # 判断按下的是关闭键还是键盘
                if event.type == pygame.QUIT:
                    self.endGame()  # 执行退出操作
                # 判断方向键
                elif event.type == pygame.KEYDOWN:
                    # 左
                    if 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_SPACE:
    					 print('发射子弹')
    					 # 如果当前子弹列表长度不大于3,才进行子弹的创建
    					 if len(MainGame.myBulletList) < 3:
    					     # 我方坦克发射子弹
    					     myBullet = Buttet(MainGame.my_tank)
    					     MainGame.myBulletList.append(myBullet)
    # 子弹类
    class Buttet():
        def __init__(self, tank):
     		# 子弹的速度
            self.speed = 6
            # 子弹的状态
            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 == 'D':
                if self.rect.top < 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 < SCREEN_WIDTH - self.rect.width:
                    self.rect.left += self.speed
                else:
                    # 修改子弹的状态值
                    self.live = False	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    敌方坦克发射子弹

    在这里插入图片描述
    在这里插入图片描述

    class MainGame():
    	# 存储我方子弹的列表
        myBulletList = []
        # 存储敌方子弹的列表
        enemyBulletList = []
        # 开始游戏
        def startGame(self): # 方法
        	while True:
        		# 调用显示子弹的方法
                self.showBullet()
                # 调用显示敌方子弹的方法
                self.showEnemyBullet()
       # 展示敌方坦克子弹的方法
        def showEnemyBullet(self):
            for enemyBullet in MainGame.enemyBulletList:
                # 如果子弹的存活状态为真
                if enemyBullet.live:
                    enemyBullet.displayBullet()
                    enemyBullet.move()
                else:
                    MainGame.enemyBulletList.remove(enemyBullet)
        # 展示敌方坦克
        def showEnemyTank(self):
            for enemyTank in MainGame.enemyTankList:
                # 直接调用父类的display()
                enemyTank.displayTank()
                # 坦克移动
                enemyTank.randMove()
                # 创建并发射子弹
                enemyBullet = enemyTank.shot()
                if enemyBullet:
                    # 当子弹能创建成功的时候,再添加到列表,在shot方法里进行了生成子弹的限制
                    MainGame.enemyBulletList.append(enemyBullet)
    # 坦克类
    class Tank():
    	# 射击
        def shot(self):# 需要对射击的方法进行限制,不然坦克会一直发射子弹
            # 用随机数控制敌方坦克偶尔发射子弹
            num = random.randint(1,100)
            if num < 10:
                return Bullet(self)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    我方坦克击杀敌方坦克

    书写一个中间类(精灵类),让坦克类和子弹类都继承自它。在我方子弹类中调用我方子弹碰撞敌方坦克的方法,左上角显示的信息敌方坦克的数量用 敌方坦克的列表的长度替换,可以实现数据的更新

    from pygame.sprite import Sprite
    class BaseItem(Sprite):
        def __init__(self, color, width, height):
            pygame.sprite.Sprite.__init__(self)
    # 主类
    class MainGame():
    	# 开始游戏
        def startGame(self): # 方法
        	 while True:
        	 	# 获取文本的绘制,显示文本和出现的位置
        	 	# 敌方坦克的数量用 坦克列表的长度表示
                MainGame.window.blit(self.getTextSurface('敌方坦克的数量:%s'% len(MainGame.enemyTankList)),(10,10))
        def showEnemyTank(self):
           for enemyTank in MainGame.enemyTankList:
               # 直接调用父类的display()
               if enemyTank.live:
                   enemyTank.displayTank()
                   # 坦克移动
                   enemyTank.randMove()
                   # 创建并发射子弹
                   enemyBullet = enemyTank.shot()
                   if enemyBullet:
                       # 当子弹能创建成功的时候,再添加到列表,在shot方法里进行了生成子弹的限制
                       MainGame.enemyBulletList.append(enemyBullet)
               else:
                   MainGame.enemyTankList.remove(enemyTank)
         # 展示子弹的方法
        def showBullet(self):
            for myBullet in MainGame.myBulletList:
                # 增加对子弹状态的判断,是否应该消失
                if myBullet.live: # 如果子弹存活,就正常显示
                    myBullet.displayBullet()
                    myBullet.move()
                    # 调用我方子弹碰撞敌方坦克的方法
                    myBullet.myBullet_hit_enemyTank()
                else:
                    # 否则,子弹碰到窗口边界,就从列表中删除子弹
                    MainGame.myBulletList.remove(myBullet)
    # 坦克类
    class Tank(Sprite):
        def __init__(self, left, top):
        	# 坦克移动的开关,按下移动,松开停止
            self.stop = True  # 默认坦克是不动的状态
            # 添加坦克是否存在的属性
            self.live = True  # 默认坦克是存在的
    # 敌方坦克
    class EnemyTank(Tank):
        def __init__(self, left, top,speed):
            # 调用父类的方法
            super().__init__(left, top)
    # 子弹类
    class Bullet(BaseItem):
    	# 我方子弹碰撞敌方坦克
        def myBullet_hit_enemyTank(self):
            for enemyTank in MainGame.enemyTankList:
                # 两个精灵之间的距离检测,返回布尔值
                if pygame.sprite.collide_rect(self, enemyTank):
                    enemyTank.live = False
                    self.live = False
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    爆炸效果的实现

    在窗口中显示爆炸的效果
    在这里插入图片描述

    class MainGame():
    	# 存储爆炸对象的列表
        explodeList = []
    	# 开始游戏
        def startGame(self):
        	while True:
        		# 展示爆炸效果的方法
                self.showExplode()
        def showExplode(self):
        for explode in MainGame.explodeList:
            if explode.live:
                explode.displayExplode()
            else:
                MainGame.explodeList.remove(explode)
    class Bullet(BaseItem):
    	    def myBullet_hit_enemyTank(self):
            for enemyTank in MainGame.enemyTankList:
                if pygame.sprite.collide_rect(self, enemyTank):
                    enemyTank.live = False
                    self.live = False
                    explode = Explode(enemyTank)
                    # 将爆炸对象添加到爆炸列表中
                    MainGame.explodeList.append(explode)
    # 爆炸类
    class Explode():
        def __init__(self, tank):
            # 爆炸位置有当前子弹打中的坦克来决定
            self.rect = tank.rect
            # 获取图片
            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.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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    敌方坦克击杀我方坦克并爆炸

    在这里插入图片描述

    class MainGame():
    	# 开始游戏
        def startGame(self):
        	while True:
        		# 获取绘制文字
                MainGame.window.blit(self.getTextSurface('地方坦克剩余%s' % len(MainGame.enemyTankList)), (10, 10))
                if MainGame.my_tank and MainGame.my_tank.live:
                    MainGame.my_tank.displayTank()
                else:
                    # 删除我方坦克
                    del MainGame.my_tank
                    MainGame.my_tank = None
             	# 调用坦克移动的方法
                if MainGame.my_tank and MainGame.my_tank.live:
                    if not MainGame.my_tank.stop:
                        MainGame.my_tank.move()
         def showEnemyBullet(self):
         	for enemyBullet in MainGame.enemyBulletList:
                # 如果状态是True
                if enemyBullet.live:
                    enemyBullet.displayBullet()
                    enemyBullet.move()
                    # 调用敌方子弹和我方坦克碰撞的方法
                    enemyBullet.enemyBullet_hit_myTank()
                else:
                    MainGame.enemyBulletList.remove(enemyBullet)
        # 获取事件
        def getEvent(self):
        	# 获取所有事件
            eventList = pygame.event.get()
            # 遍历列表
            for event in eventList:
                # 判断按下的键是关闭还是键盘
                # 如果按下的是关闭,关闭窗口
                if event.type == pygame.QUIT:
                    # 退出
                    self.endGame()
                if event.type == pygame.KEYDOWN:
                	 # 坦克存活的状态下才能移动
                    if MainGame.my_tank and MainGame.my_tank.live:
                        # 判断上下左右键
                        # 左
                        if event.key == pygame.K_LEFT:
                            print("坦克向左调头,移动")
                            # 修改坦克方向
                            MainGame.my_tank.direction = 'L'
                            MainGame.my_tank.stop = False
               # 松开方向键,坦克停止移动,修改坦克的开关状态
                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:
                        if MainGame.my_tank and MainGame.my_tank.live:
                            MainGame.my_tank.stop = True
    class Bullet(BaseItem):
    	def myBullet_hit_enemyTank(self):
            for enemyTank in MainGame.enemyTankList:
                if pygame.sprite.collide_rect(self, enemyTank):
                    enemyTank.live = False
                    self.live = False
                    explode = Explode(enemyTank)
                    # 将爆炸对象添加到爆炸列表中
                    MainGame.explodeList.append(explode)
    
    
        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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    我方坦克无限复活

    按下ESC键进行重新生成我方坦克
    在这里插入图片描述

    class MainGame():
        def createMyTank(self):
            MainGame.my_tank = Tank(450, 500)
        # 获取事件
        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:
                        if event.key == pygame.K_ESCAPE:
                            self.createMyTank()
                    if MainGame.my_tank and MainGame.my_tank.live:
                        # 左
                        if event.key == pygame.K_LEFT:
                            # 切换方向
                            MainGame.my_tank.direction = 'L'
                            # 更改移动开关
                            MainGame.my_tank.stop = False # 按下按键的时候,解除停止的状态
                            # MainGame.my_tank.move()  # 实现坦克按下移动,松开停止,要把单个方向的移动禁用掉
                            print('按下左键,向左移动')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
  • 相关阅读:
    ubuntu20.04 nerf开山之作
    【python】(九)python的模块与包
    OpenWrt 20.02.2 小米路由器3G配置CP1025网络打印
    新手使用php7的加密方法来保护代码的安全性
    【java学习】类的成员之三:构造方法(即构造器)(25)
    Rocky/GNU之Zabbix部署(3)
    前端开发:$nextTick()的使用及原理
    Vue根据条件更改列表明细某一行的背景颜色-简单实现
    贪吃蛇游戏
    JS - 以工厂模式和原型模式方式建造对象、JS的垃级回收机制、数组的使用
  • 原文地址:https://blog.csdn.net/hwwaizs/article/details/125636549