Skip to content

Instantly share code, notes, and snippets.

@majikayogames
Last active November 11, 2025 03:30
Show Gist options
  • Select an option

  • Save majikayogames/cf013c3091e9a313e322889332eca109 to your computer and use it in GitHub Desktop.

Select an option

Save majikayogames/cf013c3091e9a313e322889332eca109 to your computer and use it in GitHub Desktop.
Godot 4 CharacterBody3D to RigidBody3D Push Interaction Script
# CC0/public domain/use for whatever you want no need to credit
# Call this function directly before move_and_slide() on your CharacterBody3D script
func _push_away_rigid_bodies():
for i in get_slide_collision_count():
var c := get_slide_collision(i)
if c.get_collider() is RigidBody3D:
var push_dir = -c.get_normal()
# How much velocity the object needs to increase to match player velocity in the push direction
var velocity_diff_in_push_dir = self.velocity.dot(push_dir) - c.get_collider().linear_velocity.dot(push_dir)
# Only count velocity towards push dir, away from character
velocity_diff_in_push_dir = max(0., velocity_diff_in_push_dir)
# Objects with more mass than us should be harder to push. But doesn't really make sense to push faster than we are going
const MY_APPROX_MASS_KG = 80.0
var mass_ratio = min(1., MY_APPROX_MASS_KG / c.get_collider().mass)
# Optional add: Don't push object at all if it's 4x heavier or more
if mass_ratio < 0.25:
continue
# Don't push object from above/below
push_dir.y = 0
# 5.0 is a magic number, adjust to your needs
var push_force = mass_ratio * 5.0
c.get_collider().apply_impulse(push_dir * velocity_diff_in_push_dir * push_force, c.get_position() - c.get_collider().global_position)
@Vterebenin
Copy link

Vterebenin commented Aug 12, 2025

TY author, solved my issues.

I've translated this to godotrust if anyone needs it:

    #[func]
    fn _push_away_rigid_bodies(&mut self) {
        for slide_idx in 0..self.base().get_slide_collision_count() {
            let collision = self.base_mut().get_slide_collision(slide_idx).unwrap();
            let Some(rigid_body) = collision
                .get_collider()
                .map(|collider| collider.try_cast::<RigidBody3D>())
            else {
                continue;
            };
            if let Ok(mut rigid_body) = rigid_body {
                let mut push_dir = -collision.get_normal();
                let mut velocity_diff_in_push_dir = self.base().get_velocity().dot(push_dir)
                    - rigid_body.get_linear_velocity().dot(push_dir);
                velocity_diff_in_push_dir = velocity_diff_in_push_dir.max(0.);
                let my_mass_kg = 20.;
                let mass_ratio = (my_mass_kg / rigid_body.get_mass()).min(1.);
                if mass_ratio < 0.25 {
                    continue;
                }
                push_dir.y = 0.;
                let push_force = mass_ratio * 5.;
                rigid_body.apply_impulse(push_dir * velocity_diff_in_push_dir * push_force);
            }
        }
    }

also im no expert in rust, but this should work

@sanderfoobar
Copy link

Works quite well :-)

Thanks

2025-11-11.05-27-22.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment