Source file unity-csharp/3d/ControllerRigidbodyPusher.cs from the GDnD code examples. Download raw file

// GDnD wiki example (2 of 2: SimplePlayerController.cs, ControllerRigidbodyPusher.cs)
// Demonstrates: reacting to CharacterController collisions with OnControllerColliderHit.
//   A CharacterController does not push Rigidbodies by itself and is not moved by
//   physics. Unity sends OnControllerColliderHit to scripts on the controller's
//   GameObject whenever a Move call touches a collider; this script uses it to give
//   non-kinematic Rigidbodies (crates, balls) a horizontal shove.
//   Heavier bodies move less, because the push is divided by mass.
// Related pages: [[unity-character-controller]], [[3d-blocking-and-greyboxing]]
// Unity 6 (6000.x). Put it on the same GameObject as the CharacterController.
 
using UnityEngine;
 
namespace GDnD.ThreeD
{
    [RequireComponent(typeof(CharacterController))]
    public class ControllerRigidbodyPusher : MonoBehaviour
    {
        [SerializeField] private float pushStrength = 2f;   // target push speed (m/s) for a 1 kg body
        [SerializeField] private LayerMask pushableLayers = ~0;
 
        private void OnControllerColliderHit(ControllerColliderHit hit)
        {
            Rigidbody body = hit.collider.attachedRigidbody;
            if (body == null || body.isKinematic) return;
            if ((pushableLayers.value & (1 << body.gameObject.layer)) == 0) return;
 
            // Ignore things we are standing on: only push sideways.
            if (hit.moveDirection.y < -0.3f) return;
 
            Vector3 pushDirection = new Vector3(hit.moveDirection.x, 0f, hit.moveDirection.z);
            Vector3 targetVelocity = pushDirection * (pushStrength / Mathf.Max(body.mass, 0.01f));
 
            // Keep the body's own vertical velocity so it can still fall.
            body.linearVelocity = new Vector3(targetVelocity.x, body.linearVelocity.y, targetVelocity.z);
        }
    }
}