如何向你的 Python 游戏添加玩家

使用 Python 从零开始构建游戏系列教程的第三部分。
327 位读者喜欢这篇文章。
Python game screenshot

OpenGameArt.org

在本系列的第一篇文章中,我解释了如何使用 Python 创建一个简单的、基于文本的骰子游戏。在第二部分中,我向你展示了如何从头开始构建游戏,从创建游戏环境开始。但是每个游戏都需要一个玩家,每个玩家都需要一个可玩角色,这就是你将在本系列教程的第三部分中要做的。

在 Pygame 中,玩家控制的图标或化身被称为精灵(sprite)。如果你还没有任何图形可以用作玩家精灵,请从经典的开源游戏 Supertux 下载 walk-0.png、walk-2.png、walk-4.png 和 walk-5.png 文件,并将它们重命名为 hero1.png 到 hero4.png。或者,你可以使用 KritaInkscape 自己创建一些东西,或者在 OpenGameArt.org 上搜索其他选项。然后,如果你在之前的文章中没有这样做,请在你的 Python 项目目录中创建一个名为 images 的目录。将你想在游戏中使用的图像放入 images 文件夹中。

为了使你的游戏真正令人兴奋,你应该为你的英雄使用动画精灵。如果你自己绘制角色,这意味着你必须绘制更多的素材,但这会产生很大的不同。最常见的动画是行走循环(walk cycle),这是一系列绘画,使其看起来像你的精灵在行走。快速而粗略的行走循环需要四张图画。

A simple 4-step walk cycle

CC BY-SA Seth Kenlon

注意:本文中的代码示例允许使用静态玩家精灵和动画玩家精灵。

将你的玩家精灵命名为 hero.png。如果你正在为行走循环创建动画精灵,请在名称后附加一个数字,从 hero1.png 开始。将你的英雄图像保存到你的 Python 项目目录中的一个名为 images 的目录中。

创建一个 Python 类

在 Python 中,当你创建一个你想在屏幕上显示的对象时,你需要创建一个类。

在你的 Python 脚本的顶部,在 Objects 部分,添加代码来创建一个玩家。 如果你使用没有行走循环的静态图像,请使用此代码(请注意,此代码位于你的文件的 Objects 部分)

'''
Objects
'''

class Player(pygame.sprite.Sprite):
    """
    Spawn a player
    """

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.images = []

        img = pygame.image.load(os.path.join('images', 'hero.png')).convert()
        self.images.append(img)
        self.image = self.images[0]
        self.rect = self.image.get_rect()

此代码块为 Python 创建一个虚拟“对象”,以便在引用你的英雄精灵时使用。在面向对象编程中,“对象”被称为类(class)。对象模板(特别是 pygame.sprite.Sprite)由 Pygame 提供。这使你能够定义一个图像来代表玩家角色。如果你必须从头开始编写该程序,你必须学习更多关于 Python 的知识才能开始创建游戏,这就是使用像 Pygame 这样的框架的优势。

如果你为你的可玩角色制作了行走循环,请将每张图画保存为单独的文件,名为 hero1.pnghero4.png,放在你的项目的 images 文件夹中。然后使用一个循环来告诉 Python 循环遍历每个文件。这是面向对象编程的特性之一:每个类都可以有专门分配给它的任务,这些任务的执行不会影响周围的“世界”。在本例中,你的玩家角色精灵被编程为循环遍历四个不同的图像,以创建行走的错觉,并且无论周围发生什么,这种情况都可以发生。

'''
Objects
'''


class Player(pygame.sprite.Sprite):
    """
    Spawn a player
    """

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.images = []
        for i in range(1, 5):
            img = pygame.image.load(os.path.join('images', 'hero' + str(i) + '.png')).convert()
            self.images.append(img)
            self.image = self.images[0]
            self.rect = self.image.get_rect()

将玩家带入游戏世界

现在 Player 类已经存在,你必须使用它在你的游戏世界中生成一个玩家精灵。如果你从不调用 Player 类,它永远不会运行,并且不会有玩家。你可以通过现在运行你的游戏来测试这一点。游戏运行得和上一篇文章结尾时一样好,结果完全相同:一个空的游戏世界。

要将玩家精灵带入你的世界,你必须“调用” Player 类来生成一个精灵,然后将其添加到 Pygame 精灵组。将以下行添加到你的 Setup 部分

player = Player()   # spawn player
player.rect.x = 0   # go to x
player.rect.y = 0   # go to y
player_list = pygame.sprite.Group()
player_list.add(player)

尝试启动你的游戏,看看会发生什么。警告:它不会如你所愿。当你启动你的项目时,玩家精灵不会生成。实际上,它生成了,但只持续了一毫秒。你如何修复只发生一毫秒的事情?你可能从上一篇文章中回忆起,你需要向主循环(main loop)添加一些东西。为了使玩家精灵生成的时间超过一毫秒,请告诉 Python 每循环一次绘制它一次。

更改你的主循环的绘制子句,使其看起来像这样

    world.blit(backdrop, backdropbox)
    player_list.draw(world) # draw player
    pygame.display.flip()
    clock.tick(fps)

现在启动你的游戏。你的玩家生成了!

设置 Alpha 通道

根据你创建玩家精灵的方式,它可能周围有一个彩色块。你所看到的是应该被Alpha 通道(alpha channel)占据的空间。它本应是“颜色”的不可见性,但 Python 还不知道如何使其不可见。那么,你所看到的是精灵周围的边界框(或现代游戏术语中的“碰撞箱(hit box)”)内的空间。

No alpha

你可以通过设置 Alpha 通道并使用 RGB 值来告诉 Python 将什么颜色设置为不可见。如果你不知道你的绘图用作 Alpha 的 RGB 值,请在 Pinta 或 Inkscape 中打开你的绘图,并在你的绘图周围的空白区域填充一种独特的颜色,例如 #00ff00(或多或少是“绿幕绿”)。记下颜色的十六进制值(#00ff00,用于绿幕绿),并在你的 Python 脚本中将其用作 Alpha 通道。

使用 Alpha 需要在你的精灵创建代码中添加两行。第一行的某些版本已经在你的代码中。添加另外两行

            img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
            img.convert_alpha()     # optimise alpha
            img.set_colorkey(ALPHA) # set alpha

除非你告诉 Python,否则 Python 不知道使用什么作为 Alpha。

如果你认为你的图像已经有一个 Alpha 通道,你可以尝试将变量 ALPHA 设置为 0 或 255,这都是 Alpha 常用的存储位置。其中一个可能有效,但也许由于我在电影制作方面的背景,我更喜欢显式创建和设置我自己的 Alpha 通道。

设置你自己的 Alpha

在你的代码的 Variable 部分,添加此变量定义

ALPHA = (0, 255, 0)

在此示例代码中,使用了 0,255,0,这与 #00ff00 在十六进制中的 RGB 值相同。你可以从优秀的图形应用程序(如 GIMP、Krita 或 Inkscape)中获取所有这些颜色值。或者,你也可以使用优秀的系统级颜色选择器(如 KColorChooserColourPicker)检测颜色值。

KColorChooser

opensource.com

如果你的图形应用程序将你的精灵的背景渲染为其他值,请根据需要调整你的 Alpha 变量的值。无论你将你的 Alpha 值设置为多少,它都将变为“不可见”。RGB 值非常严格,所以如果你需要使用 000 作为 Alpha,但是你需要 000 作为你的绘图的黑色线条,只需将你的绘图的线条更改为 111,这与黑色非常接近,除了计算机之外没有人能分辨出差异。

启动你的游戏以查看结果。

Alpha

这是到目前为止的完整代码

#!/usr/bin/env python3
# by Seth Kenlon

# GPLv3
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://gnu.ac.cn/licenses/>.
from typing import Tuple

import pygame
import sys
import os

'''
Variables
'''

worldx = 960
worldy = 720
fps = 40  # frame rate
ani = 4  # animation cycles
world = pygame.display.set_mode([worldx, worldy])

BLUE = (25, 25, 200)
BLACK = (23, 23, 23)
WHITE = (254, 254, 254)
ALPHA = (0, 255, 0)

'''
Objects
'''


class Player(pygame.sprite.Sprite):
    """
    Spawn a player
    """

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.images = []
        for i in range(1, 5):
            img = pygame.image.load(os.path.join('images', 'hero' + str(i) + '.png')).convert()
            img.convert_alpha()  # optimise alpha
            img.set_colorkey(ALPHA)  # set alpha
            self.images.append(img)
            self.image = self.images[0]
            self.rect = self.image.get_rect()


'''
Setup
'''

backdrop = pygame.image.load(os.path.join('images', 'stage.png'))
clock = pygame.time.Clock()
pygame.init()
backdropbox = world.get_rect()
main = True

player = Player()  # spawn player
player.rect.x = 0  # go to x
player.rect.y = 0  # go to y
player_list = pygame.sprite.Group()
player_list.add(player)


'''
Main Loop
'''

while main:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            try:
                sys.exit()
            finally:
                main = False

        if event.type == pygame.KEYDOWN:
            if event.key == ord('q'):
                pygame.quit()
            try:
                sys.exit()
            finally:
                main = False
    world.blit(backdrop, backdropbox)
    player_list.draw(world)
    pygame.display.flip()
    clock.tick(fps)

在本系列的第四部分中,我将向你展示如何让你的精灵移动。多么令人兴奋!

接下来阅读什么
标签
Seth Kenlon
Seth Kenlon 是一位 UNIX 极客、自由文化倡导者、独立多媒体艺术家和 D&D 爱好者。他曾在电影和计算行业工作,通常同时从事这两个行业。
User profile image.
Jess Weichler 是一位数字艺术家,使用开源软件和硬件在 CyanideCupcake.com 上创作数字和物理世界的作品。

1 条评论

我认为代码中存在一些错误

1. 在 'Player' 类中
缩进错误。最后四行应该是 '__init__' 的一部分。否则 'self' 将无法识别

2. 在代码的开头,你应该放置 'pygame.display.set_mode()',否则你会收到错误。

3. 你应该用 world 替换主循环中的 'screen',因为那是屏幕的命名方式。'screen' 被 player_list.draw() 用作参数。

这些是我的评论,尽管程序的其余部分做得非常好。我已经学到了一些新的/有用的函数和属性。这些错误也可能是由于你使用的操作系统或 python 版本造成的。

© . All rights reserved.