与test_motion
我不建议使用 RigidBody2D 碰撞来处理此问题,因为并非每次碰撞都意味着它在地面上(例如可能撞到墙壁或天花板)。
但是,还有另一种方法:您可以使用test_motion。如果移动会导致碰撞,则返回 true(当然,实际上你没有移动)。
所以向下使用test_motion,如果检测到碰撞,则表示RigidBody2D在地面上:
if Input.is_action_just_released("ui_up") and self.test_motion(Vector2(0, 1), false):
apply_central_impulse(Vector2(0,-1000))
与RayCast2D
另一个简单的设置是使用RayCast2D。将其定位为从RigidBody2D 的CollisionShape2D 或CollisionPolygon2D 的底部向下延伸。确保RayCast2D 已启用。然后你可以检查RayCast2D是否正在碰撞来决定RigidBody2D是否可以跳跃:
if Input.is_action_just_released("ui_up") and $RayCast2D.is_colliding():
apply_central_impulse(Vector2(0,-1000))
考虑用上述方法,如果RayCast2D 检测不到东西,RigidBody2D 将无法跳转。例如,如果RayCast2D 居中,但RigidBody2D 仅部分位于地面上,则RayCast2D 什么都没有。
与Area2D
另一种选择是使用Area2D 而不是RayCast2D。其优势在于拥有自己的CollisionShape2D 或CollisionPolygon2D。您需要统计进入或存在Area2D 的实体数量:
var on_ground := 0
func _on_Area2D_body_entered(body: Node) -> void:
on_ground += 1
func _on_Area2D_body_exited(body: Node) -> void:
on_ground -= 1
当然,在你的检查中使用它来跳转:
if Input.is_action_just_released("ui_up") and on_ground > 0:
apply_central_impulse(Vector2(0,-1000))
最后我提醒你,你有碰撞层和碰撞遮罩。使用RayCast2D 或Area2D 将允许您设置与RigidBody2D 使用的掩码不同的掩码。这是一种指定并非所有 RigidBody2D 碰撞的东西都是它可以跳跃的东西的方法。
我发现Area2D 更加可靠和通用。但是,设置的工作量更大。