今年,我参加了 Open Jam,这是一个“游戏创作营”,世界各地的程序员利用一个周末的时间来创建开源游戏。 这个创作营本质上是一个花时间编码的借口,而这项挑战产生的大部分游戏都是小小的消遣,而不是你可能会连续玩上几个小时的游戏。 但它们有趣、多样化且开源,对于一款游戏来说,这是一个相当不错的功能列表。
我提交的游戏是 Unveil,这是一款令人平静的益智游戏,玩家必须首先发现目标,然后努力以最高的分数实现目标。 因为游戏的一部分是发现过程,所以我不会透露更多关于游戏玩法的信息。

(Klaatu, CC BY-SA 4.0)
整个游戏只有 338 行代码,使用 Python 和 Pygame 模块编写。 当然,它是开源的,其中一部分可以作为对一些曾经让我困惑的编程概念(其中最重要的是二维数组)的良好介绍。 对于简单的游戏设计,二维数组非常有用,因为许多持久的游戏都是建立在它们之上的。 您可能会想到几个,但如果您不知道什么是二维数组,您可能不会意识到这一点。
游戏中的数组
数组是数据的集合。 数组可以跨页面或 X 轴(用数学术语来说)列出。 例如
artichoke, lettuce, carrot, aubergine, potato
数组也可以表示为列表或 Y 轴
artichoke
lettuce
carrot
aubergine
potato
这是一个一维数组。 二维数组在 X 轴和 Y 轴上延伸。
这是在棋盘游戏世界中常见的二维数组

(Klaatu, CC BY-SA 4.0)
是的,二维数组用作国际象棋、跳棋、井字棋(也称为井字游戏)、RPG 战斗地图、扫雷、卡卡颂、禁忌岛的棋盘,以及稍微修改的形式,如大富翁甚至 乌尔王室游戏(字面意思是我们所知的最古老的游戏)。
如果您可以轻松地创建一个二维数组,那么您在编程任意数量的游戏方面有了一个良好的开端。
在 Pygame 中创建图块
如果您不熟悉 Python,您应该花一些时间复习这个 Python(和 Pygame)入门系列。 但是,如果您有足够的信心将代码翻译成其他库,那么这段代码的“重要”部分(数组构造函数)中没有任何特定于 Pygame 的内容,因此您可以使用任何库或语言。
为了简单起见,我将游戏板数组中的各个正方形称为图块。 要构建二维数组或游戏板(视情况而定),您必须有图块。 在面向对象编程中,您将每个组件视为基于模板(或编程术语中的类)的唯一对象。 因此,在创建游戏板之前,您必须首先为板的构建块创建基础设施:图块。
首先,设置一个简单的 Pygame 项目,创建一个显示(您进入游戏世界的窗口)、一个代表游戏板的组和一些标准变量
import pygame
pygame.init()
game_world = pygame.display.set_mode((960, 720))
game_board = pygame.sprite.Group()
running = True
black = (0, 0, 0)
white = (255, 255, 255)
red = (245, 22, 22)
world_x = 960
world_y = 720
接下来,创建一个 Tile
类来建立模板,每个图块都从中创建。 第一个函数在创建新图块时初始化它,并为其提供必要的基本字段:宽度、高度、图像(实际上,我只是用白色填充它)以及它是否处于活动状态。 在这种情况下,我使用 is_pressed
,就好像图块是一个按钮一样,因为这就是代码完成后的样子:当用户单击图块时,它会改变颜色,就好像按钮被点亮一样。 对于其他用途,此状态不必可见。 例如,在国际象棋中,您可以改为使用一个字段来表示图块是否被占用,如果被占用,则被哪种类型的棋子占用。
class Tile(pygame.sprite.Sprite):
def __init__(self, x, y, w, h, c):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((w, h))
self.image.fill(c)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.is_pressed = False
第二个函数是更新函数。 具体来说,它检查用户是否单击了图块。 这需要鼠标坐标,您将在稍后的代码中的事件循环期间获得这些坐标。
为了演示,我将使此函数在图块处于 is_pressed
状态时将其填充为红色,否则填充为白色
def was_clicked(self, mouse):
if self.rect.collidepoint(mouse) and not self.is_pressed:
self.image.fill(red)
self.is_pressed = True
elif self.rect.collidepoint(mouse) and self.is_pressed:
self.image.fill(white)
self.is_pressed = False
else:
return False
主循环
此演示的主循环很简单。 它检查两种类型的输入:退出信号和鼠标按下(单击)事件。 当它检测到鼠标单击时,它会调用 was_clicked
函数来做出反应(根据其当前状态,用红色或白色填充它)。
最后,屏幕填充为黑色,游戏板状态更新,并且屏幕被重新绘制
"""
holding place for game board construction
"""
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
for hitbox in game_board:
hitbox.was_clicked(event.pos)
game_world.fill(black)
game_board.update()
game_board.draw(game_world)
pygame.display.update()
pygame.quit()
板构建
要构建二维数组,您必须首先确定在两个方向上需要多少个图块。 在此示例中,我将使用八个,因为这就是国际象棋棋盘的构建方式,但您可以使用更少或更多。 您甚至可以在启动时接受参数以根据选项(例如 --row
和 --column:
)定义数组的大小:
rows = 8
columns = 8
因为您不知道板的大小,所以您必须根据显示器的大小计算行和列的宽度。 我还在每个图块之间包含一个像素的填充,因为如果没有间隙,它看起来就像一大块颜色
column_width = world_x / columns
row_height = world_y / rows
pad = 1
在显示器上布置图块很简单。 当然,这并不是目标,因为它只沿 X 轴绘制,但这是一个好的开始
j = 0
while j < rows:
tile = Tile(j * column_width, row_height, column_width - pad, row_height - pad, white)
game_board.add(tile)
j += 1
想法是变量 j
从 0 开始,因此第一个图块放置在从 0 到 column_width
的范围内,减去填充值。 然后变量 j
递增为 1,因此下一个图块放置在 column_width
值的 1 倍处,依此类推。
您可以运行该代码以查看它呈现的部分成功。 这种解决方案显然缺乏对进一步行的任何认识。
使用第二个计数器变量来跟踪行
j = 0
k = 0
while j < rows:
while k < columns:
tile = Tile(k * column_width, j * row_height, column_width - pad, row_height - pad, white)
game_board.add(tile)
k += 1
j += 1
k = 0
在此代码块中,它实现了预期的结果,每个图块都位于由 j
或 k
的当前值确定的空间中。
k
变量在其循环内递增,以便每个图块都沿 X 轴逐步放置。
j
变量在嵌套循环之外递增,以便所有内容都向下移动一行。
然后将 k
变量设置为 0,以便当内部循环再次开始时,所有内容都移回屏幕的最左侧。

(Klaatu, CC BY-SA 4.0)
简单的数组
创建网格在数学和语法上看起来可能很复杂,但通过此示例,再加上对您想要的结果进行一些思考,您可以随意生成它们。 您现在唯一剩下的就是围绕它创建一个游戏。 这就是我所做的,欢迎您通过从 Itch.io 上的主页或 git.nixnet.xyz 上的源代码存储库下载来玩它。 享受!
评论已关闭。