【问题标题】:Godot - Game freezes when Area2D Monitoring turned onGodot - 当 Area2D 监控打开时游戏冻结
【发布时间】:2022-01-18 07:43:36
【问题描述】:

所以当我的玩家从地图上掉下来时,我希望重新加载关卡。我使用了一个带有碰撞形状 2d 的 area2d 来创建一个区域,当玩家与该区域发生碰撞时该区域将调用一个函数。但是,当游戏在包含此代码的情况下运行时,玩家将通过几帧动画然后游戏完全冻结,我什至无法移动玩家。

func _on_Area2D_body_entered(body):
   get_tree().reload_current_scene()

如果我删除此代码,或将监控设置为关闭,然后重新运行游戏,它不会冻结。

下面是我的关卡设计截图。

Level design

任何帮助将不胜感激:) - 这是一个错误还是我在做一些愚蠢的事情?

当我在 get_tree().reload_current_scene() 行设置断点时,以下报告显示

debugger

这是否意味着玩家正在与瓷砖碰撞 - 如果是这种情况,我看不出程序在玩家接触地面之前是如何冻结的。

【问题讨论】:

  • 尝试在get_tree().reload_current_scene() 行设置断点并单步执行您的代码。看看有没有像无限循环这样的问题。
  • 想到的事情:1.自动加载导致无限循环,您可以尝试按照hola建议的方式进行步进。 2. 无法重新加载的资源(例如音乐,或其他需要在开始时加载的东西),您可以尝试在没有任何可疑资源的情况下运行。同样reload_current_scene 返回一个值,打印它,它可能会给我们一个线索。如果你去 Editor -> Open Editor Data/Settings Folder,Godot 应该打开一个文件夹,查看那里的 app_userdata 文件夹,然后是一个与你的项目名称匹配的文件夹。您可以在那里找到日志,这也可以提供有关正在发生的事情的线索。
  • “这是否意味着玩家正在与瓷砖碰撞 - 如果是这种情况,我看不出程序在玩家接触地面之前是如何冻结的。”对于碰撞调试问题,您可以在调试菜单中启用可见碰撞形状,这将在调试时将它们显示在游戏中。您还可以转到“场景”面板上的“远程”选项卡来查看调试暂停时(例如在断点上)的节点状态。
  • @Theraot 我尝试在该行上添加一个断点并单步执行。我得到了我在上面的原始帖子中编辑的报告 - 这是否表明瓷砖地图和玩家之间存在碰撞?至于像你建议的Theroat那样打印语句,0是连续输出的。我相信你可以告诉我我是游戏开发的新手(这是一个学校项目),非常感谢你们的帮助。

标签: godot gdscript


【解决方案1】:

正如我在 cmets 中所说,这一行:

get_tree().reload_current_scene()

返回一个值。

现在,您已经说过0 是“连续输出”的。在这种情况下0 表示OK,换句话说:它能够重新加载场景。问题是“持续”部分。意思是场景重新加载然后触发这段代码,然后再次重新加载,然后再次触发这段代码,以此类推。

现在,显然Area2D 正在与TileMap 发生碰撞。那讲得通。如果在加载场景时Area2D 与图块之间发生碰撞,您将获得观察到的行为。而Area2DTileMap 在场景中的定位方式支持了这个想法。


关于修复它。我将为您提供三个解决方案,其中任何一个都行得通,以及它们的缺点和注意事项:

  • 不要将Area2D 放置在与不可通过的瓷砖相交的位置。这很容易通过将Area2D 进一步向下移动,或移除与其重叠的任何图块来实现。

    这种方法的缺点是它很脆弱。您将来可能会忘记并移动Area2D 或添加瓷砖或其他使问题再次出现的东西。此外,它可能不适用于您的预期场景设计。

  • 更改collision_maskcollision_layer,使瓷砖和Area2D 不会发生碰撞。只要掩码中的位不与另一层的位重叠,反之亦然,Godot 甚至不会检查它们之间的冲突。

    这种方法的主要缺点是层数有限。

    还有一个事实是,简单地以不会发生碰撞的方式放置东西不太直观。

    为了更容易使用,请将图层分配给不同种类的事物...转到您的项目设置,在常规选项卡上的图层名称和 2D 物理下,并为它们命名(例如“环境”、“敌人” "、"敌人子弹"、"玩家"、"玩家子弹"、"物品"、"其他")。

    然后您可以在collision_layer 上为每个对象分配它们是什么,并在collision_mask 上设置它们必须与它们发生碰撞的所有东西。需要注意的是,Godot 会同时检查两种方式。

    在这种情况下,您可以将玩家角色物理对象(KinematicBody2D)的collision_layer 设置为“玩家”(或类似),并将Area2Dcollision_mask 设置为相同,所以他们相撞。将TileMapcollision_layer 设置为不在Area2Dcollision_mask 中的其他内容(例如“环境”),因此Area2DTileMap 不会发生冲突。并将玩家角色的collision_mask 设置为包含您设置为TileMap 的图层,这样玩家角色也会与它发生碰撞。我希望这是有道理的。

  • 当然,您也可以过滤Area2D,只需要一点代码。它可以检查类、节点组或物理体的名称。例如,您可以在方法的开头插入如下内容:if body.name != "player": return。这样它就会在到达reload_current_scene 之前退出方法,除非它是正确的物理体。

    这种方法的缺点是它仍在检查和注册碰撞,因此它的性能比使用collision_maskcollision_layer 更差。但它会起作用,并且对于中小型游戏来说表现还不错。

对于更复杂的情况,您可以结合使用这些方法(因为,正如我所说,层数有限,因此您需要在其之上添加过滤)。我在another answer 中有关于如何设置物理对象的更详细说明,包括此处提到的技术。

【讨论】:

  • 非常感谢你,我现在可以正常工作了?。感谢您的帮助。
猜你喜欢
  • 2018-03-30
  • 2013-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-22
  • 2020-01-09
  • 1970-01-01
相关资源
最近更新 更多