Unreal Engine: Collision Detection

·4 min read·Graham Mace
Unreal Engine: Collision Detection

Last week was all about how objects communicate; this week, quite possibly the most important topic in game development: collision. Types, custom channels, visualising, debugging, and detection.

As ever, my changes were committed to the repository as I followed along, with my notes below.

sawnoff-studios/first-project

Collision Types

Every component’s Collision Preset (Details panel, right side) determines how it interacts with everything else. Conceptually it’s like a Venn diagram of three responses:

  • Ignore – the two objects pass through each other, no events fired
  • Overlap – they pass through, but overlap events fire
  • Block - physical collision

Each object also has an Object Type, which defines how it participates in these interactions with other objects.

Some canonical examples:

  • A pawn’s CapsuleComponent uses the Pawn preset - other objects set to block pawns
  • A projectile is usually set to Overlap so you can check interactions without bouncing off things
  • Line Trace By Channel traces against a Collision Channel – the channel’s trace responses decide what it hits
  • The Spring Arm has a Do Collision Test boolean for camera collision – pull the camera in when geometry would block it

Collision responses split into two families: Trace Responses (what happens for line/sweep queries) and Object Responses (what happens with other objects).

Overlap vs Block in practice: checkpoint timing in racing games - the checkpoint should fire when you drive through, but the wall next to it shouldn’t move.

Custom Collisions

New channels are created in Project Settings → Engine → Collision, as either Object Channels (for types of things) or Trace Channels (for queries like “things a weapon can shoot through”).

Each component’s Collision Enabled mode chooses which subsystems its collision feeds:

PresetMeaning
Query OnlySpatial queries (traces, overlaps) work, but no physics simulation
Physics OnlyObjects physically collide, but no spatial queries fire
Query and PhysicsBoth

Simulate Physics and Gravity Enabled decide whether objects actually move under physics at all.

Visualising Collisions

  • Without custom colliders, the engine approximates a shape from the mesh
  • The viewport menu has a Show Collision option that reveals collision geometry during play
  • Under that view, purple objects are ones that block the character – an instant answer to “why can’t I walk there?”

Debugging Collisions

  • Collision can be removed from within the Static Mesh editor itself, not just per-component
  • Collision Complexity (right side of the mesh editor) controls which geometry is used:
    • Default - uses both simple and complex shapes as appropriate
    • Can be forced to use the complex (render) geometry for queries

Collision Detection

Blueprint hit/overlap events are added on the right-hand side of the component:

  • On Component Hit
  • On Component Begin Overlap
  • On Component End Overlap

Use Get Display Name on the other actor to debug what’s actually colliding with what.

C++ event binding follows the dynamic-delegate pattern from last week:

MeshComp->OnComponentBeginOverlap.AddDynamic(this, &AFPClass::OverlapBegin);

The awkward part is the handler signature: you have to get the parameters exactly right or the bind fails cryptically. The reliable workflow is to find the declaration of OnComponentBeginOverlap in the engine source, and copy all of its arguments into your OverlapBegin method signature (there are five, ending in the FHitResult sweep result). The lesson worth keeping: the source code is the source of truth for parameters – not the documentation.

The tracing function matrix - Unreal names every combination of {Line/Sweep} × {Single/Multi/Test} × {Channel/ObjectType/Profile}:

By ChannelBy Object TypeBy Profile
Line, SingleLineTraceSingleByChannelLineTraceSingleByObjectTypeLineTraceSingleByProfile
Sweep, SingleSweepSingleByChannelSweepSingleByObjectTypeSweepSingleByProfile
Line, MultiLineTraceMultiByChannelLineTraceMultiByObjectTypeLineTraceMultiByProfile
Sweep, MultiSweepMultiByChannelSweepMultiByObjectTypeSweepMultiByProfile
Line, TestLineTraceTestByChannelLineTraceTestByObjectTypeLineTraceTestByProfile
Sweep, TestSweepTestByChannelSweepTestByObjectTypeSweepTestByProfile

(Line = infinitely thin ray; Sweep = a shape swept along the ray. Single = first hit; Multi = all hits; Test = boolean does-it-hit-anything.)


Notes on things that stood out

Collision is where “it works until it mysteriously doesn’t” lives. The two habits I’m taking forward: turn on Show Collision before theorising about why something blocks, and when binding overlap events in C++, go straight to the engine declaration rather than trusting docs or autocomplete.