0% found this document useful (0 votes)
3 views60 pages

Advanced Ragdoll Systems Unity

The document is a comprehensive technical guide on advanced ragdoll systems in Unity, covering various aspects such as ragdoll physics, kinematic switching, and procedural balancing. It includes detailed chapters on setting up production-quality ragdolls, understanding Unity's architecture, and implementing features like hit reactions and death sequences. The guide aims to help developers achieve high-fidelity character responses and cinematic-quality animations in their games.

Uploaded by

vanshtryu
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views60 pages

Advanced Ragdoll Systems Unity

The document is a comprehensive technical guide on advanced ragdoll systems in Unity, covering various aspects such as ragdoll physics, kinematic switching, and procedural balancing. It includes detailed chapters on setting up production-quality ragdolls, understanding Unity's architecture, and implementing features like hit reactions and death sequences. The guide aims to help developers achieve high-fidelity character responses and cinematic-quality animations in their games.

Uploaded by

vanshtryu
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

ADVANCED

RAGDOLL SYSTEMS
IN UNITY
────────────────────────────────────────

Enhancing Anima�ons & Achieving Uncharted-Level Polish


────────────────────────────────────────
Ragdoll Physics · Blend Trees · Ac�ve Ragdoll · Kinema�c Switching
Hit Reac�ons · Death Sequences · Procedural Balancing · PD Controllers
Weighted Blend · Secondary Mo�on · Environment Response · Get-Up Logic
From Raw Physics to Cinema�c-Quality Character Response

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

Table of Contents

Chapter 1 — Understanding Ragdoll Physics — Unity's Architecture


Chapter 2 — Se�ng Up a Produc�on-Quality Ragdoll from Scratch
Chapter 3 — Kinema�c Switching — The Core Technique
Chapter 4 — Anima�on-to-Ragdoll Blending — The Uncharted Approach
Chapter 5 — Ac�ve Ragdoll — PD Controllers & Pose Matching
Chapter 6 — Hit Reac�ons — Direc�onal, Weighted & Contextual
Chapter 7 — Death Sequences — Cinema�c Ragdoll with Authored Intent
Chapter 8 — Ge�ng Back Up — Animated Recovery from Any Pose
Chapter 9 — Procedural Balancing & Physical Character Control
Chapter 10 — Environmental Response — Ragdoll Reacts to the World
Chapter 11 — Cloth, Hair & So�-Body Secondary Mo�on on Ragdolls
Chapter 12 — Uncharted & TLOU Technique Deep-Dive
Chapter 13 — Mul�-Character & NPC Ragdoll at Scale
Chapter 14 — Performance, LOD & Shipping Produc�on Ragdoll

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

— CHAPTER 1 —

Understanding Ragdoll Physics


Unity's architecture and what you are actually controlling

1.1 What a Ragdoll Actually Is


A ragdoll is a hierarchy of Rigidbodies connected by Joints, arranged to match a character's skeleton. When
physics simula�on is enabled, Unity's PhysX engine takes over the posi�on and rota�on of every bone — the
Animator loses authority. The bones fall, collide, and rotate based on gravity, forces, and collisions. This is what
you see when an enemy 'falls over dead' in most games.

The naive ragdoll — simply enabling physics and le�ng the character collapse — is one of the cheapest-looking
effects in games. It looks like a skeleton made of sacks of water. Uncharted 4's ragdoll looks nothing like this
because Naughty Dog never uses naked ragdoll physics. They always blend, always constrain, and always author
intent on top of the physics. Every technique in this guide is about that gap: from PhysX doing its default thing to
the controlled, cinema�c result.

1.2 PhysX Joint Types in Unity


Unity exposes three joint types for ragdoll construc�on. Knowing what each does at the physics level is essen�al
for tuning:

Joint Type Component Best For Key Limita�on

Character Joint CharacterJoint Spines, limbs — twist + swing No spring s�ffness — cannot drive
constraints. The standard ragdoll toward a pose.
joint.

Configurable Joint ConfigurableJoin PD controllers, ac�ve ragdoll — full Complex to configure. Easy to
t per-axis control of drive springs make unstable.
and limits.

Hinge Joint HingeJoint Simple doors, simple limb joints Only one axis of rota�on.
where only one DOF is needed. Insufficient for most anatomy.

Fixed Joint FixedJoint Welding accessories to bones, No rota�on at all. Not useful for
breakable connec�ons. limbs.

1.3 The Ragdoll Hierarchy


Every ragdoll follows the same joint parent-child rela�onship. The root Rigidbody has no joint — it is the anchor.
Every other Rigidbody has a joint whose Connected Body is its anatomical parent:

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

// Standard humanoid ragdoll hierarchy:


// (Each arrow = [Link] pointing to parent Rigidbody)

Hips (Rigidbody — root, no joint)


├── Spine → Hips
│ └── Chest → Spine
│ ├── UpperArm_L → Chest
│ │ └── Forearm_L → UpperArm_L
│ │ └── Hand_L → Forearm_L
│ ├── UpperArm_R → Chest
│ │ └── Forearm_R → UpperArm_R
│ │ └── Hand_R → Forearm_R
│ └── Head → Chest
├── UpperLeg_L → Hips
│ └── LowerLeg_L → UpperLeg_L
│ └── Foot_L → LowerLeg_L
└── UpperLeg_R → Hips
└── LowerLeg_R → UpperLeg_R
└── Foot_R → LowerLeg_R

1.4 CharacterJoint Parameters — What They Do


Parameter Type Effect

Swing 1 / Swing 2 Limit degrees Maximum lateral rota�on in each plane. Knee: Swing1=90, Swing2=0.
Shoulder: both ~60.

Twist Limit (Low/High) degrees Rota�on around the bone's own long axis. Forearm twist: Low=-90,
High=90.

Enable Projec�on bool Snaps joint back if PhysX stretches it. Set TRUE for all ragdoll joints.
Prevents 'noodle arm'.

Projec�on Distance metres Maximum stretch before snapping. 0.02–0.05m. Smaller = more stable but
slightly s�ffer.

Projec�on Angle degrees Max angular error before snapping. 5–15 degrees. Match to your joint
limits.

Break Force / Torque float Force/torque to sever the joint. Infinity = unbreakable (default). Use finite
values for dismemberment.

1.5 Physics Material Se�ngs for Ragdolls


The physics material on ragdoll colliders drama�cally affects how the body slides and bounces. These are the
produc�on-tested values:

// Create a PhysicsMaterial asset: [Link]


Dynamic Friction: 0.5 // How much friction while sliding across surfaces
Static Friction: 0.5 // Friction when nearly stopped
Bounciness: 0.0 // NEVER give ragdolls bounce — they look like rubber toys
Friction Combine: Average
Bounce Combine: Minimum // Ensures no accidental bouncing even with world materials

// PhysicsMaterial for ragdoll limbs that should slide more (clothing simulation):
Dynamic Friction: 0.3

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

Static Friction: 0.3


Bounciness: 0.0

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

— CHAPTER 2 —

Se�ng Up a Produc�on-Quality Ragdoll


Every parameter, every collider, from zero to working

2.1 Collider Configura�on — The Detail That Separates Good From Bad
The Ragdoll Wizard in Unity creates capsule colliders sized to bounding boxes. This produces fat, blobby colliders
that look wrong when the character interacts with the environment — the body hovers above surfaces, limbs clip
through each other, and the silhoue�e is all wrong. Produc�on ragdolls have hand-tuned colliders.

Guidelines for each body part:

• Hips — Use a CapsuleCollider, height ~0.3m, radius ~0.12m. Oriented horizontally. This is the body's
center of mass.
• Spine / Chest — CapsuleCollider, height ~0.25m each. Slightly wider than hips. Oriented ver�cally.
• Head — SphereCollider, radius ~0.10m. Offset forward slightly (+0.02m Z) to include the face.
• Upper Arms — CapsuleCollider, length matches bone exactly (measure in scene). Radius ~0.055m.
• Forearms — CapsuleCollider, radius ~0.045m. Slightly narrower than upper arm.
• Hands — BoxCollider, dimensions ~0.08 × 0.03 × 0.12m. Boxes work be�er than capsules here.
• Upper Legs — CapsuleCollider, radius ~0.09m. Largest limb collider — thighs are meaty.
• Lower Legs — CapsuleCollider, radius ~0.065m.
• Feet — BoxCollider, dimensions ~0.09 × 0.06 × 0.22m. Feet need flat contact with ground.

2.2 Rigidbody Mass Distribu�on


Mass distribu�on determines how the ragdoll falls and how it responds to forces. Use real human mass
propor�ons (total character mass = 70–80kg for a typical adult male):

Body Part Mass (kg) % of Total Notes

Hips 12 15% Center of mass. Highest single mass.

Spine 8 10%

Chest 10 12%

Head 5 6% Heavier than you think — head is dense.

Upper Arm (each) 2 2.5% each

Forearm (each) 1.5 1.9% each

Hand (each) 0.5 0.6% each Light — hands respond to impacts easily.

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

Upper Leg (each) 8 10% each Legs are heavy — affects falling behaviour.

Lower Leg (each) 3.5 4.4% each

Foot (each) 1 1.25% each

TOTAL ~75kg 100% Adjust propor�onally for character size.

2.3 Joint Limit Reference — Anatomically Correct Values


Joint Swing 1 Swing 2 Twist Low Twist High Notes

Spine→Hips 40 20 -20 20 Lumbar: limited but flexible

Chest→Spine 25 15 -15 15 Thoracic: less flexible

Head→Chest 40 30 -60 60 Neck is very flexible

Upper Arm→Chest 70 70 -90 90 Shoulder: large range all axes

Forearm→Upper Arm 0 140 -10 10 Elbow: hinge only, 0–140 flex

Hand→Forearm 60 30 -80 80 Wrist: flex/extend + limited twist

Upper Leg→Hips 70 50 -60 60 Hip: ball joint, large range

Lower Leg→Upper Leg 0 120 -10 10 Knee: hinge, 0–120 flex

Foot→Lower Leg 45 20 -25 25 Ankle: plantar/dorsi flex, some inversion

2.4 The RagdollBuilder Script — Programma�c Setup


Never rely solely on the Ragdoll Wizard — it creates a star�ng point, not a produc�on result. Use a custom editor
script to apply your tuned se�ngs programma�cally so they can be reapplied a�er skeleton changes:

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;

[[Link]]
public struct JointConfig
{
public string BoneName;
public float Mass;
public float Swing1, Swing2;
public float TwistLow, TwistHigh;
public ColliderType ColliderType;
public Vector3 ColliderSize; // radius/height for capsule; x/y/z for box
public Vector3 ColliderOffset;
public Vector3 ColliderAxis; // Capsule direction (0=X, 1=Y, 2=Z in local)
}

public class RagdollBuilder : EditorWindow


{
[SerializeField] private Animator _animator;
[SerializeField] private JointConfig[] _configs; // Filled from ScriptableObject
[SerializeField] private PhysicsMaterial _bodyMat;
[SerializeField] private int _ragdollLayer = 10;

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

[MenuItem("Tools/Ragdoll Builder")]
static void Open() => GetWindow<RagdollBuilder>();

void OnGUI()
{
if ([Link]("Build / Rebuild Ragdoll")) BuildRagdoll();
if ([Link]("Clear Ragdoll")) ClearRagdoll();
}

void BuildRagdoll()
{
[Link](_animator.gameObject, "Build Ragdoll");

foreach (var cfg in _configs)


{
Transform bone = FindBone([Link]);
if (bone == null) { [Link]($"Bone not found: {[Link]}");
continue; }

// Rigidbody
var rb = [Link]<Rigidbody>();
[Link] = [Link];
[Link] = 0.05f;
[Link] = 0.05f;
[Link] = [Link];
[Link] = [Link];
[Link] = true; // Start kinematic; switch at runtime

// Collider
AddCollider(bone, cfg);

// Joint (skip hips — it's the root)


if ([Link] != "Hips")
ConfigureJoint(bone, cfg);

[Link] = _ragdollLayer;
}
}

void ConfigureJoint(Transform bone, JointConfig cfg)


{
var joint = [Link]<CharacterJoint>();
[Link] = true;
[Link] = 0.02f;
[Link] = 5f;

joint.swing1Limit = new SoftJointLimit { limit = cfg.Swing1 };


joint.swing2Limit = new SoftJointLimit { limit = cfg.Swing2 };
[Link] = new SoftJointLimit { limit = [Link] };
[Link] = new SoftJointLimit { limit = [Link] };
}
}
#endif

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

— CHAPTER 3 —

Kinema�c Switching
The core technique — when code drives physics and when physics drives code

3.1 The Two Modes of a Ragdoll Bone


Every Rigidbody in your ragdoll lives in one of two modes at any moment. Understanding the difference is the
founda�on of every advanced ragdoll technique:

• Kinema�c Mode (isKinema�c = true): The Rigidbody ignores all physics forces. Its posi�on and rota�on
are driven externally — by the Animator, by your code, or by IK. It par�cipates in collision detec�on but
does not respond to collisions. The Animator is in control.
• Dynamic Mode (isKinema�c = false): PhysX owns the bone. Gravity, forces, and collisions drive it. The
Animator no longer has authority over this bone. Physics is in control.
The fundamental ragdoll technique is switching between these modes — and blending between them, which is
what separates amateur ragdoll from professional.

3.2 The Naive Switch — Why It Looks Bad


The most common implementa�on: on death, set all Rigidbodies to isKinema�c = false and disable the Animator.
The character immediately collapses. This is what you see in budget game produc�ons and it looks wrong for two
reasons: there is a visible snap as the physics instantly takes the pose (the character's posi�on and velocity are
not passed to the physics), and the physics simula�on has no memory of what the character was doing — there
is no velocity transfer.

3.3 The Produc�on Switch — Velocity Transfer


A produc�on kinema�c switch must transfer the character's current velocity to each Rigidbody at the moment of
switch. This makes the ragdoll begin with the right trajectory — a character falling from a ledge will con�nue on
the same arc, not drop straight down:

public class RagdollController : MonoBehaviour


{
[SerializeField] private Animator _animator;
[SerializeField] private Rigidbody[] _rigidbodies; // All ragdoll Rigidbodies
[SerializeField] private Collider[] _colliders; // All ragdoll Colliders
[SerializeField] private Collider _mainCollider; // Character controller
collider

// Per-bone velocity sampling for transfer

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

private Vector3[] _prevPositions;


private Quaternion[] _prevRotations;
private bool _ragdollActive;

public bool IsRagdollActive => _ragdollActive;

void Awake()
{
_prevPositions = new Vector3[_rigidbodies.Length];
_prevRotations = new Quaternion[_rigidbodies.Length];
SetKinematic(true); // Start in kinematic mode
}

void FixedUpdate()
{
// Always sample bone positions — needed for velocity transfer
if (!_ragdollActive)
{
for (int i = 0; i < _rigidbodies.Length; i++)
{
_prevPositions[i] = _rigidbodies[i].[Link];
_prevRotations[i] = _rigidbodies[i].[Link];
}
}
}

// ── Activate ragdoll — full physics handoff ──────────────────────


public void EnableRagdoll(Vector3 externalVelocity = default)
{
if (_ragdollActive) return;
_ragdollActive = true;

_animator.enabled = false;
_mainCollider.enabled = false;
SetKinematic(false);

// Transfer bone velocities from sampled motion


for (int i = 0; i < _rigidbodies.Length; i++)
{
var rb = _rigidbodies[i];

// Velocity from position delta


Vector3 boneVel = (_prevPositions[i] == [Link])
? externalVelocity
: ([Link] - _prevPositions[i]) / [Link];

// Clamp to prevent explosive launch


[Link] = [Link](boneVel + externalVelocity,
20f);

// Angular velocity from rotation delta


Quaternion rotDelta = [Link] *
[Link](_prevRotations[i]);
[Link](out float angle, out Vector3 axis);
if (angle > 180f) angle -= 360f;
[Link] = [Link](
axis * (angle * Mathf.Deg2Rad / [Link]), 20f);
}
}

// ── Deactivate — return to kinematic ──────────────────────────────


public void DisableRagdoll()
{

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

if (!_ragdollActive) return;
_ragdollActive = false;

SetKinematic(true);
_mainCollider.enabled = true;
_animator.enabled = true;
}

private void SetKinematic(bool kinematic)


{
foreach (var rb in _rigidbodies) [Link] = kinematic;
foreach (var col in _colliders) [Link] = !kinematic;
// Disable ragdoll colliders in kinematic mode to prevent self-intersection
}
}

3.4 Collision Layer Management


When ragdoll is ac�ve, the bones must collide with the world but NOT with each other (self-collision is expensive
and causes ji�er). When kinema�c, ragdoll colliders should be disabled en�rely to avoid interfering with the
character controller. This requires careful layer setup:

// Physics > Layer Collision Matrix setup:

Layer 8: Environment — collides with: everything


Layer 9: Character — your CharacterController layer
Layer 10: RagdollBones — collides with Environment only
— does NOT collide with: RagdollBones (no self-collision)
— does NOT collide with: Character (prevent ghost overlap)

// Set in Project Settings > Physics > Layer Collision Matrix


// RagdollBones row: check Environment only

// Assign layers in your RagdollBuilder:


[Link] = [Link]("RagdollBones");

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

— CHAPTER 4 —

Anima�on-to-Ragdoll Blending
The Uncharted approach — physics and anima�on coexist

4.1 Why Pure Ragdoll Looks Wrong


The instant you hand full control to PhysX, you lose everything the animator intended. A character who was
punching now collapses into a heap that has nothing to do with the punch. A character falling from a specific
pose — like a backwards stumble — immediately snaps into a generic physics fall. The authored intent
evaporates.

Naughty Dog's solu�on in Uncharted 4 and The Last of Us Part II is to never fully hand control to PhysX. Instead,
they blend between the animated pose and the simulated pose using a weighted interpola�on. The ar�st
controls how much physics influence each bone has at each moment.

4.2 Pose Blending — The Core Implementa�on


The technique: run the Animator and physics simula�on simultaneously. Each frame, read both the animator's
bone transforms and the physics simula�on's Rigidbody transforms, then lerp between them by a blend weight.
Apply the result to the actual skeleton transforms:

public class RagdollBlender : MonoBehaviour


{
[[Link]]
public struct BoneMapping
{
public Transform AnimBone; // Bone driven by Animator
public Rigidbody PhysicsBone; // Corresponding Rigidbody
[Range(0,1)] public float PhysicsWeight; // Per-bone physics influence
}

[SerializeField] private BoneMapping[] _bones;


[Range(0,1)]
[SerializeField] private float _globalPhysicsWeight = 0f;
[SerializeField] private float _blendSpeed = 5f;

// Cached pose storage


private Vector3[] _animPositions;
private Quaternion[] _animRotations;
private Vector3[] _physPositions;
private Quaternion[] _physRotations;

private float _targetWeight;


private float _currentWeight;

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

void Awake()
{
int n = _bones.Length;
_animPositions = new Vector3[n]; _animRotations = new Quaternion[n];
_physPositions = new Vector3[n]; _physRotations = new Quaternion[n];
}

// Call after Animator has run (LateUpdate) to capture animated pose


public void CaptureAnimatedPose()
{
for (int i = 0; i < _bones.Length; i++)
{
_animPositions[i] = _bones[i].[Link];
_animRotations[i] = _bones[i].[Link];
}
}

// Call after physics step to capture simulated pose


public void CapturePhysicsPose()
{
for (int i = 0; i < _bones.Length; i++)
{
_physPositions[i] = _bones[i].[Link];
_physRotations[i] = _bones[i].[Link];
}
}

// Call in LateUpdate after both poses captured — apply blend


public void ApplyBlend()
{
_currentWeight = [Link](_currentWeight, _targetWeight,
[Link] * _blendSpeed);

for (int i = 0; i < _bones.Length; i++)


{
float w = _currentWeight * _bones[i].PhysicsWeight * _globalPhysicsWeight;

_bones[i].[Link] = [Link](
_animPositions[i], _physPositions[i], w);
_bones[i].[Link] = [Link](
_animRotations[i], _physRotations[i], w);
}
}

public void SetPhysicsWeight(float weight) => _targetWeight =


Mathf.Clamp01(weight);
}

4.3 Per-Bone Weight Design — Where the Art Lives


The per-bone PhysicsWeight field in the BoneMapping is where your animator makes crea�ve decisions. These
are not technical values — they are ar�s�c choices about how each body part should behave during a specific
event. For a single punch hit reac�on:

Bone Physics Weight Reasoning

Hips 0.1 Body shi�s slightly but stays mostly animated — we want authored
stumble.

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

Spine 0.15 Small physics lean toward the hit.

Chest 0.6 Chest recoils toward the hit — high physics for realism.

Head 0.8 Head snaps back realis�cally — very high physics weight.

Hit-Side Arm 0.9 Nearly full physics on the side that was hit.

Opposite Arm 0.2 Counter-balance arm stays mostly animated.

Legs 0.05 Legs stay almost en�rely animated — footwork is authored.

4.4 The Blending State Machine


Blend weight is not a single value — it transi�ons through states over �me. Use a state machine to manage these
transi�ons:

public enum RagdollBlendState


{
Animated, // weight = 0: pure animation
BlendingIn, // weight 0→1: entering ragdoll
FullRagdoll, // weight = 1: pure physics
BlendingOut, // weight 1→0: exiting ragdoll
BlendingToGetUp, // special: blending to get-up animation pose
}

public class RagdollStateManager : MonoBehaviour


{
private RagdollBlendState _state = [Link];
private RagdollBlender _blender;
private RagdollController _controller;

[SerializeField] private float _blendInDuration = 0.1f; // Seconds to full


ragdoll
[SerializeField] private float _blendOutDuration = 0.8f; // Seconds to full
animation
[SerializeField] private float _getUpBlendDuration = 1.2f;

private float _blendTimer;

public void TriggerRagdoll(Vector3 velocity = default)


{
if (_state == [Link] ||
_state == [Link])
{
_controller.EnableRagdoll(velocity);
_state = [Link];
_blendTimer = 0f;
}
}

public void TriggerGetUp()


{
if (_state == [Link])
{
_state = [Link];
_blendTimer = 0f;
}
}

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

void Update()
{
_blendTimer += [Link];
switch (_state)
{
case [Link]:
float inT = Mathf.Clamp01(_blendTimer / _blendInDuration);
_blender.SetPhysicsWeight(inT);
if (inT >= 1f) _state = [Link];
break;

case [Link]:
float outT = 1f - Mathf.Clamp01(_blendTimer / _blendOutDuration);
_blender.SetPhysicsWeight(outT);
if (outT <= 0f)
{
_controller.DisableRagdoll();
_state = [Link];
}
break;
}
}
}

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

— CHAPTER 5 —

Ac�ve Ragdoll
PD controllers, pose matching & physical character control

5.1 What Ac�ve Ragdoll Is


A passive ragdoll does whatever physics dictates — it falls and flops. An ac�ve ragdoll uses forces to drive each
bone toward a target pose while s�ll being subject to physics. The result is a character that has both physical
weight and authored intent simultaneously.

This is the technique behind many memorable game systems: the drunk/stagger system in GTA V where Niko
physically stumbles but tries to stay upright, the balance system in games like Gang Beasts and Human Fall Flat,
and crucially, Uncharted 4's hit reac�on system where Drake physically absorbs a bullet but his legs keep trying to
maintain his stance.

The mathema�cs of ac�ve ragdoll is the PD Controller — Propor�onal-Deriva�ve control — a classic control
theory technique applied to Rigidbody torque.

5.2 The PD Controller — Mathema�cs


A PD controller applies a correc�ve torque to a Rigidbody to rotate it toward a target rota�on. The P
(propor�onal) term applies force propor�onal to the angular error — the bigger the error, the stronger the force.
The D (deriva�ve) term applies a damping force propor�onal to angular velocity — it prevents oscilla�on and
overshoot.

public static class PDController


{
// ── Core PD torque calculation ───────────────────────────────────
// Drives 'body' toward 'targetRotation' using proportional-derivative control.
// Returns the torque vector to apply via [Link]().
public static Vector3 ComputeTorque(
Rigidbody body,
Quaternion targetRotation,
float stiffness, // P gain — how strongly to correct error
float damping) // D gain — how strongly to damp velocity
{
// Compute rotation error as angle-axis
Quaternion rotError = targetRotation * [Link]([Link]);
[Link](out float errorAngle, out Vector3 errorAxis);

// Normalise angle to [-180, 180]


if (errorAngle > 180f) errorAngle -= 360f;

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

// Guard: degenerate axis when error is near zero


if ([Link] < 0.0001f) return [Link];

// P term: torque proportional to angular error


Vector3 proportional = [Link] * (errorAngle * Mathf.Deg2Rad) *
stiffness;

// D term: torque opposing angular velocity (damping)


Vector3 derivative = -[Link] * damping;

return proportional + derivative;


}

// ── Apply PD control to a Rigidbody in FixedUpdate ──────────────


public static void ApplyPD(
Rigidbody body,
Quaternion targetRotation,
float stiffness,
float damping,
float weight = 1f)
{
if (weight <= 0f) return;
Vector3 torque = ComputeTorque(body, targetRotation, stiffness, damping);
[Link](torque * weight, [Link]);
}
}

5.3 Pose-Matching Ac�ve Ragdoll


Apply PD control to every bone in the ragdoll, targe�ng the Animator's current pose. This creates a character that
physically inhabits the anima�on while s�ll responding to external forces:

public class ActiveRagdoll : MonoBehaviour


{
[[Link]]
public struct BonePDSettings
{
public Rigidbody Bone;
public Transform AnimTarget; // Corresponding animator bone
public float Stiffness;
public float Damping;
[Range(0,1)]
public float Weight; // Per-bone PD weight
}

[SerializeField] private BonePDSettings[] _bones;


[Range(0,1)]
[SerializeField] private float _globalWeight = 1f;

// Recommended stiffness/damping ranges:


// Stiff joint (spine): Stiffness=2000, Damping=100
// Medium joint (arm): Stiffness=500, Damping=50
// Loose joint (hand): Stiffness=100, Damping=20

void FixedUpdate()
{
foreach (var b in _bones)
{

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

if ([Link]) continue;

float w = _globalWeight * [Link];


[Link](
[Link],
[Link],
[Link],
[Link],
w);
}
}

public void SetGlobalWeight(float w) => _globalWeight = Mathf.Clamp01(w);


}

5.4 PD S�ffness Tuning Guide


PD controller values are the most important tuning parameters in an ac�ve ragdoll. These are ba�le-tested
star�ng points:

Body Part S�ffness Damping Behaviour

Hips / Pelvis 1500–3000 80–150 High s�ffness keeps body upright. Too high = ji�ery.

Spine 1000–2000 60–100 Moderate — spine needs to flex under impact.

Chest 800–1500 50–80

Head 300–600 30–50 Lower — head should bob and react more freely.

Upper Arms 400–800 30–60 Arms track pose but yield to collisions.

Forearms 200–400 20–40

Hands 50–150 10–20 Very low — hands flop freely.

Upper Legs 1200–2000 70–100 Legs need high s�ffness for standing.

Lower Legs 600–1000 40–70

Feet 100–300 15–30 Lower — feet conform to ground more freely.

Stability
Tip
If your ac�ve
ragdoll ji�ers
or explodes,
the most
common cause
is s�ffness too
high rela�ve to
the Rigidbody
mass. S�ffness
in the PD sense
is a force
mul�plier —

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

for a 10kg
bone, s�ffness
of 5000 applies
a 5000*error
Newton-force
every
FixedUpdate.
Reduce
s�ffness OR
increase mass,
OR reduce
Physics Fixed
Timestep to
0.01 (60Hz).
Never go
above 0.02
(50Hz) for
ac�ve ragdoll.

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

— CHAPTER 6 —

Hit Reac�ons
Direc�onal, weighted & contextual — the visceral signature of quality

6.1 Anatomy of a Hit Reac�on


A hit reac�on in a AAA game is never a single thing. In Uncharted 4, a bullet hit triggers at minimum five
simultaneous systems: a direc�onal physics impulse on the struck bone, a procedural anima�on override that
plays a hit-direc�on-matched clip, a camera punch that communicates the weight of the impact, an audio event
with posi�onal audio, and a par�cle system for blood or impact debris. All five must fire within the same frame.

The architecture that supports this is an event-driven HitEvent system that no�fies all interested systems
simultaneously, rather than having one system call another in sequence.

6.2 The HitEvent System

// HitEvent data — everything any system might need


public struct HitEvent
{
public Vector3 HitPoint; // World position of impact
public Vector3 HitDirection; // Direction of incoming force (normalized)
public Vector3 HitNormal; // Surface normal at impact point
public float Force; // Magnitude of impact (Newtons)
public HitBodyPart BodyPart; // Which body part was struck
public DamageType Type; // Bullet, explosion, melee, etc.
public float Damage;
}

public enum HitBodyPart


{ Head, Chest, UpperArmLeft, UpperArmRight, AbdomenLeft, AbdomenRight,
UpperLegLeft, UpperLegRight, LowerLegLeft, LowerLegRight }

// Central hit dispatcher — all other systems subscribe


public class HitReactionDispatcher : MonoBehaviour
{
public static event [Link]<HitEvent> OnHit;

public static void Dispatch(HitEvent evt)


{
OnHit?.Invoke(evt);
}
}

// In your damage system, replace direct damage application with:


[Link](new HitEvent
{
HitPoint = contactPoint,

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

HitDirection = bulletDirection,
HitNormal = hitNormal,
Force = bulletForce,
BodyPart = DetectBodyPart(contactPoint),
Type = [Link],
Damage = bulletDamage,
});

6.3 Physics Hit Impulse — Direc�onal Force Applica�on

public class PhysicsHitReaction : MonoBehaviour


{
[SerializeField] private RagdollController _ragdoll;
[SerializeField] private Rigidbody _hipsRb;

// Map body parts to their Rigidbodies


[SerializeField] private Rigidbody _headRb, _chestRb, _spineRb;
[SerializeField] private Rigidbody _upperArmLRb, _upperArmRRb;
[SerializeField] private Rigidbody _upperLegLRb, _upperLegRRb;

// Force scale per body part — lighter parts react more dramatically
[SerializeField] private float _headForceScale = 2.0f;
[SerializeField] private float _chestForceScale = 1.0f;
[SerializeField] private float _limbForceScale = 0.7f;

void OnEnable() => [Link] += HandleHit;


void OnDisable() => [Link] -= HandleHit;

void HandleHit(HitEvent evt)


{
Rigidbody target = GetBoneForPart([Link]);
float scale = GetForceScale([Link]);
Vector3 impulse = [Link] * [Link] * scale;

// Brief kinematic override: temporarily enable physics on hit bone


StartCoroutine(PhysicsImpulse(target, impulse, evt));
}

IEnumerator PhysicsImpulse(Rigidbody bone, Vector3 impulse, HitEvent evt)


{
// Temporarily switch hit bone to dynamic for one physics frame
bool wasKinematic = [Link];
[Link] = false;

// Apply impulse at exact hit point (not center of mass)


[Link](impulse, [Link], [Link]);

// Also push hips slightly in hit direction (body sways)


_hipsRb.isKinematic = false;
_hipsRb.AddForce([Link] * [Link] * 0.3f, [Link]);

// Hold for a few frames so impulse takes effect


yield return new WaitForFixedUpdate();
yield return new WaitForFixedUpdate();

// Return to kinematic if it wasn't physics before


if (wasKinematic)
{
[Link] = true;
_hipsRb.isKinematic = true;

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

}
}

Rigidbody GetBoneForPart(HitBodyPart part) => part switch


{
[Link] => _headRb,
[Link] => _chestRb,
[Link] => _upperArmLRb,
[Link] => _upperArmRRb,
_ => _chestRb,
};

float GetForceScale(HitBodyPart part) => part switch


{
[Link] => _headForceScale,
[Link] or [Link] => _limbForceScale,
_ => _chestForceScale,
};
}

6.4 Anima�on Hit Reac�on — Direc�on-Matched Clips


Simultaneously with the physics impulse, crossfade to an anima�on clip that matches the hit direc�on. Author
four hit-direc�on clips: Front, Back, Le�, Right. Select the correct clip by projec�ng the hit direc�on onto the
character's local axes:

public class AnimationHitReaction : MonoBehaviour


{
[SerializeField] private Animator _animator;
[SerializeField] private string _hitFront = "HitReact_Front";
[SerializeField] private string _hitBack = "HitReact_Back";
[SerializeField] private string _hitLeft = "HitReact_Left";
[SerializeField] private string _hitRight = "HitReact_Right";
[SerializeField] private string _hitHead = "HitReact_Head";
[SerializeField] private float _blendTime = 0.05f; // Fast blend — snap to
reaction

void OnEnable() => [Link] += HandleHit;


void OnDisable() => [Link] -= HandleHit;

void HandleHit(HitEvent evt)


{
// Head hit always uses head-specific clip
if ([Link] == [Link])
{ _animator.CrossFadeInFixedTime(_hitHead, _blendTime, 0); return; }

// Project hit direction to character local space


Vector3 localDir = [Link]([Link]);
string clip = SelectClip(localDir);
_animator.CrossFadeInFixedTime(clip, _blendTime, 0);
}

string SelectClip(Vector3 localDir)


{
// localDir.z positive = hit from front (force pushes back)
// localDir.z negative = hit from behind (force pushes forward)
if ([Link](localDir.z) >= [Link](localDir.x))
return localDir.z >= 0 ? _hitBack : _hitFront;

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

else
return localDir.x >= 0 ? _hitRight : _hitLeft;
}
}

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

— CHAPTER 7 —

Death Sequences
Cinema�c ragdoll with authored intent

7.1 The Death System Architecture


Death in Uncharted 4 is a mul�-phase system, not a single event. The sequence is: death trigger → brief
animated death start (0.1–0.3s of authored movement) → weighted blend into ragdoll → physics simula�on with
ac�ve ragdoll damping → se�le detec�on → idle ragdoll state. The authored start is what makes deaths look
inten�onal. The damping is what prevents them from flopping comically.

Every high-quality death you have ever seen in a game uses some variant of this sequence. The 'death anima�on'
you see is usually just the first 0.2 seconds of authored mo�on before physics takes over.

7.2 The Death Sequence Controller

public class DeathSequenceController : MonoBehaviour


{
[SerializeField] private Animator _animator;
[SerializeField] private RagdollStateManager _ragdollState;
[SerializeField] private RagdollController _ragdoll;
[SerializeField] private RagdollSettleDetector _settle;

[Header("Death Clip Names (direction-matched)")]


[SerializeField] private string _deathFront = "Death_Front";
[SerializeField] private string _deathBack = "Death_Back";
[SerializeField] private string _deathLeft = "Death_Left";
[SerializeField] private string _deathRight = "Death_Right";

[Header("Timing")]
[SerializeField] private float _authoredPhase = 0.15f; // Sec before blend-in
starts
[SerializeField] private float _blendInTime = 0.25f; // Sec to blend to full
ragdoll

[Header("Ragdoll Damping on Death")]


[SerializeField] private float _linearDamping = 3f; // Higher than default to
prevent wild flop
[SerializeField] private float _angularDamping = 5f;

private bool _isDead;

public void Die(HitEvent deathHit)


{
if (_isDead) return;
_isDead = true;
StartCoroutine(DeathSequence(deathHit));

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

IEnumerator DeathSequence(HitEvent hit)


{
// Phase 1: Play direction-matched death clip start
string clip = SelectDeathClip([Link]);
_animator.CrossFadeInFixedTime(clip, 0.05f, 0);

// Apply death damping to all bones before physics activates


ApplyDeathDamping();

// Phase 2: Brief authored moment


yield return new WaitForSeconds(_authoredPhase);

// Phase 3: Blend into ragdoll with transfer velocity from hit


_ragdollState.TriggerRagdoll([Link] * [Link] * 0.05f);

// Wait for blend-in to complete


yield return new WaitForSeconds(_blendInTime);

// Phase 4: Full physics — wait for body to settle


yield return _settle.WaitForSettle(maxWait: 6f);

// Phase 5: Settled — body is at rest


OnBodySettled();
}

void ApplyDeathDamping()
{
foreach (var rb in _ragdoll.GetComponentsInChildren<Rigidbody>())
{
[Link] = _linearDamping;
[Link] = _angularDamping;
}
}

string SelectDeathClip(Vector3 hitDir)


{
Vector3 local = [Link](hitDir);
if ([Link](local.z) >= [Link](local.x))
return local.z >= 0 ? _deathBack : _deathFront;
return local.x >= 0 ? _deathRight : _deathLeft;
}

void OnBodySettled() { /* Trigger loot prompt, death VFX, etc. */ }


}

7.3 Se�le Detec�on


Knowing when the ragdoll has stopped moving is essen�al — it triggers the idle state, get-up logic, and gameplay
prompts. Se�le detec�on checks that all bones are below a velocity threshold:

public class RagdollSettleDetector : MonoBehaviour


{
[SerializeField] private Rigidbody[] _bones;
[SerializeField] private float _settleVelocity = 0.08f; // m/s threshold
[SerializeField] private float _settleTime = 0.4f; // Must be below
threshold this long

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

private float _belowThresholdTime;

public bool IsSettled { get; private set; }

void FixedUpdate()
{
float maxVel = 0f;
foreach (var rb in _bones)
maxVel = [Link](maxVel, [Link]);

if (maxVel < _settleVelocity)


{
_belowThresholdTime += [Link];
if (_belowThresholdTime >= _settleTime) IsSettled = true;
}
else
{
_belowThresholdTime = 0f;
IsSettled = false;
}
}

public IEnumerator WaitForSettle(float maxWait = 8f)


{
float elapsed = 0f;
while (!IsSettled && elapsed < maxWait)
{
elapsed += [Link];
yield return null;
}
}
}

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

— CHAPTER 8 —

Ge�ng Back Up
Animated recovery from any physics-se�led pose

8.1 The Get-Up Problem


Ge�ng up from a ragdoll state is one of the hardest anima�on problems in games. The ragdoll can se�le in any
pose — face-down, face-up, on its side, against a wall. You cannot play a single get-up anima�on because the
star�ng pose is always different. Uncharted 4 handles this with: se�le pose classifica�on, a match pose system
that blends the rig toward the start of the get-up anima�on, then plays the authored get-up clip.

8.2 Se�le Pose Classifica�on


Classify the body's se�led orienta�on to select the correct get-up anima�on. The key metric is the pelvis's
world-up vector:

public enum SettledPose { FaceUp, FaceDown, OnSideLeft, OnSideRight }

public class SettledPoseClassifier : MonoBehaviour


{
[SerializeField] private Transform _hips;

public SettledPose Classify()


{
Vector3 hipsUp = _hips.up; // Hip bone's local up in world space
Vector3 hipsRight = _hips.right;

float dotUp = [Link](hipsUp, [Link]);


float dotRight = [Link](hipsRight, [Link]);

if (dotUp > 0.5f) return [Link];


if (dotUp < -0.5f) return [Link];
if (dotRight > 0f) return [Link];
return [Link];
}
}

8.3 Match Pose System — Bridging Physics to Anima�on


Before playing the get-up anima�on, the character's bones must match the first frame of that anima�on. A direct
switch would snap. The match pose system blends from the current physics pose to the anima�on's first frame
over 0.5–0.8 seconds:

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

public class GetUpController : MonoBehaviour


{
[SerializeField] private Animator _animator;
[SerializeField] private RagdollStateManager _ragdollState;
[SerializeField] private SettledPoseClassifier _classifier;
[SerializeField] private RagdollBlender _blender;

[Header("Get-Up Clips")]
[SerializeField] private string _getUpFaceUp = "GetUp_FaceUp";
[SerializeField] private string _getUpFaceDown = "GetUp_FaceDown";
[SerializeField] private string _getUpSideLeft = "GetUp_SideLeft";
[SerializeField] private string _getUpSideRight = "GetUp_SideRight";

[Header("Timing")]
[SerializeField] private float _matchPoseTime = 0.6f; // Blend to first frame
[SerializeField] private float _getUpBlendTime = 0.15f; // Crossfade into get-up
clip

public void StartGetUp()


{
StartCoroutine(GetUpSequence());
}

IEnumerator GetUpSequence()
{
// Step 1: Classify settled pose
SettledPose pose = _classifier.Classify();
string getUpClip = SelectGetUpClip(pose);

// Step 2: Snap Animator to first frame of get-up clip


// This positions the anim bones to match where we want to go
_animator.enabled = true;
_animator.Play(getUpClip, 0, 0f); // Force first frame, normalised time = 0
_animator.Update(0f); // Force immediate evaluation

// Step 3: Align character root to settled ragdoll position


AlignRootToHips();

// Step 4: Blend physics weight from 1 → 0 over matchPoseTime


// The body visually morphs from physics pose toward animation first frame
float elapsed = 0f;
while (elapsed < _matchPoseTime)
{
elapsed += [Link];
float t = elapsed / _matchPoseTime;
_blender.SetPhysicsWeight(1f - t); // Physics fades out
yield return null;
}

// Step 5: Disable ragdoll, play get-up animation


_ragdollState.DisableRagdollImmediate();
_animator.CrossFadeInFixedTime(getUpClip, _getUpBlendTime, 0);
}

void AlignRootToHips()
{
// Move character root so hips end up at ragdoll's current hips position
// This prevents the character from teleporting on get-up
Transform hipsPhys = GetComponent<RagdollController>().GetHipsTransform();
Vector3 offset = [Link] -
_animator.GetBoneTransform([Link]).position;
offset.y = 0f; // Don't adjust height — that's the animation's job

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

[Link] += offset;
}

string SelectGetUpClip(SettledPose pose) => pose switch


{
[Link] => _getUpFaceUp,
[Link] => _getUpFaceDown,
[Link] => _getUpSideLeft,
[Link] => _getUpSideRight,
_ => _getUpFaceUp,
};
}

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

— CHAPTER 9 —

Procedural Balancing
Physical character control — staying upright under physics forces

9.1 Balance as a Physics Problem


A character that stays upright while being pushed, shot, and thrown against walls is not using a predefined
'stumble' anima�on — it is solving a real-�me physics balancing problem. The ac�ve ragdoll described in Chapter
5 provides the founda�on. Balance adds a higher-level control layer: where should the character's center of mass
be to remain standing?

The key concept is the Support Polygon — the convex hull of the character's foot contact points. As long as the
center of mass projects within this polygon, the character can theore�cally stay upright. When the center of mass
leaves the polygon, the character will fall unless a step is taken to move a foot under the center of mass.

9.2 Center of Mass Calcula�on

public class CenterOfMassTracker : MonoBehaviour


{
[SerializeField] private Rigidbody[] _bones;

// Cache total mass to avoid recalculating every frame


private float _totalMass;

void Awake()
{
_totalMass = 0f;
foreach (var rb in _bones) _totalMass += [Link];
}

public Vector3 GetWorldCOM()


{
Vector3 weightedSum = [Link];
foreach (var rb in _bones)
weightedSum += [Link] * [Link];
return weightedSum / _totalMass;
}

// Project COM onto ground plane


public Vector3 GetGroundProjectedCOM(float groundY)
{
Vector3 com = GetWorldCOM();
return new Vector3(com.x, groundY, com.z);
}

// Is COM within the support polygon (simplified: between both feet)?


public bool IsBalanced(Vector3 leftFoot, Vector3 rightFoot, float margin = 0.05f)

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

{
Vector3 projCOM = GetGroundProjectedCOM(leftFoot.y);
// Simplified: check if COM is between the two foot positions laterally
Vector3 midpoint = (leftFoot + rightFoot) * 0.5f;
float halfBase = [Link](leftFoot, rightFoot) * 0.5f + margin;
return [Link](new Vector3(projCOM.x,0,projCOM.z),
new Vector3(midpoint.x,0,midpoint.z)) < halfBase;
}
}

9.3 Stagger System — Procedural Stumble Response


When an external force pushes the character's COM outside the support polygon, trigger a procedural stagger:
increase physics weight on the legs to let them react, temporarily reduce PD s�ffness to allow natural stumbling,
then restore s�ffness once the character has taken a recovery step:

public class StaggerSystem : MonoBehaviour


{
[SerializeField] private ActiveRagdoll _activeRagdoll;
[SerializeField] private CenterOfMassTracker _com;
[SerializeField] private float _staggerDuration = 0.4f;
[SerializeField] private float _reducedStiffnessMul = 0.3f; // 30%
stiffness during stagger
[SerializeField] private float _minForceForStagger = 200f;

private bool _staggering;

void OnEnable() => [Link] += EvaluateStagger;


void OnDisable() => [Link] -= EvaluateStagger;

void EvaluateStagger(HitEvent evt)


{
if ([Link] >= _minForceForStagger && !_staggering)
StartCoroutine(StaggerSequence());
}

IEnumerator StaggerSequence()
{
_staggering = true;

// Reduce PD stiffness — allow physical stumble


float origWeight = _activeRagdoll.GlobalWeight;
_activeRagdoll.SetGlobalWeight(origWeight * _reducedStiffnessMul);

yield return new WaitForSeconds(_staggerDuration);

// Restore stiffness — character catches themselves


float elapsed = 0f;
float restoreTime = 0.3f;
while (elapsed < restoreTime)
{
elapsed += [Link];
float t = elapsed / restoreTime;
_activeRagdoll.SetGlobalWeight([Link](
origWeight * _reducedStiffnessMul, origWeight, t));
yield return null;
}

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

_staggering = false;
}
}

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

— CHAPTER 10 —

Environmental Response
Ragdoll reacts to the world — explosions, water, slopes & debris

10.1 Explosion Response


Explosions apply a radial impulse that diminishes with distance. The key quality upgrade over simple
AddExplosionForce: apply different forces to each bone based on line-of-sight to the explosion center, and apply
a randomised upward component for visual varia�on:

public class ExplosionResponseSystem : MonoBehaviour


{
[SerializeField] private Rigidbody[] _bones;
[SerializeField] private LayerMask _obstacleMask;

public void ApplyExplosion(


Vector3 explosionPos,
float force,
float radius,
float upwardModifier = 0.4f)
{
foreach (var rb in _bones)
{
Vector3 delta = [Link] - explosionPos;
float dist = [Link];
if (dist > radius) continue;

// Line-of-sight check — bones behind cover get less force


float losMultiplier = 1f;
if ([Link](explosionPos, [Link], dist, _obstacleMask))
losMultiplier = 0.2f; // Behind cover — partial force

// Force falls off with square of distance (inverse square law)


float distFactor = 1f - Mathf.Clamp01(dist / radius);
distFactor = distFactor * distFactor; // Quadratic falloff

// Direction: away from explosion + upward component


Vector3 dir = [Link] + [Link] * upwardModifier;
[Link]();

// Add randomisation so multiple bones don't all fly the same way
dir += [Link] * 0.2f;

[Link] = false; // Ensure physics is active


[Link](dir * force * distFactor * losMultiplier, [Link]);
}
}
}

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

10.2 Water & Buoyancy


Ragdolls in water need buoyancy forces that keep bones near the surface, drag that slows mo�on, and wave
forces for visual interest. Apply per-bone based on submersion depth:

public class RagdollBuoyancy : MonoBehaviour


{
[SerializeField] private Rigidbody[] _bones;
[SerializeField] private float _waterLevel = 0f;
[SerializeField] private float _buoyancyForce = 12f; // Per kg
[SerializeField] private float _waterDrag = 3f;
[SerializeField] private float _waterAngularDrag = 3f;

// Store original drag values to restore when exiting water


private float[] _origDrag, _origAngDrag;

void Awake()
{
_origDrag = new float[_bones.Length];
_origAngDrag = new float[_bones.Length];
for (int i = 0; i < _bones.Length; i++)
{
_origDrag[i] = _bones[i].linearDamping;
_origAngDrag[i] = _bones[i].angularDamping;
}
}

void FixedUpdate()
{
for (int i = 0; i < _bones.Length; i++)
{
var rb = _bones[i];
float depth = _waterLevel - [Link].y;
float submerge = Mathf.Clamp01(depth / 0.3f); // 0.3m submersion range

if (submerge > 0)
{
// Buoyancy: upward force proportional to submersion
[Link]([Link] * _buoyancyForce * [Link] * submerge,
[Link]);

// Increased drag in water


[Link] = [Link](_origDrag[i], _waterDrag,
submerge);
[Link] = [Link](_origAngDrag[i], _waterAngularDrag,
submerge);
}
else
{
[Link] = _origDrag[i];
[Link] = _origAngDrag[i];
}
}
}
}

10.3 Ragdoll Collision Events — Thud and Impact Audio

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

High-quality ragdoll sells physical weight through audio. When bones impact surfaces above a velocity threshold,
fire an audio event:

// Attach to key bones (head, chest, hips) for impact sounds


public class BoneImpactAudio : MonoBehaviour
{
[SerializeField] private AudioSource _audioSource;
[SerializeField] private AudioClip[] _thudClips;
[SerializeField] private float _minVelocity = 1.5f; // m/s threshold
[SerializeField] private float _maxForceVolume = 8f; // m/s for max volume
[SerializeField] private float _cooldown = 0.1f;

private float _lastImpactTime;

void OnCollisionEnter(Collision collision)


{
if ([Link] - _lastImpactTime < _cooldown) return;
float impactVel = [Link];
if (impactVel < _minVelocity) return;

_lastImpactTime = [Link];
float vol = Mathf.Clamp01(impactVel / _maxForceVolume);
AudioClip clip = _thudClips[[Link](0, _thudClips.Length)];
_audioSource.pitch = [Link](0.88f, 1.12f); // Variation
_audioSource.PlayOneShot(clip, vol);
}
}

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

— CHAPTER 11 —

Cloth, Hair & So�-BodySecondary Mo�on


Adding physical life to ragdolls — beyond just bones

11.1 Unity Cloth on Ragdolls


Unity's Cloth component simulates fabric and hair. A�aching it to ragdoll characters is non-trivial because the
cloth must follow the ragdoll bones rather than sta�c posi�ons. The solu�on is to use the Cloth component's
vertex constraints to pin ver�ces to moving bones:

public class RagdollClothSetup : MonoBehaviour


{
[SerializeField] private SkinnedMeshRenderer _clothMesh;
[SerializeField] private Cloth _cloth;

[Header("Cloth Parameters — tuned for shirt material")]


[SerializeField] private float _stretchingStiffness = 0.8f;
[SerializeField] private float _bendingStiffness = 0.1f;
[SerializeField] private float _damping = 0.05f;
[SerializeField] private float _thickness = 0.02f;
[SerializeField] private Vector3 _gravity = new Vector3(0, -1f, 0); //
Reduced for floaty cloth

void Awake() => ConfigureCloth();

void ConfigureCloth()
{
_cloth.stretchingStiffness = _stretchingStiffness;
_cloth.bendingStiffness = _bendingStiffness;
_cloth.damping = _damping;
_cloth.thickness = _thickness;
_cloth.externalAcceleration = _gravity;

// Create vertex constraints from skinning weights


// Vertices with high influence from torso bones: maxDistance=0 (pinned)
// Vertices with high influence from sleeve tips: maxDistance=0.15 (free)
var coefficients = new
ClothSkinningCoefficient[_clothMesh.[Link]];
for (int i = 0; i < [Link]; i++)
{
coefficients[i] = new ClothSkinningCoefficient
{
// These values are set per-vertex in a custom tool normally.
// 0 = completely pinned to bone, positive = free to simulate
maxDistance = 0.10f,
collisionSphereDistance = 0.02f,
};
}
_cloth.coefficients = coefficients;
}

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

// On ragdoll activate: let cloth simulate freely


public void OnRagdollActivate()
{
_cloth.externalAcceleration = new Vector3(0, -2f, 0); // Full gravity
_cloth.damping = 0.02f; // Less damping — more dramatic flow
}

// On ragdoll deactivate: tighten cloth back to body


public void OnRagdollDeactivate()
{
_cloth.externalAcceleration = _gravity;
_cloth.damping = _damping;
}
}

11.2 Procedural Hair — Verlet Chain on Ragdoll


Hair is best handled as Verlet chains (see the IK guide, Chapter 11) whose anchor bone follows the ragdoll head
Rigidbody. When the head is flung around by physics, the hair chains trail behind with natural lag:

public class RagdollHairChain : MonoBehaviour


{
[SerializeField] private Transform _anchorBone; // Follows ragdoll head
Rigidbody
[SerializeField] private Transform[] _hairBones; // Hair skeleton joints
[SerializeField] private float _gravity = -3f;
[SerializeField] private float _damping = 0.96f;
[SerializeField] private float _stiffness = 0.85f; // Distance constraint
stiffness
[SerializeField] private int _iterations = 4;

private Vector3[] _positions, _prevPositions;


private float[] _lengths;

void Awake()
{
int n = _hairBones.Length;
_positions = new Vector3[n];
_prevPositions = new Vector3[n];
_lengths = new float[n - 1];

for (int i = 0; i < n; i++)


_positions[i] = _prevPositions[i] = _hairBones[i].position;
for (int i = 0; i < n - 1; i++)
_lengths[i] = [Link](_hairBones[i].position,
_hairBones[i+1].position);
}

void LateUpdate()
{
// Pin root to anchor bone (follows ragdoll head)
_positions[0] = _anchorBone.position;

float dt = [Link];
int n = _positions.Length;

// Verlet integrate
for (int i = 1; i < n; i++)

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

{
Vector3 vel = (_positions[i] - _prevPositions[i]) * _damping;
Vector3 prev = _positions[i];
_positions[i] += vel + new Vector3(0, _gravity * dt * dt, 0);
_prevPositions[i] = prev;
}

// Distance constraints
for (int iter = 0; iter < _iterations; iter++)
{
_positions[0] = _anchorBone.position; // Re-pin root each iteration
for (int i = 0; i < n - 1; i++)
{
Vector3 d = _positions[i+1] - _positions[i];
float dist = [Link];
if (dist < 0.0001f) continue;
float err = (dist - _lengths[i]) / dist * _stiffness;
_positions[i+1] -= d * err * 0.5f;
if (i > 0) _positions[i] += d * err * 0.5f;
}
}

// Apply to hair bone transforms


for (int i = 0; i < n - 1; i++)
{
_hairBones[i].rotation = [Link](
(_positions[i+1] - _positions[i]).normalized, _anchorBone.up);
}
}
}

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

— CHAPTER 12 —

Uncharted & TLOUTechnique Deep-Dive


Deconstruc�ng Naughty Dog's ragdoll benchmark

12.1 Naughty Dog's Published Techniques


Naughty Dog has published detailed GDC talks about their character physics systems across Uncharted 4 (2016)
and The Last of Us Part II (2020). Jonathan Cooper, Michael Boon, and David Suroviec have described the
following systems publicly. This is an analysis and Unity-implementa�on guide for each.

12.2 Physical Anima�on — The Founda�on


Naughty Dog calls their system 'Physical Anima�on' rather than 'ac�ve ragdoll' — a useful dis�nc�on. The
difference is framing: ac�ve ragdoll implies a character that is primarily physical. Physical anima�on implies a
character that is primarily animated but physically informed. Every system is designed to make the anima�on
look more real, not to replace it with physics.

The prac�cal implica�on: physics weight is almost always below 0.5 except during death sequences. The
animator's intent is always dominant. Physics adds secondary mo�on, reac�on, and believability — it never
overrides authored character.

12.3 The Uncharted 4 Hit System — Reconstructed


Based on observable behaviour and GDC disclosures, Uncharted 4's hit system works as follows:

1. Bullet contact detected. DamageType, HitBodyPart, and HitForce recorded.


2. HitEvent dispatched to all subscribed systems simultaneously.
3. Animator crossfades to direc�on-matched hit clip on the upper body addi�ve layer (not base layer —
Drake keeps walking).
4. Physics impulse applied to struck Rigidbody for exactly 2 FixedUpdate frames.
5. Ac�ve ragdoll s�ffness on the struck limb reduces by 70% for 0.3 seconds, then springs back.
6. Camera applies a 2-frame punch in hit direc�on, then spring-damps back.
7. Blood par�cle spawned at hit point, oriented to surface normal.
8. Audio event fires with posi�on, material, and force data — audio system selects the correct impact
sound.
9. If total accumulated damage exceeds threshold: death sequence triggers, which has its own 8-phase
sequence.

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

12.4 TLOU Part II — Rag Blend On Damage State


The Last of Us Part II introduced a more sophis�cated damage-state blend. Enemies become progressively more
physics-influenced as they take damage, crea�ng a visual degrada�on that communicates their state without
requiring explicit damage-state anima�ons:

// Damage state ragdoll influence — The Last of Us Part II approach


public class DamageStateRagdollBlend : MonoBehaviour
{
[SerializeField] private RagdollBlender _blender;
[SerializeField] private float _maxHealth = 100f;

// At full health: pure animation. At low health: partial physics everywhere.


// This is not obvious but is visible in frame-by-frame analysis of TLOU2.
private readonly AnimationCurve _physicsInfluenceCurve = new AnimationCurve(
new Keyframe(1.0f, 0.00f), // Full health = 0% physics
new Keyframe(0.5f, 0.05f), // Half health = 5% physics (subtle sway)
new Keyframe(0.2f, 0.20f), // 20% health = 20% physics (stumbling)
new Keyframe(0.0f, 0.60f) // Near-dead = 60% physics (barely standing)
);

private float _currentHealth;

public void ApplyDamage(float damage)


{
_currentHealth = [Link](0, _currentHealth - damage);
float healthRatio = _currentHealth / _maxHealth;
float physicsWeight = _physicsInfluenceCurve.Evaluate(healthRatio);
_blender.SetPhysicsWeight(physicsWeight);
}
}

12.5 The Uncharted Cinema�c Ragdoll Technique


For scripted death sequences in Uncharted 4 (cutscene deaths, set-piece deaths), Naughty Dog uses what they
call 'directed ragdoll' — a ragdoll where specific bones have scripted veloci�es applied at specific �mes. This
creates deaths that look authored but s�ll physically interact with the environment:

[[Link]]
public struct DirectedRagdollKeyframe
{
public float Time; // Seconds after ragdoll activation
public string BoneName; // Which bone
public Vector3 Impulse; // Force to apply in character local space
public ForceMode ForceMode;
}

public class DirectedRagdollSequence : MonoBehaviour


{
[SerializeField] private DirectedRagdollKeyframe[] _keyframes;
[SerializeField] private RagdollController _ragdoll;

public IEnumerator Play()


{

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

float startTime = [Link];


int kfIdx = 0;

while (kfIdx < _keyframes.Length)


{
float elapsed = [Link] - startTime;
var kf = _keyframes[kfIdx];

if (elapsed >= [Link])


{
Rigidbody bone = _ragdoll.FindBone([Link]);
if (bone != null)
{
// Convert local impulse to world space
Vector3 worldImpulse = [Link]([Link]);
[Link](worldImpulse, [Link]);
}
kfIdx++;
}
yield return null;
}
}
}

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

— CHAPTER 13 —

Mul�-Character & NPCRagdoll at Scale


Managing many ragdolls efficiently

13.1 The Performance Problem


A single ragdoll with 15 bones, ac�ve ragdoll PD control, and cloth simula�on costs approximately 0.5–1.5ms per
character. In a game with 10 enemies simultaneously ac�ve, that is 5–15ms on physics alone — most of a 16ms
frame budget. You need a �ered system.

13.2 Ragdoll Pool Manager


Never create and destroy ragdolls — pool them. Pre-instan�ate a pool of ragdoll instances and
ac�vate/deac�vate them as characters die:

public class RagdollPoolManager : MonoBehaviour


{
[SerializeField] private GameObject _ragdollPrefab;
[SerializeField] private int _poolSize = 20;
[SerializeField] private float _deactivateAfter = 30f; // Auto-deactivate
settled ragdolls

private Queue<RagdollController> _available = new Queue<RagdollController>();


private List<ActiveRagdollEntry> _active = new List<ActiveRagdollEntry>();

private struct ActiveRagdollEntry


{
public RagdollController Ragdoll;
public float ActivatedTime;
}

void Awake()
{
for (int i = 0; i < _poolSize; i++)
{
var obj = Instantiate(_ragdollPrefab);
[Link](false);
_available.Enqueue([Link]<RagdollController>());
}
}

public RagdollController Spawn(Vector3 position, Quaternion rotation)


{
if (_available.Count == 0)
{
// Reclaim oldest active ragdoll if pool is exhausted
var oldest = _active[0];
Return([Link]);

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

var ragdoll = _available.Dequeue();


[Link](position, rotation);
[Link](true);
_active.Add(new ActiveRagdollEntry { Ragdoll = ragdoll, ActivatedTime =
[Link] });
return ragdoll;
}

void Update()
{
// Auto-return settled ragdolls after timeout
for (int i = _active.Count - 1; i >= 0; i--)
{
var entry = _active[i];
if ([Link] - [Link] > _deactivateAfter)
Return([Link]);
}
}

void Return(RagdollController ragdoll)


{
[Link](false);
_active.RemoveAll(e => [Link] == ragdoll);
_available.Enqueue(ragdoll);
}
}

13.3 NPC Ragdoll LOD


Apply distance-based LOD to every ragdoll system — the same approach as IK LOD in Chapter 14 of the IK guide:

LOD Level Distance Ac�ve Systems

Full < 10m Ac�ve ragdoll PD, full cloth, hair chains, all per-bone audio

High 10–20m Ac�ve ragdoll PD, cloth only (no hair), impact audio head/chest only

Medium 20–35m Passive ragdoll only (no PD), no cloth, no audio

Low 35–60m Ragdoll joints disabled. Single Rigidbody falls. Bones locked to it.

Culled > 60m GameObject deac�vated. Returned to pool a�er se�le �me.

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

— CHAPTER 14 —

Performance, LOD &Shipping Produc�on


Ragdoll
Making all of this run at 60fps

14.1 Physics Se�ngs for Produc�on Ragdoll


These Project Se�ngs > Physics values are the founda�on of ragdoll stability. Get them right before any other
tuning:

// Project Settings > Physics — Production Ragdoll Configuration

Fixed Timestep: 0.01666 // 60Hz — REQUIRED for active ragdoll


stability
// 0.02 (50Hz) causes jitter in PD
controllers
Max Allowed Timestep: 0.03333 // 2 × Fixed Timestep — allows catchup

Gravity: (0, -15, 0) // Reduced from -20 for less flopping


Default Solver Iterations: 12 // Higher for stable joint chains
Default Solver Velocity Iterations: 6
Bounce Threshold: 1.0 // Very low — prevents micro-bouncing

// Enable these for active ragdoll specifically:


Improved Patch Friction: true
Friction Type: Two Directional Friction
Default Max Angular Speed: 100 // Clamp angular velocity — prevents
spinning

// Collision detection — set on individual Rigidbodies, not globally:


// Active bones: [Link]
// Settled bones: [Link] (cheaper)

14.2 Per-System Performance Budget


System CPU Cost (1 char) Notes

PhysX ragdoll simula�on (15 bones) ~0.15ms Built-in, well-op�mised. Minimal tuning needed.

Ac�ve ragdoll PD control ~0.08ms Per FixedUpdate. Scales with bone count.

Velocity transfer on ac�va�on one-time Negligible.


0.02ms

Ragdoll blending (pose lerp) ~0.03ms Per LateUpdate.

Se�le detec�on ~0.01ms Negligible.

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

Cloth simula�on (Unity Cloth) ~0.4ms Most expensive secondary system. LOD aggressively.

Verlet hair chains (5 chains × 8 ~0.05ms Very cheap. Keep always.


par�cles)

Bone impact audio < 0.01ms Event-driven. Negligible.

Full ac�ve ragdoll LOD=Full ~0.7–1.0ms Per character. Budget 1ms for safe margin.

14.3 Common Bugs & Fixes


Ragdoll explodes / bones fly apart
Cause: PD s�ffness too high, physics �mestep too large, or joint projec�on disabled. Fix: Enable projec�on on all
CharacterJoints. Reduce s�ffness by 50% and test. Lower Fixed Timestep to 0.01666 (60Hz).

Character snaps on ragdoll ac�va�on


Cause: Velocity transfer not implemented. The Rigidbodies start with zero velocity while the animator had the
character moving. Fix: Implement per-bone velocity transfer (Chapter 3) using sampled posi�on deltas.

Get-up anima�on plays from wrong posi�on


Cause: Character root not aligned to ragdoll hips before disabling physics. Fix: Implement AlignRootToHips()
(Chapter 8) before disabling ragdoll.

Ac�ve ragdoll ji�ers con�nuously


Cause: PD s�ffness too high for the mass, or Fixed Timestep is 0.02. Fix: Lower s�ffness un�l ji�er stops, then
increase damping to compensate for reduced stability. Set Fixed Timestep to 0.01666.

Cloth clips through ragdoll body


Cause: Cloth collision spheres not set up on ragdoll bones. Add Cloth collision spheres to all major ragdoll bones
(head, chest, hips, upper arms) via Cloth component's sphere colliders se�ngs. Set thickness to 0.02m.

Ragdoll colliders interfere with character controller


Cause: Ragdoll colliders ac�ve in kinema�c mode. Fix: Disable ragdoll colliders when isKinema�c = true (Chapter
3). Use a separate ragdoll layer that does not collide with the Character layer.

Character floats a�er ragdoll deac�va�on


Cause: Character root Y posi�on not corrected a�er se�ling. During ragdoll, the character root may dri�. Fix:
Snap character root to ground level (raycast down) before enabling CharacterController.

14.4 The Produc�on Checklist


10. All CharacterJoints have Enable Projec�on = true

For Personal Use — Achieve the Fidelity You Envision


ADVANCED RAGDOLL SYSTEMS IN UNITY · Complete Technical Guide

11. All ragdoll Rigidbodies start kinema�c — physics off by default


12. Ragdoll colliders disabled in kinema�c mode (separate layer)
13. Velocity transfer implemented on ragdoll ac�va�on
14. Per-bone damping increased on death ac�va�on to prevent wild flopping
15. Se�le detec�on implemented — body-at-rest triggers state change
16. Get-up sequence implemented with pose matching for all 4 se�le orienta�ons
17. Ac�ve ragdoll PD s�ffness tested at 60Hz fixed �mestep
18. Physics weight never exceeds 0.6 except during death sequence
19. All weight changes smoothed — no direct assignment
20. Ragdoll pool implemented — no run�me instan�a�on
21. LOD system with at least 4 distance levels
22. Cloth simula�on profiled — disabled at LOD Medium+
23. Explosion and impact audio calibrated with velocity thresholds
24. Full ragdoll stack profiled at worst-case scenario (10 ac�ve ragdolls)
25. Frame budget confirmed on target hardware

END OF GUIDE
Physics is the author's most honest collaborator.
It does not pretend. Master it, constrain it, and it will make every anima�on more true.

For Personal Use — Achieve the Fidelity You Envision

You might also like