在本系列的第一篇文章中,我解释了如何使用 Python 创建一个简单的、基于文本的骰子游戏。在第二部分中,我向你展示了如何从头开始构建游戏,从创建游戏环境开始。但是每个游戏都需要一个玩家,每个玩家都需要一个可玩角色,这就是你将在本系列教程的第三部分中要做的。
在 Pygame 中,玩家控制的图标或化身被称为精灵(sprite)。如果你还没有任何图形可以用作玩家精灵,请从经典的开源游戏 Supertux 下载 walk-0.png、walk-2.png、walk-4.png 和 walk-5.png 文件,并将它们重命名为 hero1.png 到 hero4.png。或者,你可以使用 Krita 或 Inkscape 自己创建一些东西,或者在 OpenGameArt.org 上搜索其他选项。然后,如果你在之前的文章中没有这样做,请在你的 Python 项目目录中创建一个名为 images
的目录。将你想在游戏中使用的图像放入 images
文件夹中。
为了使你的游戏真正令人兴奋,你应该为你的英雄使用动画精灵。如果你自己绘制角色,这意味着你必须绘制更多的素材,但这会产生很大的不同。最常见的动画是行走循环(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.png
到 hero4.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)”)内的空间。

你可以通过设置 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)中获取所有这些颜色值。或者,你也可以使用优秀的系统级颜色选择器(如 KColorChooser 或 ColourPicker)检测颜色值。

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

这是到目前为止的完整代码
#!/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)
在本系列的第四部分中,我将向你展示如何让你的精灵移动。多么令人兴奋!
1 条评论