on_body_entered 和 on_body_exited 的 Godot 奇怪行为
Godot odd behavior with on_body_entered and on_body_exited
我有一个 KinematicBody2D(玩家)和一个 Area2D(梯子)。使用下面的代码,我得到了干净的进入和退出事件,这些事件发生在玩家触摸和离开 Area2D 对象时,例如触摸 Area2D 并打印一个“输入”。向后移动并打印一个“exit”。
func _on_Ladder_body_entered(body):
if body.name == "Hero":
print("enter")
func _on_Ladder_body_exited(body):
if body.name == "Hero":
print("exit")
这段代码出错了:
func _on_Ladder_body_entered(body):
if body.name == "Hero":
set_collision_layer_bit(0, false)
print("enter")
func _on_Ladder_body_exited(body):
if body.name == "Hero":
set_collision_layer_bit(0, true)
print("exit")
一旦玩家接触到 Area2D,我就会立即收到进入事件和退出事件。我究竟做错了什么?谢谢!
Godot 版本 3.4.2
Godot 正在按照您的指示进行操作。
调用 set_collision_layer_bit(0, false)
将禁用 KinematicBody2D
和 Area2D
之间的碰撞,这意味着它们将不再发生碰撞。由于它们停止碰撞,您会收到 "body_exited"
信号。
I want to turn off collisions so the player can pass the object and re-enable them when he passes and leaves the Area2D object
Area2D
不停止物理体(StaticBody2D
、KinematicBody2D
、RigidBody
)。一定有别的东西在做那件事。例如,如果你在梯子上添加了一个 StaticBody2D
,或者用 TileMap
制作了一个 TileMap
,那里的瓷砖有碰撞,这些可能会阻止你的 KinematicBody2D
.
我认为最简单的方法是将 Area2D
放在不同的碰撞层中,这样您就可以在不禁用 Area2D
的情况下禁用停止 KinematicBody2D
的碰撞。
其他禁用碰撞的选项包括:
- 通过将
disabled
设置为 true
来禁用 CollisionPolygon2D
或 CollisionShape2D
。注意:当 Godot 正在解决碰撞响应时,你不能这样做。为避免这种情况,请使用 set_deferred
更改 disabled
. 的值
- 通过调用
add_collision_exception_with
添加碰撞异常。使用 remove_collision_exception_with
删除异常。这是一个更细粒度的工具,应该谨慎使用(如果你要添加很多例外,更喜欢使用碰撞层和遮罩)。
附录:TileMap
的一个选项是有两个版本的图块,一个有碰撞,一个没有。并在运行时用 set_cell
交换它们。但是,请考虑改用场景。事实上,您可能希望在设计器中设置单元格,并在运行时用实际场景替换它们。见 How to use SCENES in a TILEMAP(And 9 MORE TRICKS) | Godot Engine. You may even do it only when the player gets nearby, see How to create large Sidescrolling Map in Godot?.
我有一个 KinematicBody2D(玩家)和一个 Area2D(梯子)。使用下面的代码,我得到了干净的进入和退出事件,这些事件发生在玩家触摸和离开 Area2D 对象时,例如触摸 Area2D 并打印一个“输入”。向后移动并打印一个“exit”。
func _on_Ladder_body_entered(body):
if body.name == "Hero":
print("enter")
func _on_Ladder_body_exited(body):
if body.name == "Hero":
print("exit")
这段代码出错了:
func _on_Ladder_body_entered(body):
if body.name == "Hero":
set_collision_layer_bit(0, false)
print("enter")
func _on_Ladder_body_exited(body):
if body.name == "Hero":
set_collision_layer_bit(0, true)
print("exit")
一旦玩家接触到 Area2D,我就会立即收到进入事件和退出事件。我究竟做错了什么?谢谢! Godot 版本 3.4.2
Godot 正在按照您的指示进行操作。
调用 set_collision_layer_bit(0, false)
将禁用 KinematicBody2D
和 Area2D
之间的碰撞,这意味着它们将不再发生碰撞。由于它们停止碰撞,您会收到 "body_exited"
信号。
I want to turn off collisions so the player can pass the object and re-enable them when he passes and leaves the Area2D object
Area2D
不停止物理体(StaticBody2D
、KinematicBody2D
、RigidBody
)。一定有别的东西在做那件事。例如,如果你在梯子上添加了一个 StaticBody2D
,或者用 TileMap
制作了一个 TileMap
,那里的瓷砖有碰撞,这些可能会阻止你的 KinematicBody2D
.
我认为最简单的方法是将 Area2D
放在不同的碰撞层中,这样您就可以在不禁用 Area2D
的情况下禁用停止 KinematicBody2D
的碰撞。
其他禁用碰撞的选项包括:
- 通过将
disabled
设置为true
来禁用CollisionPolygon2D
或CollisionShape2D
。注意:当 Godot 正在解决碰撞响应时,你不能这样做。为避免这种情况,请使用set_deferred
更改disabled
. 的值
- 通过调用
add_collision_exception_with
添加碰撞异常。使用remove_collision_exception_with
删除异常。这是一个更细粒度的工具,应该谨慎使用(如果你要添加很多例外,更喜欢使用碰撞层和遮罩)。
附录:TileMap
的一个选项是有两个版本的图块,一个有碰撞,一个没有。并在运行时用 set_cell
交换它们。但是,请考虑改用场景。事实上,您可能希望在设计器中设置单元格,并在运行时用实际场景替换它们。见 How to use SCENES in a TILEMAP(And 9 MORE TRICKS) | Godot Engine. You may even do it only when the player gets nearby, see How to create large Sidescrolling Map in Godot?.