# Unreal Engine: Collision Detection

*2025-07-23*

> Notes taken from the seventh week of Game Programming Foundations


Last week was all about [how objects communicate]({{< relref "/posts/2025/unreal-engine-06-communication" >}}); 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](https://github.com/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:

| Preset                | Meaning                                                            |
|-----------------------|--------------------------------------------------------------------|
| **Query Only**        | Spatial queries (traces, overlaps) work, but no physics simulation |
| **Physics Only**      | Objects physically collide, but no spatial queries fire            |
| **Query and Physics** | Both                                                               |

**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:

```cpp
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 Channel                 | By Object Type                | By Profile                 |
|-------------------|----------------------------|-------------------------------|----------------------------|
| **Line, Single**  | `LineTraceSingleByChannel` | `LineTraceSingleByObjectType` | `LineTraceSingleByProfile` |
| **Sweep, Single** | `SweepSingleByChannel`     | `SweepSingleByObjectType`     | `SweepSingleByProfile`     |
| **Line, Multi**   | `LineTraceMultiByChannel`  | `LineTraceMultiByObjectType`  | `LineTraceMultiByProfile`  |
| **Sweep, Multi**  | `SweepMultiByChannel`      | `SweepMultiByObjectType`      | `SweepMultiByProfile`      |
| **Line, Test**    | `LineTraceTestByChannel`   | `LineTraceTestByObjectType`   | `LineTraceTestByProfile`   |
| **Sweep, Test**   | `SweepTestByChannel`       | `SweepTestByObjectType`       | `SweepTestByProfile`       |

(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.

