python/pygame 挑战魂斗罗 笔记(一)

前面完成了飞机和坦克两个经典游戏的基本功能,想挑战一下魂斗罗?这里的难点感觉是玩家的上下左右移动和变换动作,还有跳跃、趴下、射击等,尤其是跳到地面下的各个台阶部分,有点复杂。

下面开始我的魂斗罗1.0的挑战,看看能不能实现。 

一、建立一个配置文件Config.py。

这一次将代码想模块化管理,将所有的全局常量、变量都统一归口到这个配置文件中,方便调用。

网络上找到的背景地图图片高度为240像素,这里将游戏窗口设定为720像素高,地图放大3倍。

# Config.py
import pygame


class Constant:
    WIDTH = 1200
    HEIGHT = 720
    FPS = 60

    MAP_SCALE = 3


class Variable:
    all_sprites = pygame.sprite.Group()

    game_start = True

二、建立主循环文件Contra.py

文件主要包括键盘控制、游戏窗口、游戏时钟设定以及主循环

# Contra.py
import sys
import pygame

from Config import Constant, Variable


def control():
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            Variable.game_start = False


class Main:
    def __init__(self):
        pygame.init()
        self.game_window = pygame.display.set_mode((Constant.WIDTH, Constant.HEIGHT))
        self.clock = pygame.time.Clock()

    def game_loop(self):
        while Variable.game_start:
            control()

            self.clock.tick(Constant.FPS)
            pygame.display.set_caption(f'魂斗罗  1.0    {self.clock.get_fps():.2f}')
            pygame.display.update()

        pygame.quit()
        sys.exit()


if __name__ == '__main__':
    main = Main()
    main.game_loop()

三、建立ContraMap.py文件:

1、先载入背景地图

素材一共有8个不同阶段地图,按照stage1-8的方式命名,建立一个image_list列表。每通过一关,增加stage值进入下一关地图。

# ContraMap.py
import os
import pygame

from Config import Constant, Variable


class Stage(pygame.sprite.Sprite):
    def __init__(self, order):
        pygame.sprite.Sprite.__init__(self)
        self.image_list = []
        self.order = order
        for i in range(1, 9):
            image = pygame.image.load(os.path.join('image', 'map', 'stage' + str(i) + '.png'))
            rect = image.get_rect()
            image = pygame.transform.scale(image, (rect.width * Constant.MAP_SCALE, rect.height * Constant.MAP_SCALE))
            self.image_list.append(image)
        self.image = self.image_list[self.order]
        self.rect = self.image.get_rect()
        self.rect.x = 0
        self.rect.y = 0
        self.speed = 0
2、地图移动

魂斗罗的背景地图移动相对复杂一点,不是简单的重复移动。

素材中只有stage3是纵向移动的,其它是横向移动的,这里先不管stage3 ,先考虑横向移动方式。

横向移动方式设计为三步:先是一段英文介绍快速左移,然后等待玩家选择界面;玩家选择完后地图再次快速移动进入游戏地图开始正常游戏,此时地图停止移动,等待玩家移动到游戏窗口中间以后再进行移动,先实现前面两步。

在配置文件Config.py中增加一个变量step来控制地图移动,定义update函数实现移动。

    def update(self):
        if self.order == 2:
            print('纵向地图')
        else:
            if Variable.step == 0 and self.rect.x >= -Constant.WIDTH:
                self.rect.x -= 10
            if Variable.step == 1 and self.rect.x > -Constant.WIDTH * 2:
                self.rect.x -= 10
                if self.rect.x == -2400:
                    Variable.step = 2
            if Variable.step == 2:
                self.rect.x -= self.speed

3、在ContraMap.py中定义地图载入方法

首先需要在配置文件变量中增加map_switch = True和stage = 1两个变量,用来控制地图载入及地图索引,定义new_stage方法。

def new_stage():
    if Variable.switch:
        stage_map = Stage(Variable.stage - 1)
        Variable.all_sprites.add(stage_map)
        Variable.switch = False

 修改control方法,这里省略一下,在玩家选择界面直接Enter实现游戏进入。

def control():
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            Variable.game_start = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RETURN:
                Variable.step = 1

在主循环中通过all_sprites绘制及调用update函数实现移动,这样就实现了地图载入到进入游戏的一个简单过程。

下面准备主角Bill。

四、建立ContraBill.py文件,魂斗罗主角BILL:

1、归纳整理素材图片

这个是网络找到的主角BILL的各动作分解图! 

把各个动作进行归纳整理,先搞出第一关的部分吧,第一关的动作一共归纳了9种状态,每种状态里面都通过PS给做成了6种动作分解图片,有的是动作分解,有的就是一样的图片复制一下,比如stand状态,就是6个一样的图片,只是为了方便图片的导入。下面没有归纳到文件夹的图片是其它关使用的,暂时先放着吧。

英文都是百度的大概意思!

 2、建立ContraBill.py文件

图片的载入采用了两层for循环,一层是遍历image_dict状态字典的键,根据键来载入对应的图片,一层是前面PS做好的动作分解,因为都做成了6张图片,这里代码就简单了不少,直接一个for i in range(6)就搞定了。

# ContraBill.py
import os
import pygame

from Constant import Constant


class Bill(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image_dict = {
            'be_hit': [],
            'jump': [],
            'oblique_down': [],
            'oblique_up': [],
            'run': [],
            'shoot': [],
            'stand': [],
            'up': []
        }
        for i in range(6):
            for key in self.image_dict:
                image = pygame.image.load(os.path.join('image', 'bill', str(key), str(key) + str(i + 1) + '.png'))
                rect = image.get_rect()
                image_scale = pygame.transform.scale(
                    image, (rect.width * Constant.MAP_SCALE, rect.height * Constant.MAP_SCALE))
                self.image_dict[key].append(image_scale)
            
            self.image_order = 0
            self.image_type = 'stand'
            
            self.image = self.image_dict[self.image_type][self.image_order]
            self.rect = self.image.get_rect()
            self.rect.x = 100
            self.rect.y = 250
            self.direction = 'right'

    def update(self):
        self.image = self.image_dict[self.image_type][self.image_order]

再定义一个玩家Bill出现的时间及方法。 同样增加一个player_switch,在实例化玩家Bill后关闭。防止重复载入。

def new_player():
    bill = Bill()
    if Variable.step == 2 and Variable.player_switch:
        Variable.all_sprites.add(bill)
        Variable.player_switch = False

在主循中调用方法,可以看到玩家按照预定的步骤出现在屏幕上。这样写的玩家产生方法,不知道这样写会不会更麻烦呢?

3、玩家移动:

先简单写一下玩家的左右移动以及方向的改变,在update函数中增加按键监测。

    def update(self):
        self.image = self.image_dict[self.image_type][self.image_order]
        if self.direction == 'left':
            self.image = pygame.transform.flip(self.image, True, False)

        key_pressed = pygame.key.get_pressed()
        if key_pressed[pygame.K_a]:
            self.direction = 'left'
            self.image_type = 'run'
            self.rect.x -= 2
        elif key_pressed[pygame.K_d]:
            self.direction = 'right'
            self.image_type = 'run'
            self.rect.x += 2

现在Bill可以左右简单移动。

五、现阶段各部分完整代码:

1、Contra.py现阶段代码:
# Contra.py
import sys
import pygame

import ContraBill
import ContraMap
from Config import Constant, Variable


def control():
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            Variable.game_start = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RETURN:
                Variable.step = 1


class Main:
    def __init__(self):
        pygame.init()
        self.game_window = pygame.display.set_mode((Constant.WIDTH, Constant.HEIGHT))
        self.clock = pygame.time.Clock()

    def game_loop(self):
        while Variable.game_start:
            control()
            if Variable.stage == 1:
                ContraMap.new_stage()
                ContraBill.new_player()

            if Variable.stage == 2:
                pass

            if Variable.stage == 3:
                pass

            Variable.all_sprites.draw(self.game_window)
            Variable.all_sprites.update()
            print(Variable.all_sprites)

            self.clock.tick(Constant.FPS)
            pygame.display.set_caption(f'魂斗罗  1.0    {self.clock.get_fps():.2f}')
            pygame.display.update()

        pygame.quit()
        sys.exit()


if __name__ == '__main__':
    main = Main()
    main.game_loop()
2、ContraMap.py现阶段代码:
# ContraMap.py
import os
import pygame

from Config import Constant, Variable


class StageMap(pygame.sprite.Sprite):
    def __init__(self, order):
        pygame.sprite.Sprite.__init__(self)
        self.image_list = []
        self.order = order
        for i in range(1, 9):
            image = pygame.image.load(os.path.join('image', 'map', 'stage' + str(i) + '.png'))
            rect = image.get_rect()
            image = pygame.transform.scale(image, (rect.width * Constant.MAP_SCALE, rect.height * Constant.MAP_SCALE))
            self.image_list.append(image)
        self.image = self.image_list[self.order]
        self.rect = self.image.get_rect()
        self.rect.x = 0
        self.rect.y = 0
        self.speed = 0

    def update(self):
        if self.order == 2:
            print('纵向地图')
        else:
            if Variable.step == 0 and self.rect.x >= -Constant.WIDTH:
                self.rect.x -= 10
            if Variable.step == 1 and self.rect.x > -Constant.WIDTH * 2:
                self.rect.x -= 10
                if self.rect.x == -2400:
                    Variable.step = 2
            if Variable.step == 2:
                self.rect.x -= self.speed


def new_stage():
    if Variable.map_switch:
        stage_map = StageMap(Variable.stage - 1)
        Variable.all_sprites.add(stage_map)
        Variable.map_switch = False
3、ContraBill.py现阶段代码:
# ContraBill.py
import os
import pygame

from Config import Constant, Variable


class Bill(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image_dict = {
            'be_hit': [],
            'jump': [],
            'oblique_down': [],
            'oblique_up': [],
            'run': [],
            'shoot': [],
            'stand': [],
            'up': []
        }
        for i in range(6):
            for key in self.image_dict:
                image = pygame.image.load(os.path.join('image', 'bill', str(key), str(key) + str(i + 1) + '.png'))
                rect = image.get_rect()
                image_scale = pygame.transform.scale(
                    image, (rect.width * Constant.MAP_SCALE, rect.height * Constant.MAP_SCALE))
                self.image_dict[key].append(image_scale)

            self.image_order = 0
            self.image_type = 'stand'

            self.image = self.image_dict[self.image_type][self.image_order]
            self.rect = self.image.get_rect()
            self.rect.x = 100
            self.rect.y = 250
            self.direction = 'right'

    def update(self):
        self.image = self.image_dict[self.image_type][self.image_order]
        if self.direction == 'left':
            self.image = pygame.transform.flip(self.image, True, False)

        key_pressed = pygame.key.get_pressed()
        if key_pressed[pygame.K_a]:
            self.direction = 'left'
            self.image_type = 'run'
            self.rect.x -= 2
        elif key_pressed[pygame.K_d]:
            self.direction = 'right'
            self.image_type = 'run'
            self.rect.x += 2


def new_player():
    bill = Bill()
    if Variable.step == 2 and Variable.player_switch:
        Variable.all_sprites.add(bill)
        Variable.player_switch = False
4、Config.py现阶段代码:
# Config.py
import pygame


class Constant:
    WIDTH = 1200
    HEIGHT = 720
    FPS = 60

    MAP_SCALE = 3


class Variable:
    all_sprites = pygame.sprite.Group()

    game_start = True
    map_switch = True
    player_switch = True

    stage = 1
    step = 0

  • 19
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Pygame中的经典飞机大战源代码》 Pygame是一个流行的Python库,用于创建2D游戏和多媒体应用程序。在其GitHub仓库https://github.com/pygame/pygame中,并没有直接提供完整的飞机大战(通常称为"Breakout"或"Space Invaders"风格的游戏)的源代码。然而,Pygame确实提供了基本的游戏开发框架和工具,开发者可以在此基础上构建自己的游戏,包括飞机大战。 如果你想要学习如何用Pygame制作飞机大战,你可以从以下几个步骤开始: 1. **安装Pygame**:首先确保你已经安装了PythonPygame库。如果还没有,可以在命令行运行`pip install pygame`来安装。 2. **理解基础概念**:了解Pygame的基本模块如Surface、Sprite、事件处理等,这些都是游戏开发的基础。 3. **设计游戏结构**:定义飞机类(Player Ship)、敌人类(Enemy Sprites)以及子弹类(Bullet Sprites)。 4. **编写游戏循环**:使用Pygame的`while True`循环来控制游戏的主要流程,包括渲染帧、处理用户输入、更新游戏状态等。 5. **碰撞检测**:实现飞机和敌人的碰撞检测,当两者相遇时可能触发爆炸、得分等效果。 6. **资源管理**:加载并管理游戏图片、声音和动画资源。 7. **保存和加载**:可选地,添加保存和加载游戏进度的功能。 由于GitHub上可能包含的是库本身的核心组件,而非示例项目或完整的游戏代码,因此你需要查看相关的教程、文档或社区贡献的示例代码来找到一个实际的游戏实现。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值