微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

玩家无法在程序生成的地图中正确生成

如何解决玩家无法在程序生成的地图中正确生成

我关注了 KidsCanCode @https://www.youtube.com/watch?v=o3fwlk1NI-w 的“Godot 中的程序生成:地牢生成”,发现自己无法调试当前问题。

This specific commit代码,但我会在下面更详细地解释。

我的主场景有一个 Camera2D 节点,一个通用的 Node2D 调用房间和一个 TileMap,一切都是空的。

当脚本启动时,它会运行一个

func make_room(_pos,_size):
    position = _pos
    size = _size
    
    var s = RectangleShape2D.new()
    s.custom_solver_bias = 0.5
    s.extents = size
    $CollisionShape2D.shape = s

几次,它使用 $Rooms 填充 .add_child(r),其中 r 是具有 make_room() 函数的节点的实例。然后它会在 $Rooms.get_children() 上迭代几次以创建一个 AStar 节点来链接所有房间:

Map before carving into tilemap

当之后调用 make_map() 时,魔法就来了,它用不可行走的块填充地图,然后雕刻空白区域,这也很好用:

Map after carvinho into tilemap

一个find_start_room()调用来寻找初始房间,它还为Main脚本start_room设置了一个全局变量,用于使用{{在地图上写'Start' 1}}

当我点击“esc”时,它会运行这个简单的代码来实例化播放器:

draw_string(font,start_room.position - Vector2(125,0),"start",Color(3,4,8))

Player spawning on impossible terrain

问题出现在生成玩家时。我尝试进行一些“盲目”修复,例如在 player.position 中添加或减去 player = Player.instance() add_child(player) player.position = start_room.position + Vector2(start_room.size.x/2,start_room.size.y/2) play_mode = true 以查看是否可以使其落入房间内,但无济于事。

转向调试器没有帮助,因为变量检查器表达的位置似乎没有任何意义。

我尝试实现一个简单的“鼠标点击打印位置”:

Vector2(start_room.size.x/2,start_room.size.y/2)

还有一个“start_room”打印位置:

    print("Mouse Click/Unclick at: ",event.position)
    print("Node thing",get_node("/root/Main/TileMap").world_to_map(event.position))

当玩家移动打印位置时,直接写入角色脚本:

print(get_node("/root/Main/TileMap").world_to_map(start_room.position))

得到如下结果:

print(get_node("/root/Main/TileMap").world_to_map(self.position))

因此,玩家不会在与 start_room 相同的位置生成,并且鼠标位置信息与其他任何东西都不相同。

为什么玩家现在可以正确生成?我该如何调试这种情况?

EDIT1:用户 Theraot 提到了 RigidBody2D 如何进行一些奇怪的碰撞,据我所知,改变它们的碰撞行为应该可以解决整个问题。

代码中有一个部分 - 在生成随机房间后 - 它会删除一些房间,如下所示:

Mouse Click/Unclick at: (518,293)
Node thing(16,9)
(-142,0)
(-147,-3)

据我所知,如果房间是随机选择的,它将使用 for room in $Rooms.get_children(): if randf() < cull: room.queue_free() else: room.mode = RigidBody2D.MODE_STATIC room_positions.append(Vector3(room.position.x,room.position.y,0)) 删除,或者将其附加到 queue_free() 以供进一步处理。这意味着如果我将所有房间移动到不同的碰撞层,玩家/角色实例将与 TileMap 单独存在于同一碰撞层上。

所以我只是添加一个简单的 room_positions 将这部分代码更改为

room.collision_layer = 3

似乎没有任何改变,玩家仍然在房间外重生。

解决方法

你看到房间向外散开了吗?

您没有编写代码来移动房间。当然,代码给了他们一个随机位置。但即使您将它们的位置设置为 Vector2.ZERO,它们也会向外移动,避免重叠。

为什么?因为这些房间是 RigidBody2D,并且它们确实推动了其他物理对象。例如其他房间或玩家角色。


问题是:这些房间是 RigidBody2D,您将您的 KinematicBody2D 玩家角色放在其中一个房间之上。 RigidBody2D 将其推出。


您遵循的教程就是利用 RigidBody2D 的这种行为来传播房间。但是,在填充完 RigidBody2D 后,您不需要这些 TileMap

相反,您可以将起始位置存储在一个变量中,以便稍后放置玩家角色(您不需要偏移量 - 顺便说一下 - 房间的位置是房间的中心),然后删除 { {1}} 秒。 如果你想保留写文本的代码,你也必须修改它,所以当房间不再存在时它不会失败。

或者,您可以编辑它们的碰撞层和蒙版,这样它们就不会与玩家角色(或任何与此相关的事物发生碰撞,但您为什么希望这些 RigidBody2D 不发生任何碰撞?)。


附录后期编辑:碰撞层和遮罩无法按预期工作。

首先,碰撞层和蒙版是标志。层的值是 2 的幂(1、2、4、8...)。所以,当你把它设置为3时,就是1层加上2层。所以它仍然与1的碰撞蒙版发生碰撞。

第二,即使您将房间的碰撞层更改为 2(因此它与玩家角色拥有的碰撞掩码 1 不匹配)。玩家角色仍然有一个第 1 层,它与房间的碰撞掩码相匹配。

另见提案Make physics layers and masks logic simple and consistent

因此,您需要更改图层和蒙版。两个都。这样它们就不会发生碰撞。例如,您可以将图层和蒙版设置为 0(禁用所有碰撞)。 填充 RigidBody2D 的算法不使用图层和蒙版。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。