ausername
ausername

Reputation: 23

How do I detect collisions between a KinematicBody2D and a RigidBody2D in Godot?

I am trying to make a simple game in Godot where a wall falls down and the player has to dodge it. The wall is a RigidBody2D with a sprite and CollisionShape2D attached. The player is a KinematicBody2D with a sprite and CollisionShape2D attached. The main scene is a Node2D with the player and wall as children of it. I have managed to get the player to detect collisions but when I emit a signal (which is connected to the wall script), the wall does nothing. I have already tried using the body_entered signal in the player script, but nothing happens. Does anybody know how to fix this?

My player script:

extends KinematicBody2D

var speed = 1300
var velocity = Vector2()
signal game_over

func get_input():
velocity = Vector2()
if Input.is_action_pressed('d'):
    velocity.x += 1
if Input.is_action_pressed('a'):
    velocity.x -= 1
velocity = velocity.normalized() * speed

func _physics_process(delta):
get_input()

move_and_slide(velocity, Vector2(0, 0), false, 4, 0.785, false)

for index in get_slide_count():
    var collision = get_slide_collision(index)
    if collision.collider.is_in_group("Level"):
        death()

func death():
    emit_signal("game_over")
    hide()

The wall script:

extends RigidBody2D

func _on_Player_game_over():
    print("player collided") #example to see if collision is detected

Upvotes: 2

Views: 3121

Answers (1)

Theraot
Theraot

Reputation: 40220

I can't tell why your code is not working. However, I would do it differently: Instead of emitting a signal, call a method on the collider:

    if collision.collider.is_in_group("Level"):
        collision.collider._on_Player_game_over()
        death()

It is probably worth giving the method a better name.

By the way, you can also check if the collider has the method. For example:

    if collision.collider.has_method("_on_Player_game_over"):
        collision.collider._on_Player_game_over()
        death()

The rest of this answer is explaining how to handle the collision on the RigidBody2D with the "body_entered" signal.

  • First make sure the RigidBody2D has contact_monitor set to true.

  • Also set its contacts_reported to a value greater than 0. There can be multiple contacts with the same body, and you need to consider possible contacts with other bodies. A value around 8 is probably OK.

  • Have the "body_entered" signal of the RigidBody2D connected to itself.

  • in the method in the RigidBody2D that handles the "body_entered" signal you would get a body parameter:

    func _on_Wall_body_enter(body):
        print("Collision")
    

    By the way, I would like to encourage to take advantage of collision layer and masks. So you can narrow what collisions the RigidBody2D even checks for.

  • Then you can filter what body it is. You can, for example:

    • Use the name:

      func _on_Wall_body_enter(body):
          if body.name == "Player":
              print("Collision with player")
      
    • Use a group:

      func _on_Wall_body_enter(body):
          if body.is_in_group("Player"):
              print("Collision with player")
      
    • Use a class name (this requires to add a class_name to the player):

      func _on_Wall_body_enter(body):
          if body is Player:
              print("Collision with player")
      
    • Check for a method:

      func _on_Wall_body_enter(body):
          if body.has_method("death"):
              print("Collision with player")
      
  • And, of course, you can call a method on it notify. For example:

    func _on_Wall_body_enter(body):
        if body is Player:
            body.death()
    

    Or

    func _on_Wall_body_enter(body):
        if body.has_method("death"):
            body.death()
    

Upvotes: 3

Related Questions