A single falling box is easy: one rigid body, one collider, gravity does the rest. Most interesting things in a game are not single boxes. A character's skeleton is a dozen or more bones that all have to move together and stay connected at the joints. A cape or a ponytail is dozens of points that have to stay roughly the same distance apart while still swinging freely. This chapter is about simulating many connected pieces at once instead of one isolated body: ragdolls (a skeleton turned into physics-driven rigid bodies), cloth (a grid of points linked by distance constraints), and briefly soft bodies (squishy, jelly-like volumes).
The two halves of this chapter reach for two different tools to solve the same underlying problem: many pieces, connected, that must move as one system. Ragdolls use full rigid bodies and joints, the same building blocks from earlier physics chapters, just wired together into a chain. Cloth and soft bodies use something lighter: plain points with no rotation, stepped forward with the Verlet integration you already met in the calculus chapter (chapter 2.5, section 7), held together with simple distance constraints instead of full physics joints. By the end of this chapter you will know how to set up a ragdoll that dies and gets back up, and how to write your own cloth or rope simulation from scratch.
Normally a character's skeleton is driven by animation: the Animator plays back a walk cycle or a punch, setting every bone's rotation from keyframes an artist authored ahead of time. That looks great for anything the animator planned for, but it cannot react to being hit by an explosion, tripping on stairs, or landing on a slope — the animation is baked in advance and plays the same way no matter what physically happens around the character. A ragdoll replaces that baked animation with real physics: every bone becomes its own small rigid body (a solid object physics can push, pull, and rotate), wrapped in a collider so it can hit the ground and other objects, and connected to its neighboring bones with a joint (a physics constraint that keeps two rigid bodies attached at a point, usually limiting how far they can rotate relative to each other). Gravity, collisions, and impact forces move the whole chain, and it flops the way a real unconscious body would.
Two things make this diagram different from a plain animation skeleton. First, every box is a real physics object with mass and a collider, not just a transform an animator moves. Second, every connector is a joint, and not all joints are the same kind — an elbow only bends in one plane, so it gets a hinge joint, while a shoulder can swing much more freely, so it gets a cone joint. Sections 2 and 3 build exactly this structure in code; section 4 covers switching a character between animated and ragdoll mode.
Building a ragdoll by hand means visiting every bone in the skeleton and giving it three things: a collider shaped roughly like that body part (usually a capsule, since limbs are roughly capsule-shaped), a Rigidbody so physics can move it, and — for every bone except the root (usually the pelvis or hips) — a joint connecting it to its parent bone's Rigidbody. Unity ships a "Ragdoll Wizard" that does this for a humanoid automatically, but it helps to see what it is actually doing, since you will need the same steps for a non-humanoid creature, or to tweak the result by hand:
using UnityEngine;
// One entry per bone we want to turn into a physics body.
public class RagdollBone
{
public Transform bone;
public Transform parentBone; // null for the root bone (e.g. the pelvis)
public float radius;
public bool isLimb; // true = hinge (elbow, knee), false = cone (shoulder, hip, spine)
}
public class RagdollBuilder : MonoBehaviour
{
public RagdollBone[] bones;
void Start()
{
foreach (RagdollBone rb in bones)
{
CapsuleCollider col = rb.bone.gameObject.AddComponent<CapsuleCollider>();
col.radius = rb.radius;
Rigidbody body = rb.bone.gameObject.AddComponent<Rigidbody>();
body.mass = 1f;
if (rb.parentBone == null) continue; // root bone has no joint to a parent
Rigidbody parentBody = rb.parentBone.GetComponent<Rigidbody>();
if (rb.isLimb)
{
HingeJoint hinge = rb.bone.gameObject.AddComponent<HingeJoint>();
hinge.connectedBody = parentBody;
hinge.useLimits = true;
JointLimits lim = hinge.limits;
lim.min = 0f;
lim.max = 140f;
hinge.limits = lim;
}
else
{
CharacterJoint cone = rb.bone.gameObject.AddComponent<CharacterJoint>();
cone.connectedBody = parentBody;
cone.swing1Limit = new SoftJointLimit { limit = 70f };
cone.swing2Limit = new SoftJointLimit { limit = 50f };
}
}
}
}
Worked trace: with bones set up for a simple biped (pelvis as root, spine, chest, two upper arms, two forearms, two upper legs, two lower legs), this loop runs once per bone. The pelvis gets a collider and a Rigidbody and then continues, since it has no parent. Every other bone gets a collider, a Rigidbody, and either a HingeJoint (if isLimb is true, for elbows and knees) or a CharacterJoint (for everything else — shoulders, hips, spine, neck) connected back to its parent's Rigidbody. After Start() finishes, the whole skeleton is a chain of rigid bodies held together by joints, ready to react to gravity and collisions the moment something enables physics on it — which is exactly what section 4 does.
A joint with no limits at all will let a bone spin freely in any direction, which makes a ragdoll look like a pile of rubber, not a body. Real joints in the human body only move in specific ways, and Unity's ragdoll joints model two of the most common shapes.
A hinge joint (Unity's HingeJoint) only allows rotation around a single axis, between a min and a max angle — exactly what an elbow or a knee does; it cannot bend sideways or twist. A cone (or "ball-and-socket") joint allows rotation within a cone shape around a resting direction, plus a separate twist limit around the bone's own long axis — that is what a shoulder or a hip does, and Unity's CharacterJoint is built specifically for this, with swing1Limit and swing2Limit controlling the width of the cone in two directions, and lowTwistLimit / highTwistLimit controlling the twist:
using UnityEngine;
public class ShoulderExample : MonoBehaviour
{
public Transform shoulderBone;
public Transform torsoBone;
void Start()
{
CharacterJoint shoulder = shoulderBone.gameObject.AddComponent<CharacterJoint>();
shoulder.connectedBody = torsoBone.GetComponent<Rigidbody>();
shoulder.swing1Limit = new SoftJointLimit { limit = 80f }; // forward / back swing
shoulder.swing2Limit = new SoftJointLimit { limit = 60f }; // side swing
shoulder.lowTwistLimit = new SoftJointLimit { limit = -20f };
shoulder.highTwistLimit = new SoftJointLimit { limit = 90f };
}
}
An elbow, by contrast, only needs a single min/max range around one axis:
using UnityEngine;
public class ElbowExample : MonoBehaviour
{
public Transform elbowBone;
public Transform upperArmBone;
void Start()
{
HingeJoint elbow = elbowBone.gameObject.AddComponent<HingeJoint>();
elbow.connectedBody = upperArmBone.GetComponent<Rigidbody>();
elbow.axis = new Vector3(0f, 1f, 0f); // the one axis the elbow bends around
elbow.useLimits = true;
JointLimits limits = elbow.limits;
limits.min = 0f; // fully straight
limits.max = 150f; // fully bent
elbow.limits = limits;
}
}
Without these limits, a falling ragdoll's elbow could bend backwards into an impossible shape, or its shoulder could rotate the arm all the way around like a propeller. With them, the ragdoll settles into poses that look, at worst, like an unconscious body — never like a broken toy. Getting these limit numbers right is mostly trial and error: start with generous limits, drop a test ragdoll from a height, and tighten any joint that bends somewhere a real one could not.
A character normally has its bones fully driven by the Animator, with every bone's Rigidbody.isKinematic set to true. A kinematic rigid body ignores gravity and forces — it only moves when something (here, the Animator) directly sets its transform every frame. While a body is kinematic, any joint attached to it has nothing to actually constrain; the joint exists in the scene, but is not doing anything, since the Animator is already deciding where the bone goes. Turning a character into a ragdoll means flipping that switch: disable the Animator, and set every bone's Rigidbody back to non-kinematic, so gravity, collisions, and the joint limits from sections 2 and 3 take over completely.
using UnityEngine;
public class RagdollController : MonoBehaviour
{
public Animator animator;
public Rigidbody[] ragdollBodies; // every bone's Rigidbody, collected once in Start()
void Start()
{
SetRagdoll(false); // start fully animated
}
public void SetRagdoll(bool enabled)
{
animator.enabled = !enabled;
foreach (Rigidbody body in ragdollBodies)
body.isKinematic = !enabled;
}
public void Die(Vector3 hitPoint, Vector3 hitForce)
{
SetRagdoll(true);
Rigidbody nearest = FindNearestBody(hitPoint);
nearest.AddForceAtPosition(hitForce, hitPoint, ForceMode.Impulse);
}
Rigidbody FindNearestBody(Vector3 point)
{
Rigidbody best = ragdollBodies[0];
float bestDist = Vector3.Distance(point, best.position);
foreach (Rigidbody body in ragdollBodies)
{
float d = Vector3.Distance(point, body.position);
if (d < bestDist) { bestDist = d; best = body; }
}
return best;
}
}
Worked trace: before Die() is ever called, SetRagdoll(false) has run, so animator.enabled is true and every bone is kinematic — the character walks, attacks, and idles exactly like normal, and none of its joints do anything. When something calls Die(hitPoint, hitForce) — say, a rocket explosion at the character's chest — SetRagdoll(true) disables the Animator and flips every bone to non-kinematic in one pass, so the whole skeleton instantly starts falling under gravity. FindNearestBody then picks whichever bone was closest to the explosion (probably the chest or a nearby arm) and applies the explosion's force directly to that one bone as an impulse; because every bone is now connected through joints, that single push travels down the chain — the chest yanks the connected arms and head, which yank their own children — and the whole body flops away from the blast realistically, obeying every hinge and cone limit set up in sections 2 and 3.
Turning a character into a ragdoll is easy. Getting it back onto its feet, smoothly, is the harder half. The ragdoll can come to rest in almost any pose — face down, face up, twisted sideways — and a game usually wants to play a matching "get up" animation and have the character's bones glide from wherever physics left them into that animation, instead of snapping instantly (which looks like a glitch). The standard trick is to snapshot every bone's position and rotation the instant the ragdoll stops being simulated, re-enable the Animator so it starts driving bones toward the get-up clip again, and then blend — interpolate — from the snapshot toward whatever the Animator is now producing, over a short window of time.
using System.Collections;
using UnityEngine;
public class GetUpBlend : MonoBehaviour
{
public Animator animator;
public Transform[] bones; // every bone the ragdoll used
public float blendTime = 0.4f;
Vector3[] ragdollPos;
Quaternion[] ragdollRot;
public void StartGetUp()
{
// 1. snapshot exactly where physics left every bone
ragdollPos = new Vector3[bones.Length];
ragdollRot = new Quaternion[bones.Length];
for (int i = 0; i < bones.Length; i++)
{
ragdollPos[i] = bones[i].position;
ragdollRot[i] = bones[i].rotation;
}
animator.enabled = true; // animator starts driving bones again
animator.Play(ChooseGetUpClip()); // e.g. "GetUpFront" or "GetUpBack"
StartCoroutine(BlendToAnimation());
}
string ChooseGetUpClip()
{
// lying face-down if the chest's local up axis points toward the ground
return (transform.up.y < 0f) ? "GetUpFront" : "GetUpBack";
}
IEnumerator BlendToAnimation()
{
float t = 0f;
while (t < blendTime)
{
t += Time.deltaTime;
float alpha = t / blendTime;
for (int i = 0; i < bones.Length; i++)
{
// blend FROM the frozen ragdoll snapshot TOWARD wherever the
// Animator just wrote this bone this frame
bones[i].position = Vector3.Lerp(ragdollPos[i], bones[i].position, alpha);
bones[i].rotation = Quaternion.Slerp(ragdollRot[i], bones[i].rotation, alpha);
}
yield return null;
}
}
}
Worked trace: the instant StartGetUp() runs, every bone's current world position and rotation (wherever the ragdoll flopped to) is copied into ragdollPos / ragdollRot. The Animator is switched back on and told to play a get-up clip chosen by a very simple check — if the character's "up" direction is pointing down, it must be lying face down, so it plays a front get-up clip, and vice versa. For the next blendTime seconds, each frame the Animator writes its own animated pose into every bone first (that is what bones[i].position already contains going into the loop body), and the coroutine then overwrites it with a Lerp/Slerp between the frozen ragdoll snapshot and that freshly-animated pose. At alpha = 0 the bone is still exactly where the ragdoll left it; at alpha = 1 it is exactly where the animation wants it; in between, it glides smoothly from one to the other. Once t passes blendTime, the coroutine stops touching the bones, and the Animator drives them on its own from then on.
A ragdoll is a small number of rigid bodies (a dozen or two bones). Cloth is the opposite extreme: hundreds of tiny points, each one far too light and too numerous to give its own collider and Rigidbody. The classic way to think about cloth is the mass-spring model: imagine cloth as a grid of point masses, each one connected to its neighbors by springs that pull it back toward a rest distance whenever it stretches or compresses.
You could simulate that literally with Hooke's law from the calculus chapter (F = -k * stretch) and step it forward with an integrator. In practice this works badly: cloth springs need to be very stiff (a high k) to feel like real fabric instead of a jelly, and section 5 of chapter 2.5 already showed that a stiff, fast-changing force pushes even a stable integrator toward instability unless dt is made very small — small enough that a literal spring-based cloth becomes too slow to run every frame. The fix games actually use is position-based dynamics (PBD): instead of computing a spring force and integrating it, treat each spring as a hard distance constraint ("these two points must be exactly restLength apart") and directly nudge the two points toward satisfying it — exactly the satisfyDistance idea you already saw at the end of section 7 in chapter 2.5. Combine that with Verlet integration (which only needs current and previous position, no separate velocity to keep in sync) and you get a cloth simulation that is both cheap and numerically stable.
Real cloth code usually adds two more kinds of constraint besides the horizontal/vertical ones drawn above: shear constraints (diagonal, connecting each particle to the neighbors one step over on both axes, which stops the grid from collapsing into a thin sliver) and bend constraints (connecting a particle to the neighbor two steps away in a straight line, which resists sharp folding and keeps cloth from crumpling too easily). All three kinds are solved with the exact same satisfyDistance-style code — only the pair of particles and the rest length change — so adding them later is cheap once the basic solver from the next two sections is working.
The simplest possible cloth-like object is a rope: a single chain of particles, each one connected to the next by a distance constraint, with the first particle pinned in place. Building this first, before jumping to a full 2D grid, makes the moving parts easy to see.
#include <cstdio>
#include <cmath>
const int N = 6; // number of particles in the rope
const float REST = 0.5f; // rest length of each segment
const float GRAVITY = -9.8f;
const float DT = 1.0f / 60.0f;
struct Particle {
float x, y;
float px, py; // previous position (this is what makes it Verlet)
bool pinned;
};
Particle rope[N];
void initRope() {
for (int i = 0; i < N; i++) {
rope[i].x = i * REST;
rope[i].y = 0.0f;
rope[i].px = rope[i].x; // starts at rest, implied velocity 0
rope[i].py = rope[i].y;
rope[i].pinned = (i == 0); // pin only the first particle
}
}
void integrate() {
for (int i = 0; i < N; i++) {
Particle& p = rope[i];
if (p.pinned) continue;
float newX = 2*p.x - p.px; // no horizontal force
float newY = 2*p.y - p.py + GRAVITY * DT*DT; // Verlet step from ch 2.5
p.px = p.x; p.py = p.y;
p.x = newX; p.y = newY;
}
}
void satisfyConstraint(Particle& a, Particle& b, float rest) {
float dx = b.x - a.x, dy = b.y - a.y;
float dist = std::sqrt(dx*dx + dy*dy);
if (dist < 1e-6f) return;
float diff = (dist - rest) / dist;
float moveA = a.pinned ? 0.0f : (b.pinned ? 1.0f : 0.5f);
float moveB = b.pinned ? 0.0f : (a.pinned ? 1.0f : 0.5f);
a.x += dx * moveA * diff;
a.y += dy * moveA * diff;
b.x -= dx * moveB * diff;
b.y -= dy * moveB * diff;
}
void relaxConstraints(int iterations) {
for (int it = 0; it < iterations; it++) {
for (int i = 0; i < N - 1; i++) {
satisfyConstraint(rope[i], rope[i+1], REST);
}
}
}
int main() {
initRope();
for (int frame = 0; frame < 3; frame++) {
integrate();
relaxConstraints(5); // a handful of passes to settle every segment
printf("frame %d: tip = (%.4f, %.4f)\n", frame, rope[N-1].x, rope[N-1].y);
}
}
Output:
frame 0: tip = (2.5000, -0.0027)
frame 1: tip = (2.5000, -0.0082)
frame 2: tip = (2.4999, -0.0163)
The tip barely drops in these first three frames — that is expected, since gravity has only had 3 * (1/60) seconds to act, and the rope segments are stiff enough that most of the sag is still building up. Notice the loop shape: integrate() runs once per frame and moves every free particle by a plain Verlet step, exactly like chapter 2.5 section 7; relaxConstraints(5) then runs the pairwise satisfyConstraint fix-up five times in a row over the whole chain, not once. That repetition matters — fixing the distance between particles 0 and 1 can slightly stretch the just-fixed distance between particles 1 and 2, so a single pass over the chain never leaves every segment perfectly at rest length. Running several passes (this is the "constraint relaxation" from the section title) lets the small leftover errors settle down each time, the same way each rectangle in a Riemann sum only approximates the true area, but adding more of them gets you closer to the truth.
Cloth is the same idea as the rope in section 7, just extended to two dimensions: a grid of particles instead of a single chain, with a horizontal constraint to the particle on the right and a vertical constraint to the particle below, for every particle that has one. The snippet below only handles the simulation step — feeding the resulting positions into a Mesh's vertices to actually draw the cloth is ordinary Unity rendering code and is left out here to keep the physics clear.
using System.Collections.Generic;
using UnityEngine;
public class VerletCloth : MonoBehaviour
{
public int cols = 12;
public int rows = 10;
public float spacing = 0.2f;
public int solverIterations = 8;
public Vector3 gravity = new Vector3(0f, -9.8f, 0f);
struct Constraint { public int a, b; public float restLength; }
Vector3[] pos;
Vector3[] prevPos;
bool[] pinned;
Constraint[] constraints;
void Start()
{
int count = cols * rows;
pos = new Vector3[count];
prevPos = new Vector3[count];
pinned = new bool[count];
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < cols; x++)
{
int i = y * cols + x;
pos[i] = transform.position + new Vector3(x * spacing, -y * spacing, 0f);
prevPos[i] = pos[i]; // starts at rest, implied velocity 0
pinned[i] = (y == 0); // pin the whole top row -- e.g. a cape's collar
}
}
BuildConstraints();
}
void BuildConstraints()
{
var list = new List<Constraint>();
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < cols; x++)
{
int i = y * cols + x;
if (x < cols - 1) list.Add(new Constraint { a = i, b = i + 1, restLength = spacing }); // horizontal
if (y < rows - 1) list.Add(new Constraint { a = i, b = i + cols, restLength = spacing }); // vertical
}
}
constraints = list.ToArray();
}
void Update()
{
float dt = Mathf.Min(Time.deltaTime, 1f / 30f); // clamp -- same idea as ch 2.5's accumulator clamp
Integrate(dt);
for (int it = 0; it < solverIterations; it++)
SatisfyConstraints();
}
void Integrate(float dt)
{
for (int i = 0; i < pos.Length; i++)
{
if (pinned[i]) continue;
Vector3 current = pos[i];
Vector3 velocity = current - prevPos[i]; // implied velocity, Verlet-style
Vector3 next = current + velocity + gravity * dt * dt;
prevPos[i] = current;
pos[i] = next;
}
}
void SatisfyConstraints()
{
foreach (Constraint c in constraints)
{
Vector3 delta = pos[c.b] - pos[c.a];
float dist = delta.magnitude;
if (dist < 1e-6f) continue;
float diff = (dist - c.restLength) / dist;
float moveA = pinned[c.a] ? 0f : (pinned[c.b] ? 1f : 0.5f);
float moveB = pinned[c.b] ? 0f : (pinned[c.a] ? 1f : 0.5f);
pos[c.a] += delta * moveA * diff;
pos[c.b] -= delta * moveB * diff;
}
}
}
Worked trace: Start() lays out cols * rows particles in a flat grid below transform.position, and pins every particle in row 0 — the whole top edge hangs from nothing and never moves, exactly like the pinned first particle in the rope. BuildConstraints() walks the same grid and records one horizontal constraint to the particle on the right and one vertical constraint to the particle below, for every particle that has one, giving roughly 2 * cols * rows constraints in total. Every Update(), each unpinned particle takes one Verlet step using gravity, and then SatisfyConstraints() runs solverIterations times over every constraint — the cloth equivalent of relaxConstraints from section 7. Because row 0 is pinned, the rest of the grid sags downward under its own implied weight and settles into a hanging sheet, anchored along the top edge.
Pinning a fixed row works for a curtain, but a cape or a skirt is usually pinned to a bone that is itself moving (a neck bone, a waist bone). To make a pinned particle follow a moving bone instead of staying frozen in world space, set both pos[i] and prevPos[i] to the bone's current position every frame, before Integrate() runs — setting both, not just pos[i], is what keeps the implied velocity at that point from spiking to some huge, wrong value the instant the bone moves.
A soft body takes the same particle-and-constraint idea and extends it from a flat sheet (cloth) into a solid, squishy volume — think of a blob of jelly, a soft fruit, or a bouncy enemy creature. Instead of one layer of particles, imagine a whole 3D lattice of them filling the shape, connected by distance constraints in every direction, not just across a surface.
Plain distance constraints alone are not quite enough for a convincing soft body — a lattice held together only by distance constraints between neighbors can still slowly flatten out under enough pressure, since satisfying each local constraint does not guarantee the overall shape or volume is preserved. Games and simulation tools add one more idea on top: shape matching, where every particle also remembers an offset from the object's rest shape, and each frame is pulled a little bit toward where that offset says it "should" be, relative to the blob's current average position and orientation:
// shape matching, concept-level pseudocode -- not a full implementation
for each particle i:
goalPos[i] = currentCenterOfMass
+ currentOrientation * restOffset[i] // where i "should" be right now
pos[i] = lerp(pos[i], goalPos[i], stiffness) // nudge it partway there
Working out currentOrientation — the best-fit rotation of the whole blob compared to its rest pose — is the genuinely hard part of shape matching, and it is out of scope for this chapter; treat this section as the concept-level map, not a build-it-yourself recipe. The important idea to take away is that cloth, rope, and soft bodies are all the same family of technique — particles, Verlet integration, and constraints — with soft bodies simply adding a volume-preserving pull on top of the same distance-constraint machinery from sections 6 to 8.
Character cloth shows up constantly in anime-style games — flowing capes, pleated skirts, twin-tails and ponytails that swing with movement. All three reuse the same rope/grid building blocks from sections 7 and 8:
The cost of all of this is real and adds up fast. Three things drive it: the number of particles (a bigger grid means more integration work and more constraints), the number of solver iterations (section 7's trade-off — more passes look better but cost proportionally more), and collision — checking cloth particles against the character's own body so a skirt does not clip straight through a leg. Full per-particle self-collision (every particle checked against every other particle and the whole body mesh) is expensive enough that most games skip it entirely for hair and only apply a handful of cheap capsule colliders along the body for cloth, accepting occasional minor clipping instead. All of this cost is paid once per cloth-wearing character, per frame — a single hero character with a fancy cape is cheap; a crowd scene with fifty background characters each wearing similar outfits is not, unless something backs off the simulation for the ones the player is not looking closely at.
void Update()
{
float dist = Vector3.Distance(Camera.main.transform.position, transform.position);
int iterations = dist > 15f ? 2 : solverIterations; // fewer relax passes far away
bool freeze = dist > 40f; // stop simulating entirely when far off
if (freeze) return;
float dt = Mathf.Min(Time.deltaTime, 1f / 30f);
Integrate(dt);
for (int it = 0; it < iterations; it++)
SatisfyConstraints();
}
This is a simple level of detail (LOD) strategy: characters far from the camera get far fewer solver iterations (the cloth looks slightly stretchier, but nobody is close enough to notice), and characters far enough away stop simulating cloth at all, freezing it in its last pose. Section 13's third exercise works through the actual numbers this trade-off saves.
Everything in sections 6 to 10 can be hand-rolled, exactly as shown, or you can reach for Unity's own built-in tools. Both are legitimate choices, and knowing when to pick which one matters more than knowing every option's full feature list.
Cloth component — attaches to a SkinnedMeshRenderer and simulates cloth on top of an existing skinned character mesh. It has built-in wind, optional self-collision, and works with capsule colliders you place around the body. It is the fastest way to get a reasonable-looking cape or skirt with almost no code, and Unity's engineers have already tuned its solver — but you get less control over exactly how it behaves, and pushing it toward a very stylized, bouncy, exaggerated cloth motion (common in anime-style games) can be harder than just writing the motion yourself.HingeJoint, SpringJoint, ConfigurableJoint) — excellent for a small number of connected rigid bodies: a chain necklace of a dozen links, a swinging lantern, a ragdoll's dozen bones. Each joint links two full Rigidbodies, and PhysX has to solve all of them together every physics step. That is fine at ragdoll scale; it stops being fine at cloth scale, where a single garment might need hundreds of particles — hundreds of Rigidbodies and joints is far more expensive than the same count of plain Verlet points with no rotation to solve for.Cloth component's polish (like automatic self-collision) has to be built by hand if you want it at all.A practical rule of thumb: reach for joints when you have a small number of genuinely rigid, connected pieces (ragdolls, chain links, swinging signs). Reach for Unity's built-in Cloth component for a single hero character's garment when the default look and feel is good enough and you want it working quickly. Write a custom Verlet solver when you need many cloth objects at once (a crowd), a distinctive stylized motion the built-in component cannot easily produce, or full control over performance trade-offs like the LOD from section 10.
Cloth component for the player character's one hero cape, and a lightweight custom Verlet solver for a crowd of background NPCs wearing simpler outfits — pick the right tool per situation, not one tool for the whole game.1.0 between each pair. Particle A is pinned at (0, 0). Particles B and C start at rest at (1, 0) and (2, 0) (so their previous position equals their current position — implied velocity zero). Apply one Verlet integration step with acceleration a = (0, -1) and dt = 1 (chosen for round numbers) to B and C. Then run one pass of constraint satisfaction, first on the A-B pair, then on the B-C pair, using the halving rule from section 7 (a pinned particle does not move; between two free particles, each moves half the correction). Give the resulting positions of B and C, and the resulting distance between A and B after this single pass. What does that final A-B distance tell you about why section 7 runs five relaxation passes instead of one?Integration step. Since prevPos = pos for both B and C, the Verlet formula x_next = 2x - x_prev + a*dt*dt simplifies to x_next = x + a (because 2x - x = x and dt*dt = 1). So B moves from (1, 0) to (1, -1), and C moves from (2, 0) to (2, -1). A stays pinned at (0, 0).
A-B constraint. dx = 1, dy = -1, so dist = sqrt(2) ~ 1.4142. diff = (1.4142 - 1) / 1.4142 ~ 0.2929. A is pinned, so all the correction is applied to B: B = (1 - 1*0.2929, -1 - (-1*0.2929)) = (0.7071, -0.7071). Check: distance from A to this new B is exactly 1.0000, as expected.
B-C constraint. Using the just-updated B = (0.7071, -0.7071) and C = (2, -1): dx = 1.2929, dy = -0.2929, dist ~ 1.3257, diff ~ 0.2457. Both are free, so each moves half: B = (0.8659, -0.7431), C = (1.8412, -0.9640). Check: distance from this new B to C is exactly 1.0000.
A-B distance after this pass: distance from A (0,0) to the final B (0.8659, -0.7431) is about 1.1410 — noticeably more than the rest length of 1.0 again, even though the A-B pair was made exactly correct just one step earlier. Fixing B-C moved B, which re-stretched A-B. This is exactly why section 7 loops relaxConstraints five times instead of once: each additional pass shrinks the leftover error further, the same way each extra Riemann-sum rectangle in chapter 2.5 got the approximation a little closer to the true integral, without ever needing to solve everything exactly in one shot.
HingeJoint or a CharacterJoint, and (b) explain, in terms of how the real body part moves, why that is the right choice. Then explain what would visibly go wrong if you swapped the two choices.Neck: CharacterJoint (cone/twist). A real neck can tilt forward, back, and side to side, and also twist (turning the head to look around) — that is swing in two directions plus a separate twist, exactly what swing1Limit, swing2Limit, and the twist limits model. A single-axis hinge cannot represent "tilt sideways and also turn to look left" at the same time, since a hinge only has one axis of rotation.
Knee: HingeJoint. A real knee only bends forward in one plane, roughly like a door hinge — it does not tilt sideways or twist under normal movement. A single min/max angle around one axis captures that completely, and it is cheaper for the physics solver to work with a one-axis constraint than an unnecessary cone.
If swapped: giving the knee a CharacterJoint would let it bend slightly sideways or twist under impact forces, which looks distinctly wrong — real knees do not bow outward. Giving the neck a HingeJoint would lock the head into bending in only one plane, so a ragdoll that fell sideways would show its head snapping straight instead of lolling naturally to the side, and it could never show the head twisted, since a hinge has no twist axis at all.
cols = 10, rows = 14, and solverIterations = 6, running at 60 FPS. (a) How many structural constraints does this grid have in total (count every horizontal neighbor pair plus every vertical neighbor pair)? (b) How many constraint-satisfaction calls happen per second for one character wearing this cape? (c) If 8 characters on screen all wear this cape at full detail, how many constraint-satisfaction calls happen per second in total? (d) Using the LOD idea from section 10, suppose 2 of the 8 characters stay at full detail (6 iterations) and the other 6 are far enough away to drop to 2 iterations. What is the new total calls per second, and roughly what fraction of the original total (c) is that?(a) Horizontal constraints: each of the 14 rows has 10 - 1 = 9 horizontal neighbor pairs, giving 14 * 9 = 126. Vertical constraints: each of the 10 columns has 14 - 1 = 13 vertical neighbor pairs, giving 10 * 13 = 130. Total: 126 + 130 = 256 constraints.
(b) Per frame: 256 constraints * 6 iterations = 1536 constraint-satisfaction calls. Per second at 60 FPS: 1536 * 60 = 92,160 calls per second, for one character.
(c) With all 8 characters at full detail: 92,160 * 8 = 737,280 calls per second.
(d) The 2 full-detail characters still cost 92,160 each: 2 * 92,160 = 184,320. Each of the 6 reduced characters now runs 256 constraints * 2 iterations * 60 = 30,720 calls per second: 6 * 30,720 = 184,320. New total: 184,320 + 184,320 = 368,640 calls per second — almost exactly half of the original 737,280, for a change that only visibly softens cloth on characters the player is not looking closely at.
That is the toolbox for simulating things that are not one solid object: ragdolls chain rigid bodies together with hinge and cone joints and need a careful hand-off between animation and physics on death and recovery; cloth, rope, and hair reuse the Verlet integration from the calculus chapter, held together with distance constraints solved by repeated relaxation instead of literal spring forces; soft bodies extend the same idea into a volume with an extra pull back toward a rest shape. None of it needs to be built from scratch every time — Unity's joints and Cloth component cover most everyday cases — but knowing what a custom Verlet solver is actually doing underneath is what lets you push past the defaults when a game needs cloth that tears, hair that behaves unusually, or a performance budget the built-in tools cannot hit on their own.