Character to Rigid Body Interaction

Problem

You want your character body to interact with rigid bodies.

Solution

Note

This recipe applies equally well in both 2D and 3D nodes.

By default, a CharacterBody2D moved with move_and_slide() or move_and_collide() will not push any RigidBody2D it collides with. The rigid body doesn’t react at all, and behaves just like a StaticBody2D.

alt alt

In some cases, this might be all you need. However, if you want to be able to push the bodies, you’ll need to make some changes.

For this example, we’ll use the 2D character described in the Platform character recipe. This example uses the most common movement method for character bodies: move_and_slide(). If you’re using move_and_collide(), you’ll need to adjust the examples below accordingly.

You have two options when deciding how to interact with rigid bodies:

  1. You can just push them, ignoring physics. If you’re familiar with Godot 3.x, this is equivalent to the “infinite inertia” option.
  2. You can give them a push based on the character’s imagined “mass” and velocity. This will give you a “realistic” result - pushing heavy bodies a little, and lighter bodies a lot.

We’ll try out both options below.

Infinite Inertia

This option has its pros and cons. The biggest pro is, you don’t need any extra code. You just need to correctly set the collision layers/masks of the objects. For this example, we’ve defined three physics layers:

alt alt

For the rigid body, we’ve placed it on the “items” layer (layer 3), and left the mask at the default (masking all layers):

alt alt

Then, we’ve placed the player on the “player” layer (layer 2), and configured the mask to ignore the “items”:

alt alt

Running the game, we now see we can push the boxes around. Note that the mass of the box doesn’t matter - they’ll all be pushed the same.

alt alt

Here, you can also see the downside of this option. Because the physics of the boxes is being ignored, they can clip through walls and you can’t jump on top of them.

For some games, this will be fine. If you want to prevent the clipping, you’ll need to go with option 2.

Applying impulses

To give the colliding body a “push” we’ll need to apply an impulse. An impulse is an instantaneous “kick” - think of a bat hitting a ball. This is as opposed to a force, which is a continuous “push” on an object.

# This represents the player's inertia.
var push_force = 80.0

func _physics_process(delta):
    # after calling move_and_slide()
    for i in get_slide_collision_count():
        var c = get_slide_collision(i)
        if c.get_collider() is RigidBody2D:
            c.get_collider().apply_central_impulse(-c.get_normal() * push_force)

The collision normal points out of the rigid body, so we reverse it to point away from the character and apply the push_force factor. Now pushing works again, but it won’t force the rigid bodies through walls:

alt alt

You’ll need to adjust the push_force in relation to the mass of your rigid bodies. Too high a force will still cause clipping, while too low will prevent pushing at all.

Experiment to find the settings that work for your particular game.

Download This Project

Download the project’s example code here: https://github.com/godotrecipes/character_vs_rigid

Watch Video