UE Physics & Collision
Target engine: UE 5.8. APIs below are verified against the 5.8 headers; older forms are listed under "Deprecated — do not use".
Collision and physics live in the Engine module (UPrimitiveComponent, UWorld queries, FHitResult, UCollisionProfile) and the PhysicsCore module (FCollisionShape, UPhysicalMaterial, FBodyInstanceCore, ECollisionTraceFlag, EPhysicalSurface). The simulator itself is Chaos (Chaos / ChaosSolverEngine modules); destruction adds GeometryCollectionEngine and FieldSystemEngine. Most gameplay code only needs "Engine" and "PhysicsCore" in Build.cs.
Context
Read .agents/ue-project-context.md if it exists (module names, conventions, enabled plugins, GAS/networking setup). Do not stop if it is missing.
Identify the area from the request and the codebase. Ask only when two plausible readings would produce different code.
Collision Channels and Profiles
ECollisionChannel (Engine/EngineTypes.h:1098) has 8 engine channels, 6 hidden engine slots and 50 game slots (64 total; ECC_GameTraceChannel50 at :1168):
- Object channel — every component has exactly one, set with
SetCollisionObjectType. Matched by*ByObjectTypequeries. - Trace channel — never an object type; a query passes it to
*ByChanneland each component's response to that channel decides block/overlap/ignore. ECollisionResponse(Engine/EngineTypes.h:1346):ECR_Ignore,ECR_Overlap,ECR_Block.ECollisionEnabled::Type(Engine/EngineTypes.h:1805):NoCollision,QueryOnly,PhysicsOnly,QueryAndPhysics,ProbeOnly,QueryAndProbe.
SetCollisionProfileName overwrites every manual response, so apply the profile first and the per-channel overrides after.
Engine profiles shipped in Config/BaseEngine.ini under [/Script/Engine.CollisionProfile]: NoCollision, BlockAll, OverlapAll, BlockAllDynamic, OverlapAllDynamic, IgnoreOnlyPawn, OverlapOnlyPawn, Pawn, Spectator, CharacterMesh, PhysicsActor, Destructible, InvisibleWall, InvisibleWallDynamic, Trigger, Ragdoll, Vehicle, UI, WaterBodyCollision.
Custom channels and profiles are config-only — there is no runtime API to create one:
bTraceType=True declares a trace channel, False an object channel. +Profiles= adds or replaces a whole profile; +EditProfiles= only patches responses on an existing one (Engine/CollisionProfile.h:160-190). UCollisionProfile::Get() reads the table and UCollisionProfile::LoadProfileConfig(bool bForceInit) (Engine/CollisionProfile.h:237) re-reads it after a config change.
See collision-channel-setup.md [blocked] for full profile sets, the ini reference and a debugging checklist.
Trace Sweep and Overlap Queries
All world queries are const members of UWorld (Engine/World.h:2128-2441). Three families, each in Test / Single / Multi form:
TraceTag is the first constructor argument; it also drives the TraceTagAll / named-tag debug drawing in the console.
Sweeps take a rotation and an FCollisionShape (PhysicsCore/Public/CollisionShape.h:284-316):
GetCapsuleHalfHeight() includes the end radius; GetCapsuleAxisHalfLength() is the shaft only.
Overlaps are stationary shape tests returning FOverlapResult (Engine/OverlapResult.h:12):
OverlapAnyTestByChannel stops at the first block or touch; OverlapBlockingTestByChannel ignores touches. When the query is "what is my own component already touching", use UPrimitiveComponent::GetOverlappingActors or ComponentOverlapComponent instead of a world query.
Async traces queue this frame and are readable next frame (Engine/World.h:2522, WorldCollision.h:148):
Passing a FTraceDelegate* (DECLARE_DELEGATE_TwoParams(FTraceDelegate, const FTraceHandle&, FTraceDatum&)) instead calls you back when the batch completes.
See trace-patterns.md [blocked] for hitscan, melee sweep, interaction, ground check, AoE, line-of-sight and async sensor patterns, plus the Blueprint-layer UKismetSystemLibrary wrappers and performance guidance.
FHitResult
Engine/HitResult.h. Actor is no longer a member — the actor is reached through an accessor.
For a Multi query only the last element can be a blocking hit; every earlier element is a touch.
Collision Events
Delegates are sparse dynamic multicast, so handlers must be UFUNCTION()-declared in the header with exactly the delegate's parameter list, or AddDynamic fails to bind at runtime. Signatures from Components/PrimitiveComponent.h:274-282 and GameFramework/Actor.h:194-196:
Requirements: overlaps need ECR_Overlap on at least one side, a non-ECR_Ignore pair, and SetGenerateOverlapEvents(true) on both components (bGenerateOverlapEvents is private — Components/PrimitiveComponent.h:429). Simulation hits need ECR_Block on both, QueryAndPhysics or PhysicsOnly, and SetNotifyRigidBodyCollision(true) on the simulating component; a swept move (SetActorLocation(..., true), movement components) fires OnComponentHit on any blocking hit without that flag (PrimitiveComponent.cpp:3540-3550). OnComponentWake / OnComponentSleep need bGenerateWakeEvents on the body (PhysicsCore/Public/BodyInstanceCore.h:59).
Physics Bodies and Forces
bVelChange=true / bAccelChange=true ignore mass. ERadialImpulseFalloff is RIF_Constant or RIF_Linear (PhysicsCore/Public/Chaos/ChaosEngineInterface.h:90).
MyMesh->GetBodyInstance() reaches the body. FBodyInstanceCore flags (PhysicsCore/Public/BodyInstanceCore.h): bSimulatePhysics (:30), bOverrideMass (:35), bEnableGravity (:39), bUpdateKinematicFromSimulation (:43), bAutoWeld (:51), bStartAwake (:55), bGenerateWakeEvents (:59). FBodyInstance adds bUseCCD (:418), bNotifyRigidBodyCollision (:440), LinearDamping (:629), MassScale (:645), InertiaTensorScale (:653), SleepFamily (:410) and CustomSleepThresholdMultiplier (:696). ESleepFamily (Chaos/ChaosEngineInterface.h:101) is Normal, Sensitive or Custom; only Custom reads the multiplier.
Collision complexity comes from ECollisionTraceFlag (PhysicsCore/Public/BodySetupEnums.h:13-20): CTF_UseDefault, CTF_UseSimpleAndComplex, CTF_UseSimpleAsComplex, CTF_UseComplexAsSimple. Complex-as-simple bodies cannot simulate.
Constraints Radial Force and Ragdolls
UPhysicsConstraintComponent (PhysicsEngine/PhysicsConstraintComponent.h:24) wraps an FConstraintInstance (:73) — the same struct a Physics Asset stores per joint.
Motion enums are ELinearConstraintMotion (LCM_Free, LCM_Limited, LCM_Locked) and EAngularConstraintMotion (ACM_Free, ACM_Limited, ACM_Locked). Editor presets are only combinations of these: Fixed locks all six, Hinge frees one angular axis, Prismatic frees one linear axis, Ball-and-Socket frees all angular. URadialForceComponent (PhysicsEngine/RadialForceComponent.h:16) is the drop-in explosion/vacuum component: Radius, Falloff, ImpulseStrength, bImpulseVelChange, bIgnoreOwningActor, ForceStrength, then FireImpulse() (:50) for a one-shot and AddObjectTypeToAffect(EObjectTypeQuery) (:54) to filter targets.
Ragdolls run through the skeletal mesh's Physics Asset (UPhysicsAsset::SkeletalBodySetups, ConstraintSetup — PhysicsEngine/PhysicsAsset.h:213-220):
Physical Materials
PhysicsCore/Public/PhysicalMaterials/PhysicalMaterial.h:103.
EPhysicalSurface (PhysicsCore/Public/Chaos/ChaosEngineInterface.h:20) is SurfaceType_Default plus SurfaceType1..SurfaceType62, named in Project Settings > Physics.
Chaos Solver and Async Physics
Chaos is the only physics backend in 5.8. FChaosScene (PhysicsCore/Public/Chaos/ChaosScene.h:84) owns the solver and is driven by SetUpForFrame (:141), StartFrame (:140), EndFrame (:142); WaitPhysScenes (:122) blocks for results.
Project settings live on UPhysicsSettings / UPhysicsSettingsCore under [/Script/Engine.PhysicsSettings]:
FChaosSolverConfiguration (Chaos/Public/ChaosSolverConfiguration.h:51) exposes PositionIterations, VelocityIterations, ProjectionIterations, CollisionMarginFraction, CollisionCullDistance, CollisionMaxPushOutVelocity.
Diagnostic CVars that exist in 5.8:
With bTickPhysicsAsync on, gameplay code that must run in lockstep with the solver uses the async tick instead of Tick: set bAsyncPhysicsTickEnabled in an actor constructor (protected, GameFramework/Actor.h:699) or call SetAsyncPhysicsTickEnabled(true) on a component (ActorComponent.h:1435; the component field at Components/ActorComponent.h:407 is private) and override AsyncPhysicsTickActor(float DeltaTime, float SimTime) (Actor.h:2930) or AsyncPhysicsTickComponent(float DeltaTime, float SimTime) (ActorComponent.h:985). Feed inputs across the boundary with UAsyncPhysicsInputComponent (Engine/Public/Physics/AsyncPhysicsInputComponent.h:10).
Below FBodyInstance, bodies are addressed as Chaos::FPhysicsObject. UPrimitiveComponent implements IPhysicsComponent and exposes GetPhysicsObjectById, GetPhysicsObjectByName and GetAllPhysicsObjects (Components/PrimitiveComponent.h:3248-3250); FHitResult::PhysicsObject and PhysicsObjectOwner (Engine/HitResult.h:134-137) identify what a query hit when no actor owns it.
Network Physics
Physics simulates on the server. Hit and overlap events fire wherever the simulation runs, so clients see nothing unless the actor also simulates locally or you replicate the result.
AActor::SetPhysicsReplicationMode(EPhysicsReplicationMode)/GetPhysicsReplicationMode()(GameFramework/Actor.h:924,928) selectDefault,PredictiveInterpolation,ResimulationorNone(Engine/EngineTypes.h:3614).Resimulationrequires Project Settings > Physics > Physics Prediction (UPhysicsSettings::PhysicsPrediction);PredictiveInterpolationruns without it but works best with it enabled (Engine/EngineTypes.h:3619-3629).UNetworkPhysicsComponent(Engine/Public/Physics/NetworkPhysicsComponent.h:2290) records input and state history on the physics thread so the client can resimulate from a corrected past state.- Transform sync for non-predicted actors still rides on
bReplicateMovement/FRepMovement.
Replication rules, conditions and RPC design belong to ue-networking-replication; this skill only covers which physics mode to pick.
Module Dependencies
Deprecated — do not use
Common Mistakes
UFUNCTION() on an out-of-line definition: UHT only reads headers, so a UFUNCTION() written above void AMyPickup::OnHit in the .cpp generates no reflection data and AddDynamic silently binds nothing. Declare the handler inside the class body with UFUNCTION(); define it plainly in the .cpp.
Handler signature drift: AddDynamic matches the delegate exactly. A missing int32 OtherBodyIndex or a FHitResult taken by value will not compile, and a stale copy of an old signature will not bind.
Overlap events set on one side only: both components need a non-ignore response and SetGenerateOverlapEvents(true). Setting it only on the trigger is the most common "my overlap never fires".
Hit events without SetNotifyRigidBodyCollision(true): for simulated bodies ECR_Block alone is not enough; OnComponentHit stays silent (swept moves dispatch regardless).
Profile applied after manual responses: SetCollisionProfileName resets the whole response container. Order is profile first, overrides second.
Mixing channel families: a component whose object type is ECC_Pawn is invisible to LineTraceSingleByObjectType querying ECC_GameTraceChannel3, and a trace channel can never be an object type. bTraceType in the ini decides which one a slot is.
bTraceComplex = true by default: per-triangle queries are several times the cost of the simple hull and skip simple-only bodies. Enable it only where triangle accuracy matters.
SetPhysicsLinearVelocity as a movement API: it overwrites the solver's velocity every call and fights contacts. Use AddForce / AddImpulse unless you are deliberately teleporting velocity.
Fast bodies tunnelling: enable SetUseCCD(true) on the body, or substepping project-wide, rather than shrinking the timestep globally. For traces every tick on many actors, use AsyncLineTraceByChannel or throttle to 5–10 Hz with a timer.
Related Skills
ue-actor-component-architecture— component creation, attachment, registration and lifecycle for shape and mesh componentsue-character-movement—UCharacterMovementComponentfloor checks, capsule sweeps and step-up logicue-networking-replication—DOREPLIFETIME, replication conditions and RPCs for anything you send about a physics resultue-ai-navigation— perception traces, navmesh queries andUNavigationSystemV1ue-procedural-generation— collision setup on runtime-generated meshes- Also relevant:
ue-testing-debugging,ue-gameplay-framework,ue-mover


