Physics & collision (Chaos)
Chaos is the physics engine in UE. Most gameplay needs three things from it: collision (what blocks/overlaps what), queries (traces/sweeps to ask about the world), and occasionally simulation (rigid bodies, ragdolls, constraints). Collision setup mistakes are the most common source of "my overlap/hit never fires" bugs.
When to use this skill
- Setting up what collides with what (channels, presets, per-channel responses).
- Making trigger volumes or detecting overlaps between actors.
- Line/shape tracing the world (aiming, ground checks, interaction detection).
- Simulating physics objects — enabling rigid-body physics, applying forces/impulses.
- Building ragdolls or constraining bodies with
UPhysicsConstraintComponent. - Debugging "overlap never fires", "trace misses", or "physics not simulating" problems.
Collision model — three controls per component
Every UPrimitiveComponent has three collision controls:
Object type (
ECollisionChannel) — what this component is. Built-in:ECC_WorldStatic,ECC_WorldDynamic,ECC_Pawn,ECC_PhysicsBody,ECC_Visibility,ECC_Camera. Custom channels map toECC_GameTraceChannel1–ECC_GameTraceChannel50at runtime (expanded from 18 to 50 in 5.8).Response per channel (
ECollisionResponse) — how it reacts to each channel:ECR_Ignore,ECR_Overlap,ECR_Block.Collision enabled mode (
ECollisionEnabled::Type) — what the shape participates in:NoCollision— no physics, no queries.QueryOnly— overlaps/traces; no rigid-body simulation. Best for trigger volumes.PhysicsOnly— rigid-body sim only; traces don't hit it.QueryAndPhysics— both. Default for most simulated objects.
Block requires both sides to set ECR_Block for the other's object type. For overlap
events, both sides need ECR_Overlap response and bGenerateOverlapEvents = true.
// Set up a trigger sphere: query-only, ignore everything except pawns.
Trigger->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
Trigger->SetCollisionObjectType(ECC_WorldDynamic);
Trigger->SetCollisionResponseToAllChannels(ECR_Ignore);
Trigger->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);
Trigger->SetGenerateOverlapEvents(true);
Collision presets bundle object type + responses into a named profile. Apply with
SetCollisionProfileName(TEXT("Trigger")) to match a project preset or one defined in
Project Settings → Collision. Applying a preset overwrites per-channel overrides, so call
any fine-grained SetCollisionResponseToChannel calls after the preset.
See references/collision-channels-and-profiles.md for the full channel list, custom-channel setup, and preset internals.
Hit & overlap events
Bind in BeginPlay (not the constructor — no world available there):
void AMyActor::BeginPlay()
{
Super::BeginPlay();
// Overlap: trigger volume notifying actor entry
Trigger->OnComponentBeginOverlap.AddDynamic(this, &AMyActor::OnBeginOverlap);
// Hit: physics body reporting impact
Mesh->OnComponentHit.AddDynamic(this, &AMyActor::OnHit);
}
// Exact delegate signatures required — see PrimitiveComponent.h:1457,1468
UFUNCTION()
void AMyActor::OnBeginOverlap(UPrimitiveComponent* Comp, AActor* Other,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex,
bool bFromSweep, const FHitResult& Sweep) { /* ... */ }
UFUNCTION()
void AMyActor::OnHit(UPrimitiveComponent* HitComp, AActor* Other,
UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) { /* ... */ }
Handlers must be UFUNCTION() — dynamic delegates require UObject reflection. For hit events
on simulating bodies, also enable Simulation Generates Hit Events on the body
(FBodyInstance::bNotifyRigidBodyCollision). See ue-actors-and-components for delegate binding
patterns and ue-delegates-and-events for the delegate system.
Traces & sweeps
// Line trace — first blocking hit on ECC_Visibility
FHitResult Hit;
FCollisionQueryParams Params(SCENE_QUERY_STAT(MyTrace), /*bTraceComplex=*/false);
Params.AddIgnoredActor(this); // never hit self
if (GetWorld()->LineTraceSingleByChannel(Hit, GetActorLocation(),
GetActorLocation() + GetActorForwardVector() * 2000.f, ECC_Visibility, Params))
{
// Hit.GetActor(), Hit.ImpactPoint, Hit.ImpactNormal, Hit.PhysMaterial
}
// Sphere sweep — shape-based query
FHitResult SweepHit;
GetWorld()->SweepSingleByChannel(SweepHit, Start, End, FQuat::Identity,
ECC_Pawn, FCollisionShape::MakeSphere(40.f), Params);
// Overlap query — all bodies overlapping a box at a point
TArray<FOverlapResult> Overlaps;
GetWorld()->OverlapMultiByChannel(Overlaps, Center, FQuat::Identity,
ECC_WorldDynamic, FCollisionShape::MakeBox(FVector(50.f)), Params);
FHitResult fields to know: Time (0–1 along trace), Distance, Location (shape center
at contact), ImpactPoint (surface contact), ImpactNormal, GetActor(), GetComponent(),
BoneName, PhysMaterial.
Multi-variants (LineTraceMultiByChannel, SweepMultiByChannel) return all overlaps up to
and including the first block — useful for bullets through foliage.
See references/traces-and-queries.md for ByObjectType, async traces, UV coordinates from hits, and debug-draw helpers.
Simulating rigid bodies
// Enable physics simulation — requires simple collision on the mesh asset.
Mesh->SetSimulatePhysics(true);
Mesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
Mesh->SetCollisionProfileName(TEXT("PhysicsActor"));
// Mass: override per component or let BodyInstance compute from density/volume.
Mesh->SetMassOverrideInKg(NAME_None, 80.f);
// Forces and impulses (world space by default):
Mesh->AddImpulse(FVector(0.f, 0.f, 600000.f)); // instantaneous kg*cm/s
Mesh->AddForce(FVector(0.f, 0.f, 98000.f)); // continuous N per physics step
Mesh->AddImpulseAtLocation(Impulse, HitPoint); // torque from off-center
AddForce accumulates over each physics substep; AddImpulse applies once in the current
step. Damping is on the FBodyInstance (accessible via GetBodyInstance()):
LinearDamping and AngularDamping (both at BodyInstance.h).
Simulating bodies must have simple collision (sphere/box/capsule/convex hull). Complex per-triangle collision cannot drive rigid-body simulation.
Ragdolls and physics assets
A ragdoll runs through a UPhysicsAsset (authored in the Physics Asset Editor), which
defines per-bone bodies and constraints for a USkeletalMeshComponent:
GetMesh()->SetSimulatePhysics(true); // whole-body ragdoll
GetMesh()->SetCollisionProfileName(TEXT("Ragdoll"));
// For blended / partial ragdoll, use UPhysicalAnimationComponent.
Physics constraints
UPhysicsConstraintComponent wraps FConstraintInstance and joins two simulated bodies:
// ConstraintComp is a UPROPERTY(VisibleAnywhere) TObjectPtr<UPhysicsConstraintComponent>
ConstraintComp->SetConstrainedComponents(CompA, NAME_None, CompB, NAME_None);
ConstraintComp->SetLinearXLimit(LCM_Free, 0.f); // allow X-axis translation
ConstraintComp->SetAngularSwing1Limit(ACM_Limited, 45.f); // 45° swing limit
ConstraintComp->ConstraintInstance.OnConstraintBroken.BindUObject(this,
&AMyActor::OnConstraintBroken);
BreakConstraint() on the component tears the joint at runtime. FConstraintInstance also
supports drives (motors): SetLinearPositionDrive, SetAngularDriveMode.
See references/physics-simulation-and-constraints.md
for FBodyInstance details, damping, sub-stepping, and constraint drives.
Physical materials
UPhysicalMaterial (under Runtime/PhysicsCore) stores surface properties referenced by
both UStaticMesh and UPrimitiveComponent. Key fields: Friction, StaticFriction,
Restitution, Density, SurfaceType (EPhysicalSurface). Assign via the mesh asset or
at runtime with GetBodyInstance()->PhysMaterialOverride.
Read SurfaceType from a hit to drive effects (footstep sounds, particle emitters):
Hit.PhysMaterial.Get()->SurfaceType.
Collision complexity
| Mode | Uses | Sim? | Notes |
|---|---|---|---|
| Simple | primitives / convex hull | yes | Required for rigid-body sim; cheap queries |
| Complex | per-triangle | no | Precise static queries (landscape, detailed meshes) |
Set per-mesh in the Static/Skeletal Mesh asset collision settings, and optionally override
on the component. Use FCollisionQueryParams::bTraceComplex = true to query complex.
Gotchas
- Overlap never fires — both components need
ECR_Overlapresponse to each other's object type andbGenerateOverlapEvents = trueon both. One side beingECR_Blockstill generates an overlap if the other isECR_Overlap, but only one fires. - Hit event never fires — enable
Simulation Generates Hit Events(bNotifyRigidBodyCollisiononFBodyInstance); physics sim must also be enabled. - Trace misses everything — check
ECollisionEnabledon targets;NoCollisionorPhysicsOnlymakes them invisible to traces. - Simulating on complex-collision mesh — physics simulation requires simple collision; complex (per-triangle) collision cannot be simulated.
- Forgot
AddIgnoredActor(this)— trace hits own actor's collision shapes. - Handler not
UFUNCTION()—AddDynamicsilently fails; the method must be aUFUNCTION()with the exact delegate signature. - Applying a preset then per-channel overrides —
SetCollisionProfileNameresets all responses; set per-channel responses after calling it. - Force vs. Impulse units —
AddForceis Newtons (applied each substep);AddImpulseis kg·cm/s (applied once). Scale accordingly. SetSimulatePhysics(true)silently does nothing — the mesh has no simple collision, orSetCollisionEnabledisNoCollision/QueryOnly.
Version notes
Chaos replaced PhysX as the default physics engine in UE5. The Chaos solver runs
deterministic substeps controlled by UPhysicsSettings::AsyncFixed (Project Settings →
Physics → Simulation → Use Async Scene). FBodyInstance is stable across UE5; solver
internals differ from PhysX but the UPrimitiveComponent API is unchanged.
References & source material
Engine source (UE 5.8, under Engine/Source/):
Runtime/Engine/Classes/Engine/EngineTypes.h—ECollisionChannel:1098,ECollisionResponse:1346,ECollisionEnabled:1805,FCollisionResponseContainer:1445.Runtime/Engine/Classes/Engine/HitResult.h—FHitResult:20.Runtime/Engine/Classes/Components/PrimitiveComponent.h—OnComponentHit:1457,OnComponentBeginOverlap:1468,SetGenerateOverlapEvents:418,SetSimulatePhysics:1661,AddImpulse:1692,AddForce:1759,SetCollisionEnabled:2026,SetCollisionProfileName:2036,SetCollisionObjectType:2047,SetCollisionResponseToAllChannels:2952,GetBodyInstance:2337,SetMassOverrideInKg:2857.Runtime/Engine/Classes/PhysicsEngine/BodyInstance.h—LinearDamping:629,AngularDamping:633.Runtime/Engine/Classes/PhysicsEngine/ConstraintInstance.h—FConstraintInstance:254,SetLinearLimits:358,InitConstraint:949.Runtime/Engine/Classes/PhysicsEngine/PhysicsConstraintComponent.h—UPhysicsConstraintComponent:24,BreakConstraint:142,SetLinearPositionDrive:151,SetAngularDriveMode:213.Runtime/Engine/Classes/Engine/World.h—LineTraceSingleByChannel:2161,LineTraceMultiByChannel:2210,SweepSingleByChannel:2286,SweepMultiByChannel:2325,OverlapMultiByChannel:2418.Runtime/Engine/Public/CollisionQueryParams.h—FCollisionQueryParams:42,AddIgnoredActor:243,bTraceComplex:51.Runtime/PhysicsCore/Public/PhysicalMaterials/PhysicalMaterial.h—UPhysicalMaterial:103,Friction:115,Restitution:131,Density:147,SurfaceType:181.
Official docs (UE 5.8):
- Collision Overview — https://dev.epicgames.com/documentation/unreal-engine/collision-in-unreal-engine---overview
- Traces Overview — https://dev.epicgames.com/documentation/unreal-engine/traces-in-unreal-engine---overview
- Physics Bodies — https://dev.epicgames.com/documentation/unreal-engine/physics-bodies-in-unreal-engine
- Physics Constraints — https://dev.epicgames.com/documentation/unreal-engine/physics-constraints-in-unreal-engine
- Physical Materials — https://dev.epicgames.com/documentation/unreal-engine/physical-materials-in-unreal-engine
Deep-dive references in this skill:
- references/collision-channels-and-profiles.md
— channel taxonomy, custom channels, preset internals,
FCollisionResponseContainer. - references/traces-and-queries.md — full trace/sweep/ overlap API, ByObjectType vs ByChannel, async traces, debug helpers.
- references/physics-simulation-and-constraints.md
—
FBodyInstanceproperties, sub-stepping, constraint drives, ragdoll setup.
Related skills: ue-actors-and-components (component types, overlap wiring),
ue-meshes-static-and-skeletal (collision geometry on assets).