Skip to content

Instantly share code, notes, and snippets.

@Drumsmasher17
Last active March 10, 2026 11:24
Show Gist options
  • Select an option

  • Save Drumsmasher17/bf59918cf9105682e8f2dd68484098b1 to your computer and use it in GitHub Desktop.

Select an option

Save Drumsmasher17/bf59918cf9105682e8f2dd68484098b1 to your computer and use it in GitHub Desktop.
A copy of Valve's physics following logic as seen in 'The Lab'
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PhysicsFollow : MonoBehaviour
{
public Transform follow;
public Rigidbody rb;
void FixedUpdate()
{
if (rb == null)
{
return;
}
Vector3 velocityTarget, angularTarget;
bool success = GetUpdatedAttachedVelocities(follow, out velocityTarget, out angularTarget);
if (success)
{
float maxAngularVelocityChange = MaxAngularVelocityChange;
float maxVelocityChange = MaxVelocityChange;
rb.velocity = Vector3.MoveTowards(rb.velocity, velocityTarget, maxVelocityChange);
rb.angularVelocity = Vector3.MoveTowards(rb.angularVelocity, angularTarget, maxAngularVelocityChange);
}
}
// Magic Numbers
const float MaxVelocityChange = 10f; /// 10f
const float velocityMagic = 6000f; /// 6000f
const float AngularVelocityMagic = 50f; /// 50f
const float MaxAngularVelocityChange = 20f; /// 20f
protected bool GetUpdatedAttachedVelocities(Transform target, out Vector3 velocityTarget, out Vector3 angularTarget)
{
bool realNumbers = false;
Vector3 positionDelta = (target.position - transform.position);
velocityTarget = (positionDelta * velocityMagic * Time.deltaTime);
if (float.IsNaN(velocityTarget.x) == false && float.IsInfinity(velocityTarget.x) == false)
{
realNumbers = true;
}
else
{
velocityTarget = Vector3.zero;
}
Quaternion targetItemRotation = target.rotation;
Quaternion rotationDelta = targetItemRotation * Quaternion.Inverse(transform.rotation);
float angle;
Vector3 axis;
rotationDelta.ToAngleAxis(out angle, out axis);
if (angle > 180)
{
angle -= 360;
}
if (angle != 0 && float.IsNaN(axis.x) == false && float.IsInfinity(axis.x) == false)
{
angularTarget = angle * axis * AngularVelocityMagic * Time.deltaTime;
realNumbers &= true;
}
else
{
angularTarget = Vector3.zero;
}
return realNumbers;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment