Skip to content

Instantly share code, notes, and snippets.

@majikayogames
Last active May 12, 2025 14:10
Show Gist options
  • Save majikayogames/cf013c3091e9a313e322889332eca109 to your computer and use it in GitHub Desktop.
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)
@413x1nkp
Copy link

413x1nkp commented Jul 25, 2024

For anyone in need, here's a rough 1:1 translation to C#

	private void PushAwayRigidBodies() {
		for (int i = 0; i < GetSlideCollisionCount(); i++) {
			KinematicCollision3D CollisionData = GetSlideCollision(i);

			GodotObject UnkObj = CollisionData.GetCollider();
			
			if (UnkObj is RigidBody3D) {
				RigidBody3D Obj = UnkObj as RigidBody3D;

				// Objects with more mass than us should be harder to push.
				// But doesn't really make sense to push faster than we are going
				float MassRatio = Mathf.Min(1.0f, Mass / Obj.Mass);

				// Optional add: Don't push object at all if it's 4x heavier or more
				if (MassRatio < 0.25f) continue;

				Vector3 PushDir = -CollisionData.GetNormal();

				// How much velocity the object needs to increase to match player velocity in the push direction
				float VelocityDiffInPushDir = Velocity.Dot(PushDir) - Obj.LinearVelocity.Dot(PushDir);

				// Only count velocity towards push dir, away from character
				VelocityDiffInPushDir = Mathf.Max(0.0f, VelocityDiffInPushDir);

				PushDir.Y = 0; // Don't push object from above/below

				float PushForce = MassRatio * PushForceScalar;
				Obj.ApplyImpulse(PushDir * VelocityDiffInPushDir * PushForce, CollisionData.GetPosition() - Obj.GlobalPosition);
			}
		}
	}

I'm not an expert, this translation might not be perfect, but it does seem to work as intended.
NOTE: I moved the player's MASS and PushForceScalar's declarations to the public fields of the class, here:

public partial class Player : CharacterBody3D {

	// . . .

	[Export] public float Mass = 80.0f;

	[Export] public float PushForceScalar = 5.0f;

	// . . .

@t0qen
Copy link

t0qen commented Apr 7, 2025

Thank you !

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