Pygame实战:对象突然想玩坦克大战,我用Python三十分钟实现(他开心的笑了。)

Posted 顾木子吖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Pygame实战:对象突然想玩坦克大战,我用Python三十分钟实现(他开心的笑了。)相关的知识,希望对你有一定的参考价值。

导语

今天是回忆童年的一天,文章游戏代码的话小编写了蛮多还,等啥时候有时间了我整理下笔记归类放着!!

《坦克大战》当年算是红遍大江南北的热门游戏。

别看这游戏画面简陋,它可是集合了所有经典游戏的成功要素——

上手容易、升级强化、关卡丰富、可以双打,甚至还有良心到爆的编辑模式。

虽然是个低K游戏,但在当时的国人看来,这游戏买得非常值!

今天小编带大家写一款经典版的坦克大战游戏项目,期待叭~

​正文

(1)准备的图片素材很多分类处理:以下是部分截图。

​​

(2)不同的音乐背景:当熟悉的背景音乐响起,扑面而来的是整个童年啊!

​​

(3)游戏规则:

游戏有单人和双人两种模式,己方大本营被破或者己方坦克被歼灭则游戏失败,成功通过所有关卡则游戏胜利。另外,玩家可以通过射击特定的坦克使地图上随机出现一个道具,若己方坦克捡到该道具,则触发一个事件,例如坦克能力的增强。

​​

玩家操作方式如下:

玩家一:

wsad键:上下左右;

空格键:射击。

玩家二:

↑↓←→键:上下左右;

小键盘0键:射击。

# 玩家一, WSAD移动, 空格键射击
            if tank_player1.num_lifes >= 0:
                if key_pressed[pygame.K_w]:
                    player_tanks_group.remove(tank_player1)
                    tank_player1.move('up', self.scene_elems, player_tanks_group, enemy_tanks_group, home)
                    player_tanks_group.add(tank_player1)
                elif key_pressed[pygame.K_s]:
                    player_tanks_group.remove(tank_player1)
                    tank_player1.move('down', self.scene_elems, player_tanks_group, enemy_tanks_group, home)
                    player_tanks_group.add(tank_player1)
                elif key_pressed[pygame.K_a]:
                    player_tanks_group.remove(tank_player1)
                    tank_player1.move('left', self.scene_elems, player_tanks_group, enemy_tanks_group, home)
                    player_tanks_group.add(tank_player1)
                elif key_pressed[pygame.K_d]:
                    player_tanks_group.remove(tank_player1)
                    tank_player1.move('right', self.scene_elems, player_tanks_group, enemy_tanks_group, home)
                    player_tanks_group.add(tank_player1)
                elif key_pressed[pygame.K_SPACE]:
                    bullet = tank_player1.shoot()
                    if bullet:
                        self.sounds['fire'].play() if tank_player1.tanklevel < 2 else self.sounds['Gunfire'].play()
                        player_bullets_group.add(bullet)
            # 玩家二, ↑↓←→移动, 小键盘0键射击
            if self.is_dual_mode and (tank_player2.num_lifes >= 0):
                if key_pressed[pygame.K_UP]:
                    player_tanks_group.remove(tank_player2)
                    tank_player2.move('up', self.scene_elems, player_tanks_group, enemy_tanks_group, home)
                    player_tanks_group.add(tank_player2)
                elif key_pressed[pygame.K_DOWN]:
                    player_tanks_group.remove(tank_player2)
                    tank_player2.move('down', self.scene_elems, player_tanks_group, enemy_tanks_group, home)
                    player_tanks_group.add(tank_player2)
                elif key_pressed[pygame.K_LEFT]:
                    player_tanks_group.remove(tank_player2)
                    tank_player2.move('left', self.scene_elems, player_tanks_group, enemy_tanks_group, home)
                    player_tanks_group.add(tank_player2)
                elif key_pressed[pygame.K_RIGHT]:
                    player_tanks_group.remove(tank_player2)
                    tank_player2.move('right', self.scene_elems, player_tanks_group, enemy_tanks_group, home)
                    player_tanks_group.add(tank_player2)
                elif key_pressed[pygame.K_KP0]:
                    bullet = tank_player2.shoot()
                    if bullet:
                        player_bullets_group.add(bullet)
                        self.sounds['fire'].play() if tank_player2.tanklevel < 2 else self.sounds['Gunfire'].play()

加载游戏素材中:

​​

附:

 # 加载游戏素材
    sounds = 
    for key, value in cfg.AUDIO_PATHS.items():
        sounds[key] = pygame.mixer.Sound(value)
        sounds[key].set_volume(1)

(4)在坦克移动中、打到对方等肯定有碰撞:

       # 碰撞检测
            # --子弹和砖墙
            pygame.sprite.groupcollide(player_bullets_group, self.scene_elems.get('brick_group'), True, True)
            pygame.sprite.groupcollide(enemy_bullets_group, self.scene_elems.get('brick_group'), True, True)
            # --子弹和铁墙
            for bullet in player_bullets_group:
                if pygame.sprite.spritecollide(bullet, self.scene_elems.get('iron_group'), bullet.is_stronger, None):
                    player_bullets_group.remove(bullet)
            pygame.sprite.groupcollide(enemy_bullets_group, self.scene_elems.get('iron_group'), True, False)
            # --子弹撞子弹
            pygame.sprite.groupcollide(player_bullets_group, enemy_bullets_group, True, True)
            # --我方子弹撞敌方坦克
            for tank in enemy_tanks_group:
                if pygame.sprite.spritecollide(tank, player_bullets_group, True, None):
                    if tank.food:
                        foods_group.add(tank.food)
                        tank.food = None
                    if tank.decreaseTankLevel():
                        self.sounds['bang'].play()
                        self.total_enemy_num -= 1
            # --敌方子弹撞我方坦克
            for tank in player_tanks_group:
                if pygame.sprite.spritecollide(tank, enemy_bullets_group, True, None):
                    if tank.is_protected:
                        self.sounds['blast'].play()
                    else:
                        if tank.decreaseTankLevel():
                            self.sounds['bang'].play()
                        if tank.num_lifes < 0:
                            player_tanks_group.remove(tank)
            # --我方子弹撞我方大本营
            if pygame.sprite.spritecollide(home, player_bullets_group, True, None):
                is_win = False
                is_running = False
                home.setDead()
            # --敌方子弹撞我方大本营
            if pygame.sprite.spritecollide(home, enemy_bullets_group, True, None):
                is_win = False
                is_running = False
                home.setDead()

(5)坦克游戏中会随机生成食物:

 # --坦克吃到食物
            for player_tank in player_tanks_group:
                for food in foods_group:
                    if pygame.sprite.collide_rect(player_tank, food):
                        if food.name == 'boom':
                            self.sounds['add'].play()
                            for _ in enemy_tanks_group:
                                self.sounds['bang'].play()
                            self.total_enemy_num -= len(enemy_tanks_group)
                            enemy_tanks_group = pygame.sprite.Group()
                        elif food.name == 'clock':
                            self.sounds['add'].play()
                            for enemy_tank in enemy_tanks_group:
                                enemy_tank.setStill()
                        elif food.name == 'gun':
                            self.sounds['add'].play()
                            player_tank.improveTankLevel()
                        elif food.name == 'iron':
                            self.sounds['add'].play()
                            self.__pretectHome()
                        elif food.name == 'protect':
                            self.sounds['add'].play()
                            player_tank.setProtected()
                        elif food.name == 'star':
                            self.sounds['add'].play()
                            player_tank.improveTankLevel()
                            player_tank.improveTankLevel()
                        elif food.name == 'tank':
                            self.sounds['add'].play()
                            player_tank.addLife()
                        foods_group.remove(food)

游戏效果:

​​总结

这游戏的话经典哈,我第一关就没玩了哈,大家自己探索。

说实话代码真挺多的,你感觉这款坦克大战有还原多少呀??

源码基地免费分享项目:​🎊🎊源码基地:关注小编获取哦~💝记得三连吖

..............更多内容敬请期待...........

学习 Python 之 Pygame 开发坦克大战

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

坦克大战的需求

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

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

物体总结完毕后,规划一下窗口的大小,下面是我设置的窗口大小

素材链接:百度网盘
链接:https://pan.baidu.com/s/19sCyH7rp37f6DzRj0iXDCA?pwd=tkdz
提取码:tkdz

开始编写坦克大战

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

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

运行结果

主类中运用到的知识,都是学习 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

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)

以上是关于Pygame实战:对象突然想玩坦克大战,我用Python三十分钟实现(他开心的笑了。)的主要内容,如果未能解决你的问题,请参考以下文章

python 全解坦克大战 辅助类 附完整代码雏形

学习 Python 之 Pygame 开发坦克大战

学习 Python 之 Pygame 开发坦克大战

学习 Python 之 Pygame 开发坦克大战

学习 Python 之 Pygame 开发坦克大战

学习 Python 之 Pygame 开发坦克大战