如何解决玩家无法在程序生成的地图中正确生成
我关注了 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
节点来链接所有房间:
当之后调用 make_map()
时,魔法就来了,它用不可行走的块填充地图,然后雕刻空白区域,这也很好用:
有一个find_start_room()
被调用来寻找初始房间,它还为Main脚本start_room
设置了一个全局变量,用于使用{{在地图上写'Start' 1}}
当我点击“esc”时,它会运行这个简单的代码来实例化播放器:
draw_string(font,start_room.position - Vector2(125,0),"start",Color(3,4,8))
问题出现在生成玩家时。我尝试进行一些“盲目”修复,例如在 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 举报,一经查实,本站将立刻删除。