在Python/Pygame中创建迷宫,但不确定如何制作墙壁


import pygame, sys
from pygame.locals import *
pygame.init()
windowwidth = 600
windowheight = 800
WALLWIDTH = 30
WALLHEIGHT = 30
PLAYERWIDTH = 20
PLAYERHEIGHT = 20

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
LIMEGREEN = (50, 205, 50)
running = True
while running == True:
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == KEYDOWN:
if (event.key == K_UP or event.key == K_w):
elif (event.key == K_DOWN or event.key == K_s):
elif (event.key == K_LEFT or event.key == K_a):
elif (event.key == K_RIGHT or event.key == K_d):
thescreen = pygame.display.set_mode((windowwidth, windowheight))
pygame.display.set_caption('Maze Game')
mainclock = pygame.time.Clock()
player1 = pygame.draw.rect(thescreen, LIMEGREEN, (50, 50, PLAYERWIDTH, PLAYERHEIGHT))

我正在尝试使用Python/Pygame为学校的一个项目创建一个迷宫游戏(而不是生成器)。我到处都在寻找一种方法来创建墙,让玩家(只是一个绿色矩形)与这些墙碰撞,以及如何为此制作几个关卡。我将如何制作关卡,如何创建墙,以及如何检测玩家和墙之间的碰撞?

以下是我所知道的制作墙壁的两种最简单的方法。这两种方法都与图结构和图搜索算法一起工作,因此您可以实现";路径查找";如果你愿意的话。这一切都是我想不出来的,所以如果有任何不清楚的地方,我很抱歉,但我也提供了相关文档的链接,如果你感到困惑,你可以查看。

方法1:基于瓷砖的迷宫

这可能是在中生成映射最简单的方法,因为它可以简单地通过制作ASCII字符数组并在Python中处理它们来生成正方形";墙";对象。

以这个网格为例:

###########
#         #
#  ###### #
#S #F     #
###########

"S"表示起点,"F"表示终点。是的,这可能是最简单的";迷宫";在世界上解决,但这只是一个例子。想象一下,我可怕的ASCII数组中的每个字符都代表一个大小为N x N的方形瓦片。空格代表瓦片可以行走的字符,哈希字符代表墙"#"。

在这种类型的游戏中,墙本身就是游戏实体。特别是在Pygame的上下文中,它们继承自Sprite类。精灵类是表示实体的特殊类,或者基本上是游戏中现有的对象。它们非常特别,因为它们可以代表障碍物、墙壁、地板、天花板、玩家、敌人,你能想到的。基本上,游戏中的每个对象都可以继承精灵类。

那么是什么让Sprite课程如此特别呢?首先,你提到你在理解墙壁碰撞时有概念上的困难。Pygame中的每个精灵都有自己的Rect属性。rect属性基本上只是一个不可见的矩形,用于确定碰撞检测和绘制精灵等内容。根据定义,在纯基于瓦片的映射中;"碰撞";实体之间的定义如下:如果两个实体的矩形相互重叠,则两个实体发生碰撞。然后是Sprite类的一个方法pygame.sprite.groupcollide()。上面ASCII地图中的每一面墙都有一个宽度、高度和位置,由它们在阵列中的位置决定。因此,每个标签字符直接表示矩形,该矩形也是正方形并且具有正方形";"表面";形象

让你的玩家从精灵类继承并将他放在一个精灵组中;玩家组";。让你的墙实体从sprite类继承,并将它们放在另一个sprite组中,称之为";障碍物组";或者类似的东西。然后,你所要做的就是在游戏循环的每一帧中调用pygame.sprite.groupcollide(),并使用它返回的字典来判断玩家是否与任何精灵碰撞。如果有任何不清楚的地方,我已经提供了文档的链接。阅读Pygame文档可能会比我的答案更好地帮助你理解这一点。

所以不管怎样,你最终得到的是一本词典。我将直接引用文件来解释我的观点:

groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict
This will find collisions between all the Sprites in two groups. Collision is
determined by comparing the Sprite.rect attribute of each Sprite or by using the 
collided function if it is not None.
Every Sprite inside group1 is added to the return dictionary. The value 
for each item is the list of Sprites in group2 that intersect.

您可以在游戏循环的每次迭代中直接调用此函数之后更新玩家的移动,之前使用玩家组作为group1参数,使用障碍组作为group2参数绘制所有实体。然后你会得到以下形式的字典:

{player_in_group1: [<list of obstacles from group2 that collide with player>] }

那么你怎么处理这份清单呢?建议您定义自己的局部函数(如果您愿意,也可以将其作为播放器类的方法)来处理此问题。以下是我的高级伪代码实现,它根本不接近实际代码:

def handle_collisions(sprite_dict):
'''given sprite dict, moves all entities in group1 out of group2's
rectangle area'''
for p in sprite_dict:
for o in sprite_dict[p]:
# move p in such a way that its rectangle is no longer overlapping
# with the rectangle of o with the additional constraint that p must
# be moved **as minimally as possible.**

我不打算为你实现这个功能,因为我觉得最好把挑战留给你。:)然而,我要警告你,逻辑并没有那么简单。

顺便说一句,这种类型的迷宫/地图结构在许多流行的游戏中都有使用,包括塞尔达传说、吃豆人、炸弹人、俄罗斯方块等。这是一种经过验证的方法,因为它与游戏设计无缝集成。但不要相信我的话,有一个完整的网站可以解释为什么基于瓷砖的游戏如此强大。

方法2:基于顶点边缘的迷宫

请注意,这种方法很难实现。它完全基于图形。图中的每个空间都是玩家可以遍历的节点。决定一个实体是否被允许在两个节点之间移动(换句话说……基于限制原则的碰撞)的是,在底层无向(或有向,如果你愿意的话)图中,是否存在于这两个节点之间。

我不打算详细解释这一点,因为很难用一个答案来涵盖。如果你想使用这种方法,你只需要自己做研究,但请记住,这要困难得多,因为Pygame实际上并不太支持这种策略。如果你真的对此感兴趣,最好的起点可能是谷歌。


就这样!尝试一下我给你的信息,如果你对此有任何问题,你可以在这里或GameDev StackExchange上问另一个问题。将来,当你在SO上提问时,请确保这是一个特定的编程问题,否则你很可能会得到很多反对票。

相关内容

最新更新