学习 Python 之 Pygame 开发坦克大战(二)

这篇具有很好参考价值的文章主要介绍了学习 Python 之 Pygame 开发坦克大战(二)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

坦克大战的需求

坦克大战游戏包含很多个物体,现在要对这些物体进行总结

类名 包含的操作 包含的属性
敌方坦克类 射击,移动,显示 生命,速度,伤害,方向,类型
我方坦克类 射击,移动,显示 生命,速度,伤害,方向,装甲,等级
子弹类 移动,显示 方向,伤害,发射源,速度
墙壁类、草类、石砖类、河类 显示 是否可以摧毁
音效类 播放,停止,设置音乐 -
爆炸效果类 显示 是否可以摧毁
主类

物体总结完毕后,规划一下窗口的大小,下面是我设置的窗口大小
pythonpygame塔克大战代码,Python,python,pygame,学习
素材链接:百度网盘
链接:https://pan.baidu.com/s/19sCyH7rp37f6DzRj0iXDCA?pwd=tkdz
提取码:tkdz

坦克大战代码链接:百度网盘
链接:https://pan.baidu.com/s/1qFV-0hi0cgZS1Hnvx6mK6Q?pwd=90tk
提取码:90tk

开始编写坦克大战

一切都准备就绪啦,现在开始编写坦克大战的代码吧

1. 搭建主类框架

主类是整个游戏运作的类,当然你也可以不用使用类,直接创建一个函数也可以,这里使用了面向对象的思想

import pygame


SCREEN_WIDTH = 1100
SCREEN_HEIGHT = 600
BACKGROUND_COLOR = pygame.Color(0, 0, 0)
FONT_COLOR = (255, 255, 255)
class MainGame:

    # 窗口Surface对象
    window = None

    def __init__(self):
        pass

    def startGame(self):
        # 初始化展示模块
        pygame.display.init()
        # 设置窗口大小
        size = (SCREEN_WIDTH, SCREEN_HEIGHT)
        # 初始化窗口
        MainGame.window = pygame.display.set_mode(size)
        # 设置窗口标题
        pygame.display.set_caption('Tank Battle')

        while 1:
            # 设置背景颜色
            MainGame.window.fill(BACKGROUND_COLOR)
            # 更新窗口
            pygame.display.update()

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

运行结果
pythonpygame塔克大战代码,Python,python,pygame,学习
主类中运用到的知识,都是学习 Python 之 Pygame 开发坦克大战(一)中所包含的

2. 获取窗口中的事件

坦克大战关键是对玩家自己的坦克进行操控,消灭敌人的坦克,所以键盘事件响应是必不可少的

def getPlayingModeEvent(self):
    # 获取所有事件
    eventList = pygame.event.get()
    for event in eventList:

        if event.type == pygame.QUIT:
            sys.exit()

        if event.type == pygame.KEYDOWN:
            print('键盘按键按下')
            if event.key == pygame.K_w:
                print('w按下')
            elif event.key == pygame.K_s:
                print('s按下')
            elif event.key == pygame.K_a:
                print('a按下')
            elif event.key == pygame.K_d:
                print('d按下')
            elif event.key == pygame.K_j:
                print('j按下')

        if event.type == pygame.KEYUP:
            print('键盘按键抬起')
            if event.key == pygame.K_w:
                print('w抬起')
            elif event.key == pygame.K_s:
                print('s抬起')
            elif event.key == pygame.K_a:
                print('a抬起')
            elif event.key == pygame.K_d:
                print('d抬起')

获取窗口中的事件,用于玩家操控坦克、发射坦克子弹等操作

游戏中,我规定aswd操控坦克,j攻击,当然你也可以上下左右键移动,空格攻击,如果你想设置双人游戏,这也是可以的

import pygame
import sys


SCREEN_WIDTH = 1100
SCREEN_HEIGHT = 600
BACKGROUND_COLOR = pygame.Color(0, 0, 0)
FONT_COLOR = (255, 255, 255)
class MainGame:

    # 窗口Surface对象
    window = None

    def __init__(self):
        pass

    def startGame(self):
        # 初始化展示模块
        pygame.display.init()
        # 设置窗口大小
        size = (SCREEN_WIDTH, SCREEN_HEIGHT)
        # 初始化窗口
        MainGame.window = pygame.display.set_mode(size)
        # 设置窗口标题
        pygame.display.set_caption('Tank Battle')

        while 1:
            # 设置背景颜色
            MainGame.window.fill(BACKGROUND_COLOR)
            
            # 获取窗口事件
            self.getPlayingModeEvent()
            
            # 更新窗口
            pygame.display.update()
            
    def getPlayingModeEvent(self):
        # 获取所有事件
        eventList = pygame.event.get()
        for event in eventList:
            
            if event.type == pygame.QUIT:
                sys.exit()
                
            if event.type == pygame.KEYDOWN:
                print('键盘按键按下')
                if event.key == pygame.K_w:
                    print('w按下')
                elif event.key == pygame.K_s:
                    print('s按下')
                elif event.key == pygame.K_a:
                    print('a按下')
                elif event.key == pygame.K_d:
                    print('d按下')
                elif event.key == pygame.K_j:
                    print('j按下')

            if event.type == pygame.KEYUP:
                print('键盘按键抬起')
                if event.key == pygame.K_w:
                    print('w抬起')
                elif event.key == pygame.K_s:
                    print('s抬起')
                elif event.key == pygame.K_a:
                    print('a抬起')
                elif event.key == pygame.K_d:
                    print('d抬起')

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

3. 创建基类

坦克操控事件完成后,现在就是实现坦克啦,首先场景中的物体都需要发生物体间的碰撞,简单来说就是检测两个屏幕上的图片是否发生了重叠,如果发生了,就要触发一些事件,这里创建ParentObject类,用于继承pygame.sprite.Sprite类

pygame.sprite.Sprite类可以用来检测物体碰撞,是pygame提供的一个类,非常的方便

import pygame.sprite


class ParentObject(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()

4. 初始化我方坦克类

创建我方坦克类,并且继承基类

import pygame as pg
import pygame.image
from ParentObject import ParentObject


class PlayerTank(ParentObject):
    def __init__(self, x, y, order, amour):
        """

        :param x: 坦克横坐标
        :param y: 坦克纵坐标
        :param order: 玩家坦克序号,1表示一号玩家,2表示二号玩家
        :param amour: 坦克初始护甲
        """
        super().__init__()
        self.images = []
        if order == 1:
            self.images.append({
                'UP': pygame.image.load('../Image/Player1/45x45/UP1.png'),
                'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN1.png'),
                'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT1.png'),
                'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT1.png')
            })
            self.images.append({
                'UP': pygame.image.load('../Image/Player1/45x45/UP2.png'),
                'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN2.png'),
                'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT2.png'),
                'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT2.png')
            })
            self.images.append({
                'UP': pygame.image.load('../Image/Player1/45x45/UP3.png'),
                'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN3.png'),
                'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT3.png'),
                'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT3.png')
            })
            self.images.append({
                'UP': pygame.image.load('../Image/Player1/45x45/UP4.png'),
                'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN4.png'),
                'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT4.png'),
                'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT4.png')
            })
            self.images.append({
                'UP': pygame.image.load('../Image/Player1/45x45/UP5.png'),
                'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN5.png'),
                'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT5.png'),
                'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT5.png')
            })
            self.images.append({
                'UP': pygame.image.load('../Image/Player1/45x45/UP6.png'),
                'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN6.png'),
                'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT6.png'),
                'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT6.png')
            })

        # 生命
        self.life = 3
        # 装甲
        self.armor = amour

        # 方向
        self.direction = 'UP'
        
        # 根据护甲选择坦克的样子
        self.image: pg.Surface = self.images[max(self.armor - 1, 0)][self.direction]
        self.rect = self.image.get_rect()
        self.rect.left = x
        self.rect.top = y

        # 速度
        self.accumulation: float = 0
        self.speed = 2
        # 移动开关
        self.stop = True
        

        # 等级
        self.level = 1
        # 伤害
        self.damage = 1

    def move(self):
        pass

    def shot(self):
        pass

    def draw(self):
       pass

5. 完善我方坦克的移动

accumulation 可以更细的控制坦克的移动速度

当 accumulation 累加到 1 时,坦克移动一次,如果不设置这个属性,即使是速度每次 +1,坦克移动的也速度很快,所以增加这个属性,可以减慢坦克的移动速度

def move(self):
    if self.accumulation >= 1:
        self.accumulation = 0
        if self.direction == 'LEFT':
            if self.rect.left > 0:
                self.rect.left -= self.speed
        elif self.direction == 'UP':
            if self.rect.top > 0:
                self.rect.top -= self.speed
        elif self.direction == 'DOWN':
            if self.rect.top < 555:
                self.rect.top += self.speed
        elif self.direction == 'RIGHT':
            if self.rect.left < 855:
                self.rect.left += self.speed
    else:
        self.accumulation += 0.20

这里需要设置坦克的边界范围
防止坦克跑出窗口

坦克的图片是45x45
pythonpygame塔克大战代码,Python,python,pygame,学习

5. 完善我方坦克的显示

坦克的显示就是把坦克的图片显示在窗口中

def draw(self, window):
	# window传入主窗口
	# 坦克生命中为0,表示已经死亡,不再展示坦克
    if self.life <= 0:
        return
    # 获取展示的对象
    self.image = self.images[max(self.armor - 1, 0)][self.direction]
    window.blit(self.image, self.rect)

我方坦克类完整代码

import pygame as pg
import pygame.image
from ParentObject import ParentObject


class PlayerTank(ParentObject):
    def __init__(self, x, y, order, amour):
        """

        :param x: 坦克横坐标
        :param y: 坦克纵坐标
        :param order: 玩家坦克序号,1表示一号玩家,2表示二号玩家
        :param amour: 坦克初始护甲
        """
        super().__init__()
        self.images = []
        if order == 1:
            self.images.append({
                'UP': pygame.image.load('../Image/Player1/45x45/UP1.png'),
                'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN1.png'),
                'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT1.png'),
                'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT1.png')
            })
            self.images.append({
                'UP': pygame.image.load('../Image/Player1/45x45/UP2.png'),
                'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN2.png'),
                'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT2.png'),
                'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT2.png')
            })
            self.images.append({
                'UP': pygame.image.load('../Image/Player1/45x45/UP3.png'),
                'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN3.png'),
                'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT3.png'),
                'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT3.png')
            })
            self.images.append({
                'UP': pygame.image.load('../Image/Player1/45x45/UP4.png'),
                'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN4.png'),
                'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT4.png'),
                'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT4.png')
            })
            self.images.append({
                'UP': pygame.image.load('../Image/Player1/45x45/UP5.png'),
                'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN5.png'),
                'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT5.png'),
                'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT5.png')
            })
            self.images.append({
                'UP': pygame.image.load('../Image/Player1/45x45/UP6.png'),
                'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN6.png'),
                'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT6.png'),
                'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT6.png')
            })

        # 生命
        self.life = 3
        # 装甲
        self.armor = amour

        # 方向
        self.direction = 'UP'

        # 根据护甲选择坦克的样子
        self.image: pg.Surface = self.images[max(self.armor - 1, 0)][self.direction]
        self.rect = self.image.get_rect()
        self.rect.left = x
        self.rect.top = y

        # 速度
        self.accumulation: float = 0
        self.speed = 2
        # 移动开关
        self.stop = True

        # 碰撞前的坐标
        self.prvX = self.rect.left
        self.prvY = self.rect.top

        # 等级
        self.level = 1
        # 伤害
        self.damage = 1

    def move(self):
        if self.accumulation >= 1:
            self.accumulation = 0
            if self.direction == 'LEFT':
                if self.rect.left > 0:
                    self.rect.left -= self.speed
            elif self.direction == 'UP':
                if self.rect.top > 0:
                    self.rect.top -= self.speed
            elif self.direction == 'DOWN':
                if self.rect.top < 555:
                    self.rect.top += self.speed
            elif self.direction == 'RIGHT':
                if self.rect.left < 855:
                    self.rect.left += self.speed
        else:
            self.accumulation += 0.20


    def shot(self):
        pass

    def draw(self, window):
        # 坦克生命中为0,表示已经死亡,不再展示坦克
        if self.life <= 0:
            return
        # 获取展示的对象
        self.image = self.images[max(self.armor - 1, 0)][self.direction]
        # 画出图片
        window.blit(self.image, self.rect)

6. 在主类中加入我方坦克并完成坦克移动

我方坦克类中移动和显示函数实现后,就要让它们在主类中调用

添加类变量playerTank,用于存放我方坦克的对象

修改循环中的代码

while 1:
            # 设置背景颜色
            MainGame.window.fill(BACKGROUND_COLOR)

            # 获取窗口事件
            self.getPlayingModeEvent()

            # 显示我方坦克
            MainGame.playerTank.draw(MainGame.window)

            # 我方坦克移动
            if not MainGame.playerTank.stop:
                MainGame.playerTank.move()

            # 更新窗口
            pygame.display.update()

完整我方坦克类代码

import pygame
import sys

from PlayerTank import PlayerTank

SCREEN_WIDTH = 1100
SCREEN_HEIGHT = 600
BACKGROUND_COLOR = pygame.Color(0, 0, 0)
FONT_COLOR = (255, 255, 255)
PLAYER_TANK_POSITION = (325, 550)

class MainGame:

    # 窗口Surface对象
    window = None

    # 玩家坦克
    playerTank = None

    def __init__(self):
        pass

    def startGame(self):
        # 初始化展示模块
        pygame.display.init()
        # 设置窗口大小
        size = (SCREEN_WIDTH, SCREEN_HEIGHT)
        # 初始化窗口
        MainGame.window = pygame.display.set_mode(size)
        # 设置窗口标题
        pygame.display.set_caption('Tank Battle')

        # 初始化我方坦克
        MainGame.playerTank = PlayerTank(PLAYER_TANK_POSITION[0], PLAYER_TANK_POSITION[1], 1, 1)

        while 1:
            # 设置背景颜色
            MainGame.window.fill(BACKGROUND_COLOR)

            # 获取窗口事件
            self.getPlayingModeEvent()

            # 显示我方坦克
            MainGame.playerTank.draw(MainGame.window)

            # 我方坦克移动
            if not MainGame.playerTank.stop:
                MainGame.playerTank.move()

            # 更新窗口
            pygame.display.update()
            
    def getPlayingModeEvent(self):
        # 获取所有事件
        eventList = pygame.event.get()
        for event in eventList:

            if event.type == pygame.QUIT:
                sys.exit()

            """
            stop属性用来控制坦克移动,当键盘按键按下时,坦克可以移动,一直按住一直移动,当按键抬起时,停止移动
            如果没有该属性,按一下按键移动一次,按一下移动一下,不能一直按住一直移动
            """
            if event.type == pygame.KEYDOWN:
                print('键盘按键按下')
                if event.key == pygame.K_w:
                    MainGame.playerTank.direction = 'UP'
                    MainGame.playerTank.stop = False
                elif event.key == pygame.K_s:
                    MainGame.playerTank.direction = 'DOWN'
                    MainGame.playerTank.stop = False
                elif event.key == pygame.K_a:
                    MainGame.playerTank.direction = 'LEFT'
                    MainGame.playerTank.stop = False
                elif event.key == pygame.K_d:
                    MainGame.playerTank.direction = 'RIGHT'
                    MainGame.playerTank.stop = False
                elif event.key == pygame.K_j:
                    print('j按下')

            if event.type == pygame.KEYUP:
                print('键盘按键抬起')
                if event.key == pygame.K_w:
                    MainGame.playerTank.stop = True
                elif event.key == pygame.K_s:
                    MainGame.playerTank.stop = True
                elif event.key == pygame.K_a:
                    MainGame.playerTank.stop = True
                elif event.key == pygame.K_d:
                    MainGame.playerTank.stop = True

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

运行结果
pythonpygame塔克大战代码,Python,python,pygame,学习

7. 初始化子弹类

现在已经实现了坦克的移动啦,下面就要实现坦克的发射子弹

实际上,子弹也是一幅图片,当我们按下开火按键后,就在坦克的正前方画出子弹,随着时间的流逝,要让子弹按照当前方向一直运动下去

import pygame
from ParentObject import ParentObject


class Bullet(ParentObject):
    def __init__(self, tank):
        super().__init__()
        self.images = {
            'UP': pygame.image.load('../Image/Bullet/Bullet(UP).png'),
            'DOWN': pygame.image.load('../Image/Bullet/Bullet(DOWN).png'),
            'LEFT': pygame.image.load('../Image/Bullet/Bullet(LEFT).png'),
            'RIGHT': pygame.image.load('../Image/Bullet/Bullet(RIGHT).png')
        }
        # 方向
        self.direction = tank.direction
        self.image: pygame.Surface = self.images[self.direction]
        self.rect = self.image.get_rect()
        
		# 坦克发射子弹的位置
        if self.direction == 'UP':
            self.rect.left = tank.rect.left + 17.5
            self.rect.top = tank.rect.top - 25
        elif self.direction == 'DOWN':
            self.rect.left = tank.rect.left + 17.5
            self.rect.top = tank.rect.top + 25
        elif self.direction == 'LEFT':
            self.rect.left = tank.rect.left - 25
            self.rect.top = tank.rect.top + 17.5
        elif self.direction == 'RIGHT':
            self.rect.left = tank.rect.left + 25
            self.rect.top = tank.rect.top + 17.5

        # 速度
        self.accumulationMax: float = 0
        self.accumulation = 0.25
        self.speed = 10
        # 销毁开关
        self.isDestroy = False
        # 发射源
        self.source = tank
        # 伤害
        self.damage = tank.damage

    def move(self, explodeList):
        pass

    def draw(self, window):
        window.blit(self.image, self.rect)


下面是确定子弹的位置:

子弹图片是25x10,坦克发射子弹是在坦克中间位置发射

pythonpygame塔克大战代码,Python,python,pygame,学习

8. 完善子弹的移动

子弹的初始位置确定后,一旦创建出来,就要一直移动下去,实际上就是刷新屏幕,然后把原来位置上的子弹图片去掉,在新的位置上再画出子弹图片,坦克移动的原理也是这样

修改move函数,添加检查子弹出界函数

    def move(self):
        if self.accumulation >= 1:
            self.accumulation = 0
            if self.direction == 'LEFT':
                self.rect.left -= self.speed
            elif self.direction == 'UP':
                self.rect.top -= self.speed
            elif self.direction == 'DOWN':
                self.rect.top += self.speed
            elif self.direction == 'RIGHT':
                self.rect.left += self.speed
            # 检查子弹是否出界
            self.checkBullet()
        else:
            self.accumulation += 0.20
            
    def checkBullet(self):
        toDestroy = False
        # 如果出界,就设置为销毁
        if self.rect.top < 0 or self.rect.top > 600:
            toDestroy = True
        if self.rect.left < 0 or self.rect.right > 900:
            toDestroy = True
        if toDestroy:
            self.isDestroy = True

子弹类完整代码

import pygame
from ParentObject import ParentObject


class Bullet(ParentObject):
    def __init__(self, tank):
        super().__init__()
        self.images = {
            'UP': pygame.image.load('../Image/Bullet/Bullet(UP).png'),
            'DOWN': pygame.image.load('../Image/Bullet/Bullet(DOWN).png'),
            'LEFT': pygame.image.load('../Image/Bullet/Bullet(LEFT).png'),
            'RIGHT': pygame.image.load('../Image/Bullet/Bullet(RIGHT).png')
        }
        # 方向
        self.direction = tank.direction
        self.image: pygame.Surface = self.images[self.direction]
        self.rect = self.image.get_rect()

        # 坦克发射子弹的位置
        if self.direction == 'UP':
            self.rect.left = tank.rect.left + 17.5
            self.rect.top = tank.rect.top - 25
        elif self.direction == 'DOWN':
            self.rect.left = tank.rect.left + 17.5
            self.rect.top = tank.rect.top + 25
        elif self.direction == 'LEFT':
            self.rect.left = tank.rect.left - 25
            self.rect.top = tank.rect.top + 17.5
        elif self.direction == 'RIGHT':
            self.rect.left = tank.rect.left + 25
            self.rect.top = tank.rect.top + 17.5

        # 速度
        self.accumulationMax: float = 0
        self.accumulation = 0.25
        self.speed = 10
        # 销毁开关
        self.isDestroy = False
        # 发射源
        self.source = tank
        # 伤害
        self.damage = tank.damage

    def move(self):
        if self.accumulation >= 1:
            self.accumulation = 0
            if self.direction == 'LEFT':
                self.rect.left -= self.speed
            elif self.direction == 'UP':
                self.rect.top -= self.speed
            elif self.direction == 'DOWN':
                self.rect.top += self.speed
            elif self.direction == 'RIGHT':
                self.rect.left += self.speed
            # 检查子弹是否出界
            self.checkBullet()
        else:
            self.accumulation += 0.20

    def checkBullet(self):
        toDestroy = False
        # 如果出界,就设置为销毁
        if self.rect.top < 0 or self.rect.top > 600:
            toDestroy = True
        if self.rect.left < 0 or self.rect.right > 900:
            toDestroy = True
        if toDestroy:
            self.isDestroy = True

    def draw(self, window):
        window.blit(self.image, self.rect)


9. 完善坦克开火

有了子弹类,就可以让坦克发射子弹了

在主类中设置玩家子弹数量的最大值

... ...

class MainGame:

    # 窗口Surface对象
    window = None
 	# 指定的子弹个数,这里设置玩家的子弹最多只有3颗子弹可以同时在场
    playerBulletNumber = 3
    
    # 玩家坦克
    playerTank = None
    
	... ...

修改坦克的 shot() 函数

def shot(self):
    return Bullet(self)

修改 getPlayingModeEvent() 函数
当 j键按下,发射子弹

    def getPlayingModeEvent(self):
        # 获取所有事件
        eventList = pygame.event.get()
        for event in eventList:

            if event.type == pygame.QUIT:
                sys.exit()

            """
            stop属性用来控制坦克移动,当键盘按键按下时,坦克可以移动,一直按住一直移动,当按键抬起时,停止移动
            如果没有该属性,按一下按键移动一次,按一下移动一下,不能一直按住一直移动
            """
            if event.type == pygame.KEYDOWN:
                print('键盘按键按下')
                if event.key == pygame.K_w:
                    MainGame.playerTank.direction = 'UP'
                    MainGame.playerTank.stop = False
                elif event.key == pygame.K_s:
                    MainGame.playerTank.direction = 'DOWN'
                    MainGame.playerTank.stop = False
                elif event.key == pygame.K_a:
                    MainGame.playerTank.direction = 'LEFT'
                    MainGame.playerTank.stop = False
                elif event.key == pygame.K_d:
                    MainGame.playerTank.direction = 'RIGHT'
                    MainGame.playerTank.stop = False
                elif event.key == pygame.K_j:
                    # 判断子弹数量是否超过指定的个数
                    if len(MainGame.playerBulletList) < MainGame.playerBulletNumber:
                        bullet = MainGame.playerTank.shot()
                        MainGame.playerBulletList.append(bullet)

            if event.type == pygame.KEYUP:
                print('键盘按键抬起')
                if event.key == pygame.K_w:
                    MainGame.playerTank.stop = True
                elif event.key == pygame.K_s:
                    MainGame.playerTank.stop = True
                elif event.key == pygame.K_a:
                    MainGame.playerTank.stop = True
                elif event.key == pygame.K_d:
                    MainGame.playerTank.stop = True

子弹有了,但是没有显示在窗口,此时写一个函数让子弹在窗口显示出来

def drawPlayerBullet(self, playerBulletList):
	# 遍历整个子弹列表,如果是没有被销毁的状态,就把子弹显示出来,否则从列表中删除
    for bullet in playerBulletList:
        if not bullet.isDestroy:
            bullet.draw(MainGame.window)
            bullet.move()
        else:
            playerBulletList.remove(bullet)

有了函数还需要调用,在while循环中加入该函数

while 1:
    # 设置背景颜色
    MainGame.window.fill(BACKGROUND_COLOR)

    # 获取窗口事件
    self.getPlayingModeEvent()

    # 显示我方坦克
    MainGame.playerTank.draw(MainGame.window)

    # 我方坦克移动
    if not MainGame.playerTank.stop:
        MainGame.playerTank.move()

    # 显示我方坦克子弹
    self.drawPlayerBullet(MainGame.playerBulletList)

    # 更新窗口
    pygame.display.update()

运行游戏看看结果

当我们按下开火键时,子弹就发射了

pythonpygame塔克大战代码,Python,python,pygame,学习
注意:MainGame.playerBulletList 需要定义出来,否则程序运行会报错

添加位置如下:

... ...

class MainGame:

    # 窗口Surface对象
    window = None
    playerBulletList = []
    playerBulletNumber = 3
    
    # 玩家坦克
    playerTank = None
    
	... ...

10. 实现敌方坦克类

现在我的坦克可以移动和开火,那么就要有点靶子给我们练习了,是时候实现敌方坦克类了

敌方坦克类的大部分代码跟我方坦克类一样,这里可以用继承,即父类是坦克类,实现两个类的一样的代码,然后我方坦克类和敌方坦克类继承这个类,不过我没有使用继承

import random
import pygame
import pygame.image

from ParentObject import ParentObject
from Bullet import Bullet


class EnemyTank(ParentObject):
    def __init__(self, x, y):
        super().__init__()
        types = [(1, 3), (2, 1), (3, 2), (4, 10)]
        # 随机产生一种坦克
        self.type = types[random.randint(0, len(types) - 1)]
        up = []
        down = []
        left = []
        right = []
        for i in range(1, self.type[1] + 1):
            up.append(
                pygame.image.load(
                    '../Image/Enemy/EnemyTank' + str(self.type[0]) + '/EnemyTank'+ str(self.type[0]) + 'Lv' + str(i) + '(UP).png'
                )
            )
            down.append(
                pygame.image.load(
                    '../Image/Enemy/EnemyTank' + str(self.type[0]) + '/EnemyTank'+ str(self.type[0]) + 'Lv' + str(i) + '(DOWN).png'
                )
            )
            left.append(
                pygame.image.load(
                    '../Image/Enemy/EnemyTank' + str(self.type[0]) + '/EnemyTank' + str(self.type[0]) + 'Lv' + str(
                        i) + '(LEFT).png'
                )
            )
            right.append(
                pygame.image.load(
                    '../Image/Enemy/EnemyTank' + str(self.type[0]) + '/EnemyTank' + str(self.type[0]) + 'Lv' + str(
                        i) + '(RIGHT).png'
                )
            )
        self.images = {
            'UP': up,
            'DOWN': down,
            'LEFT': left,
            'RIGHT': right
        }
        # 生命
        self.life = self.type[1]

        # 方向
        self.direction = 'DOWN'
        self.image: pygame.Surface = self.images[self.direction][self.life - 1]
        self.rect = self.image.get_rect()
        self.rect.left = x
        self.rect.top = y

        # 速度
        self.accumulationMax: float = 0
        self.accumulation = 0.1
        
        speed = 0
        maxBulletCount = 0
        damage = 1
        if self.type[0] == 1:
            speed = 3
            self.level = 1
            maxBulletCount = 1
        elif self.type[0] == 2:
            speed = 5
            self.level = 2
            maxBulletCount = 1
            damage = 3
        elif self.type[0] == 3:
            speed = 7
            self.level = 1
            maxBulletCount = 3
            damage = 2
        elif self.type[0] == 4:
            speed = 6
            self.level = 2
            maxBulletCount = 3
            damage = 1
        self.speed = speed
        # 移动开关
        self.stop = True
        # 开火开关
        self.fire = True
        # 步数
        self.step = 30
        # 伤害
        self.damage = damage
        # 子弹个数
        self.bulletCount = 0
        self.maxBulletCount = maxBulletCount

    def move(self):
        """
        新增步数变量, 当坦克移动时, 步数进行减少, 当步数小于等于0的时候, 修改地方坦克的方向
        :return: None
        """
        if self.stop:
            if self.step <= 0:
                self.direction = self.randDirection()
                self.step = 30
            else:
                if self.accumulationMax >= 1:
                    self.accumulationMax = 0
                    if self.direction == 'LEFT':
                        if self.rect.left > 0:
                            self.rect.left -= self.speed
                    elif self.direction == 'UP':
                        if self.rect.top > 0:
                            self.rect.top -= self.speed
                    elif self.direction == 'DOWN':
                        if self.rect.top < 555:
                            self.rect.top += self.speed
                    elif self.direction == 'RIGHT':
                        if self.rect.left < 855:
                            self.rect.left += self.speed
                    self.step -= 1
                else:
                    self.accumulationMax += self.accumulation

    def shot(self):
        if self.fire:
            if self.bulletCount < self.maxBulletCount:
                num = random.randint(0, 100)
                if num == 5 or num == 6:
                    self.bulletCount += 1
                    return Bullet(self)
        return None

    def draw(self, window):
        # 获取展示的对象
        self.image = self.images[self.direction][self.life - 1]
        window.blit(self.image, self.rect)

    def randDirection(self):
        directions = ['UP', 'DOWN', 'LEFT', 'RIGHT']
        index = random.randint(0, 3)
        return directions[index]

我实际上设置了四种坦克的种类,下面types变量中记录着四种种类的序号和生命值,我规定,生命中不同坦克的样子也不同

types = [(1, 3), (2, 1), (3, 2), (4, 10)]
# 随机产生一种坦克
self.type = types[random.randint(0, len(types) - 1)]

元组中的第二个元素表示生命值, 直接获取

# 生命
self.life = self.type[1]

根据方向和生命值获取对应的图片

self.image: pygame.Surface = self.images[self.direction][self.life - 1]

坦克的属性

根据坦克种类的不同,伤害、等级、生命值也不同

等级是子弹的穿透性,1级只能打烂砖墙,2级可以打烂石墙,3级以上可以打烂黑曜石墙,这个黑曜石墙是我自己新加入的,我们以前玩的坦克大战是没有的,而且规则和我这个不太一样,当然你也可以修改,比如给坦克加入能量,当坦克在一定时间内连续击杀多个敌人,可以获得怒气,短时间伤害提升,这些都可以实现

speed = 0
maxBulletCount = 0
damage = 1
# 每种坦克都有不同的属性
if self.type[0] == 1:
    speed = 3
    self.level = 1
    maxBulletCount = 1
elif self.type[0] == 2:
    speed = 5
    self.level = 2
    maxBulletCount = 1
    damage = 3
elif self.type[0] == 3:
    speed = 7
    self.level = 1
    maxBulletCount = 3
    damage = 2
elif self.type[0] == 4:
    speed = 6
    self.level = 2
    maxBulletCount = 3
    damage = 1

坦克的移动

step是步数,每次按照30次循环作为一次坦克的操作

 if self.stop:
        if self.step <= 0:
        	# 随机产生一个方向,接下来朝这个方向移动
            self.direction = self.randDirection()
            self.step = 30
        else:
            if self.accumulationMax >= 1:
                self.accumulationMax = 0
                if self.direction == 'LEFT':
                    if self.rect.left > 0:
                        self.rect.left -= self.speed
                elif self.direction == 'UP':
                    if self.rect.top > 0:
                        self.rect.top -= self.speed
                elif self.direction == 'DOWN':
                    if self.rect.top < 555:
                        self.rect.top += self.speed
                elif self.direction == 'RIGHT':
                    if self.rect.left < 855:
                        self.rect.left += self.speed
                self.step -= 1
            else:
                self.accumulationMax += self.accumulation

坦克开火

随机产生一个0到100的数字,当为5或者6时,坦克就开火

def shot(self):
    if self.fire:
        if self.bulletCount < self.maxBulletCount:
            num = random.randint(0, 100)
            if num == 5 or num == 6:
                self.bulletCount += 1
                return Bullet(self)
    return None

在上面的代码中,下面的变量用来设置敌方坦克是否移动,是否开火

# 移动开关
self.stop = True
# 开火开关
self.fire = True

11. 在主类中加入敌方坦克并完成坦克移动和开火

在主类中创建类变量

class MainGame:

    # 窗口Surface对象
    window = None

    # 玩家坦克
    playerTank = None

    # 玩家子弹
    playerBulletList = []
    playerBulletNumber = 3

    # 敌人坦克
    enemyTankList = []
    enemyTankTotalCount = 5
    # 用来给玩家展示坦克的数量
    enemyTankCurrentCount = 5

    # 敌人坦克子弹
    enemyTankListBulletList = []


创建展示敌方坦克函数

这里我规定一次展示三辆敌方坦克,当全部被消灭后,再展示3辆,直到全部被消灭

def drawEnemyTank(self):
    # 如果当前坦克为0,那么就该重新生成坦克
    if len(MainGame.enemyTankList) == 0:
        # 一次性产生三个,如果剩余坦克数量超过三,那只能产生三个
        n = min(3, MainGame.enemyTankTotalCount)
        # 如果最小是0,就说明敌人坦克没有了,那么就赢了
        if n == 0:
            print('赢了')
            return
        # 没有赢的话,就产生n个坦克
        self.initEnemyTank(n)
        # 总个数减去产生的个数
        MainGame.enemyTankTotalCount -= n
    # 遍历坦克列表,展示坦克并且移动
    for tank in MainGame.enemyTankList:
        # 坦克还有生命值
        if tank.life > 0:
            tank.draw(MainGame.window)
            tank.move()
            bullet = tank.shot()
            if bullet is not None:
                MainGame.enemyTankBulletList.append(bullet)
        # 坦克生命值为0,就从列表中剔除
        else:
            MainGame.enemyTankCurrentCount -= 1
            MainGame.enemyTankList.remove(tank)

坦克开火之后子弹加入敌方坦克子弹列表,把里面的子弹画出来,然后在while中调用它

def drawEnemyBullet(self):
    for bullet in MainGame.enemyTankBulletList:
        if not bullet.isDestroy:
            bullet.draw(MainGame.window)
            bullet.move()
        else:
            bullet.source.bulletCount -= 1
            MainGame.enemyTankBulletList.remove(bullet)
while 1:
    # 设置背景颜色
    MainGame.window.fill(BACKGROUND_COLOR)

    # 获取窗口事件
    self.getPlayingModeEvent()

    # 显示我方坦克
    MainGame.playerTank.draw(MainGame.window)

    # 我方坦克移动
    if not MainGame.playerTank.stop:
        MainGame.playerTank.move()

    # 显示我方坦克子弹
    self.drawPlayerBullet(MainGame.playerBulletList)

    # 展示敌方坦克
    self.drawEnemyTank()

    # 展示敌方坦克子弹
    self.drawEnemyBullet()

    # 更新窗口
    pygame.display.update()

完整的主类代码

import pygame
import sys

from PlayerTank import PlayerTank
from EnemyTank import EnemyTank

SCREEN_WIDTH = 1100
SCREEN_HEIGHT = 600
BACKGROUND_COLOR = pygame.Color(0, 0, 0)
FONT_COLOR = (255, 255, 255)
PLAYER_TANK_POSITION = (325, 550)

class MainGame:

    # 窗口Surface对象
    window = None

    # 玩家坦克
    playerTank = None

    # 玩家子弹
    playerBulletList = []
    playerBulletNumber = 3

    # 敌人坦克
    enemyTankList = []
    enemyTankTotalCount = 5
    # 用来给玩家展示坦克的数量
    enemyTankCurrentCount = 5

    # 敌人坦克子弹
    enemyTankBulletList = []

    def __init__(self):
        pass

    def startGame(self):
        # 初始化展示模块
        pygame.display.init()
        # 设置窗口大小
        size = (SCREEN_WIDTH, SCREEN_HEIGHT)
        # 初始化窗口
        MainGame.window = pygame.display.set_mode(size)
        # 设置窗口标题
        pygame.display.set_caption('Tank Battle')

        # 初始化我方坦克
        MainGame.playerTank = PlayerTank(PLAYER_TANK_POSITION[0], PLAYER_TANK_POSITION[1], 1, 1)

        while 1:
            # 设置背景颜色
            MainGame.window.fill(BACKGROUND_COLOR)

            # 获取窗口事件
            self.getPlayingModeEvent()

            # 显示我方坦克
            MainGame.playerTank.draw(MainGame.window)

            # 我方坦克移动
            if not MainGame.playerTank.stop:
                MainGame.playerTank.move()

            # 显示我方坦克子弹
            self.drawPlayerBullet(MainGame.playerBulletList)

            # 展示敌方坦克
            self.drawEnemyTank()

            # 展示敌方坦克子弹
            self.drawEnemyBullet()

            # 更新窗口
            pygame.display.update()
            
    def getPlayingModeEvent(self):
        # 获取所有事件
        eventList = pygame.event.get()
        for event in eventList:

            if event.type == pygame.QUIT:
                sys.exit()

            """
            stop属性用来控制坦克移动,当键盘按键按下时,坦克可以移动,一直按住一直移动,当按键抬起时,停止移动
            如果没有该属性,按一下按键移动一次,按一下移动一下,不能一直按住一直移动
            """
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_w:
                    MainGame.playerTank.direction = 'UP'
                    MainGame.playerTank.stop = False
                elif event.key == pygame.K_s:
                    MainGame.playerTank.direction = 'DOWN'
                    MainGame.playerTank.stop = False
                elif event.key == pygame.K_a:
                    MainGame.playerTank.direction = 'LEFT'
                    MainGame.playerTank.stop = False
                elif event.key == pygame.K_d:
                    MainGame.playerTank.direction = 'RIGHT'
                    MainGame.playerTank.stop = False
                elif event.key == pygame.K_j:
                    # 判断子弹数量是否超过指定的个数
                    if len(MainGame.playerBulletList) < MainGame.playerBulletNumber:
                        bullet = MainGame.playerTank.shot()
                        MainGame.playerBulletList.append(bullet)

            if event.type == pygame.KEYUP:
                if event.key == pygame.K_w:
                    MainGame.playerTank.stop = True
                elif event.key == pygame.K_s:
                    MainGame.playerTank.stop = True
                elif event.key == pygame.K_a:
                    MainGame.playerTank.stop = True
                elif event.key == pygame.K_d:
                    MainGame.playerTank.stop = True

    def drawPlayerBullet(self, playerBulletList):
        # 遍历整个子弹列表,如果是没有被销毁的状态,就把子弹显示出来,否则从列表中删除
        for bullet in playerBulletList:
            if not bullet.isDestroy:
                bullet.draw(MainGame.window)
                bullet.move()
            else:
                playerBulletList.remove(bullet)

    def drawEnemyTank(self):
        # 如果当前坦克为0,那么就该重新生成坦克
        if len(MainGame.enemyTankList) == 0:
            # 一次性产生三个,如果剩余坦克数量超过三,那只能产生三个
            n = min(3, MainGame.enemyTankTotalCount)
            # 如果最小是0,就说明敌人坦克没有了,那么就赢了
            if n == 0:
                print('赢了')
                return
            # 没有赢的话,就产生n个坦克
            self.initEnemyTank(n)
            # 总个数减去产生的个数
            MainGame.enemyTankTotalCount -= n
        # 遍历坦克列表,展示坦克并且移动
        for tank in MainGame.enemyTankList:
            # 坦克还有生命值
            if tank.life > 0:
                tank.draw(MainGame.window)
                tank.move()
                bullet = tank.shot()
                if bullet is not None:
                    MainGame.enemyTankBulletList.append(bullet)
            # 坦克生命值为0,就从列表中剔除
            else:
                MainGame.enemyTankCurrentCount -= 1
                MainGame.enemyTankList.remove(tank)
    
    def initEnemyTank(self, number):
        y = 0
        position = [0, 425, 850]
        index = 0
        for i in range(number):
            x = position[index]
            enemyTank = EnemyTank(x, y)
            MainGame.enemyTankList.append(enemyTank)
            index += 1

    def drawEnemyBullet(self):
        for bullet in MainGame.enemyTankBulletList:
            if not bullet.isDestroy:
                bullet.draw(MainGame.window)
                bullet.move()
            else:
                bullet.source.bulletCount -= 1
                MainGame.enemyTankBulletList.remove(bullet)

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

运行一下,看看结果
pythonpygame塔克大战代码,Python,python,pygame,学习

哈哈,终于实现发射子弹啦文章来源地址https://www.toymoban.com/news/detail-785212.html

到了这里,关于学习 Python 之 Pygame 开发坦克大战(二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • python | 基础学习(六)pygame游戏开发:飞机大战

    pygame 模块,转为电子游戏设计 $ sudo pip3 install pygame windows: pip install pygame (1)新建项目 飞机大战 (2)新建文件 pygame.py (3)建立游戏窗口: ①pygame的初始化和退出 pygame.init() :导入并初始化所有pygame模块,使用其他模块之前,必须先调用init方法。 pygame.quit() :卸载所有

    2024年02月08日
    浏览(49)
  • 【python】 pygame学习示例 --飞机大战小游戏制作

    python版本:3.8.5 所需模块:pygame random os pygame版本:20.1 开发环境:pycharm专业版 硬件环境:win11 8G内存以上 使用python的第三方库–pygame 制作飞机大战小游戏 小游戏的内容包括: 玩家player的移动 子弹的发射 陨石的随机掉落(包括旋转 大小 下落角度) 玩家 子弹 陨石的碰撞交互

    2024年02月04日
    浏览(47)
  • Java游戏开发 —— 坦克大战

    坦克大战也是小时一个比较经典的游戏了,我在网上也是参考了韩顺平老师写的坦克大战,并做了一下完善,编写出来作为儿时的回忆吧! 创建主窗口,加载菜单及游戏面板。 在游戏面板中初始化各种参数,并建立各种功能组件。 利用线程固定刷新游戏界面。 处理各种碰撞

    2024年02月06日
    浏览(51)
  • Unity学习回忆--3D坦克大战

    2023年LPL春季赛季后赛正在火热进行中,你们心中的总冠军是哪支队伍呢?作为热爱游戏的程序猿,一起来聊聊你那些有意义的游戏开发经历吧! 前言 还记得大一的时候第一次接触编程,为了手写一个hello,world绞尽脑汁。最后以失败告终!大一的暑假开始学习unity。从我第一

    2023年04月24日
    浏览(58)
  • Python坦克大战完整版

    图片和音效自己自行在网上下载即可。    

    2024年02月04日
    浏览(35)
  • Python实现【坦克大战】+源码分享

    坦克大战,这款经典的电子游戏,无疑是许多80后和90后心中不可磨灭的童年记忆。它不仅仅是一款游戏,更是那个时代科技娱乐方式的缩影,见证了电子游戏行业的起步与发展。 在那个电脑和网络尚未完全普及的年代,坦克大战以其简单的规则、丰富的关卡设计和紧张刺激

    2024年04月10日
    浏览(34)
  • python项目分享 - python坦克大战小游戏

    🔥 Hi,各位同学好呀,这里是L学长! 🥇今天向大家分享一个今年(2022)最新完成的毕业设计项目作品 python小游戏毕设 坦克大战小游戏设计与实现 (源码) 🥇 学长根据实现的难度和等级对项目进行评分(最低0分,满分5分) 难度系数:3分 工作量:3分 创新点:4分 项目获取:

    2024年02月03日
    浏览(38)
  • 毕业设计 python坦克大战小游戏

    🔥 Hi,各位同学好呀,这里是L学长! 🥇今天向大家分享一个今年(2022)最新完成的毕业设计项目作品 python小游戏毕设 坦克大战小游戏设计与实现 (源码) 🥇 学长根据实现的难度和等级对项目进行评分(最低0分,满分5分) 难度系数:3分 工作量:3分 创新点:4分 项目获取:

    2024年02月21日
    浏览(39)
  • python毕设分享 python坦克大战小游戏

    🔥 Hi,各位同学好呀,这里是L学长! 🥇今天向大家分享一个今年(2022)最新完成的毕业设计项目作品 python小游戏毕设 坦克大战小游戏设计与实现 (源码) 🥇 学长根据实现的难度和等级对项目进行评分(最低0分,满分5分) 难度系数:3分 工作量:3分 创新点:4分 项目获取:

    2024年02月03日
    浏览(43)
  • python项目分享 - 坦克大战小游戏设计与实现 (源码)

    🔥 Hi,各位同学好呀,这里是L学长! 🥇今天向大家分享一个今年(2022)最新完成的毕业设计项目作品 python小游戏毕设 坦克大战小游戏设计与实现 (源码) 🥇 学长根据实现的难度和等级对项目进行评分(最低0分,满分5分) 难度系数:3分 工作量:3分 创新点:4分 项目获取:

    2024年02月01日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包