# Unreal Engine: Miscellaneous

*2025-11-05*

> Miscellaneous notes taken from the final week of Game Programming Foundations


After learning all about [testing and profiling]({{< relref "/posts/2025/unreal-engine-18-testing-and-profiling" >}}), the final week of my [**Game Programming Foundations** course](https://www.cgspectrum.com/courses/game-programming-foundations) was a capstone - exploring various aspects of Unreal Engine development that hadn't been covered in earlier lessons, or needed consolidation: the [Environment Query System (EQS)](https://dev.epicgames.com/documentation/unreal-engine/environment-query-system-in-unreal-engine), [Data Tables](https://dev.epicgames.com/documentation/unreal-engine/data-driven-gameplay-elements-in-unreal-engine) (again), [Networking and Multiplayer](https://dev.epicgames.com/documentation/unreal-engine/networking-and-multiplayer-in-unreal-engine), and [Online Subsystems and Services](https://dev.epicgames.com/documentation/unreal-engine/online-subsystems-and-services-in-unreal-engine).

Notes below – and fair warning, this is the longest and most fragmented of the series.

---

## Setting Up Tantrumn

The course started with a practical project: building from the [**Tantrumn** source](https://github.com/sawnoff-studios/tantrumn-source) (Unreal's third-person reference character).

- Requires building from source code with dynamic and static DLLs
- Link GitHub to Epic, request access, run `Setup.bat` (can take hours)
- Movement/jumping exposed through `RequestMove*` functions
- Input scaling via `InputPitchScale`, `InputYawScale`, `InputRollScale`, plus `BaseLookUpRate` and `BaseLookRightRate`

## The Three Cs

A framework for evaluating game feel:

### Character
- Animation and movement meshed together - launching and looping animations look janky when not timed to locomotion
- **Mario** - movement and animation tightly coupled
- **Rayman** - camera and control integration matters

### Camera
- Avoid unwanted clipping
- Good focus – don't lose the character
- Make use of multiple cameras (switching based on context)
- Resources: Daedalic's [third-person camera](https://github.com/DaedalicEntertainment/third-person-camera), YouTube guides on camera systems

### Control
- Responsive controls with immediate feedback
- **Control tricks:** coyote time and input buffers
- Correct use of available buttons (don't waste action space)

### Coyote Time
- When the input binding wasn't received (you *thought* you jumped but pressed after leaving the edge)
- Allow a small window of frames/milliseconds to press the jump button after falling off a platform – classic example: the indie game *Flynn*, where the player can still jump briefly after leaving terrain

### Input Buffering
- The last few frames before the player hits the floor, they want to jump
- Was the player grounded? No jump. Input wasn't received?
- Buffer the input – wait until on floor, then jump automatically
- Smooths out imprecise timing without feeling permissive

### Transferring Assets
- Based on references tracked by class – migrate to Content folder
- Importing missing animations: animation doesn't have the skeleton → retarget animation to skeleton

### Character Movement
- Crouch/Uncrouch - check `IsMovingOnGround()` before allowing crouching in the air
- `MaxAccelerationSpeed`, `MaxWalkSpeed`, `MaxJumpCount` for double jumping

### Movement Unit Testing
- Jump distances between platforms
- Slope angles for walking up
- Sonic Infinity Plus test level with lots of animation blends
- Enemies and interactables
- Reference: [ProjectBorealis PBCharacterMovement](https://github.com/ProjectBorealis/PBCharacterMovement)

## Kinematics (Round Two)

The course revisited kinematic equations with practical application:

### Setting Up Environment
- Static meshes as cubes at varying heights (100m, 200m, 300m)
- Jumping events: `On Jumped`, `On Landed`
- Note time started, subtract from time landed

### Equations

Notation: `v = velocity`, `d = distance`, `t = time`, `a = acceleration`, `vi = initial velocity`, `vf = final velocity`

1. `v = Δd/t`
2. `a = Δv/t`
3. `d = vi * t + 0.5at²`
4. `vf² = vi² + 2ad`
5. `vf = vi + at`
6. `d = ((vi + vf) / 2) * t`

All values are constant. Use Desmos for verification - same time to reach apex equals same time to fall. Default gravity set in `Project Settings → Default Gravity Z`. Air control configures mid-air movement. Pythagoras' theorem for distance calculations.

### Adding Gameplay
- `PlayerController->PlayDynamicForceFeedback()`
- Fall impact speed: `GetVelocity().Z`

## Throw Feature (Practical Implementation)

A complete throw mechanic example:

- **Throwable Actor Blueprint**: Get Component, Activate, Set Homing Projectile as player
- `On Actor Hit` → Deactivate, `Attach Actor To Actor`
- Override `NotifyHit` to set owner, deactivate and attach
- **Launch**: detach from actor, activate Projectile Movement Component, set initial velocity

### Animation Support
- Event graph sets variables, calls `IsPullingObject()`
- Locomotion pose cached and blended with actions pose

### Throw States
- Interact montage with anim notify
- Throw curve to speed up just before release
- Montage as member variable, call `PlayAnimMontage()`
- During Tick: if throwing, check `GetCurrentActiveMontage()`, get throw curve value, `Montage_SetPlayRate()`
- States enum determines when object is idle

### Player Feedback
- Material to highlight throwable object
- Line render width, highlight colour, screen-position-based scale
- Raycast and sphere trace to prevent picking objects behind
- Dot product to check whether object is behind the player

## Game Loop

### Game Loop Structure
- Start / Wait / Countdown
- Engage with Player/AI challengers
- Reach end / Restart

### Network Compendium
Reference: [Cédric Neukirchen's Network Compendium](https://cedric-neukirchen.net/docs/category/multiplayer-network-compendium/)

### Game Mode
- Custom Game States
- Send and receive game progress updates

### Player Controller
- Check for whether player is playing
- `GameMode->GetCurrentGameState()`
- Check game state in Animation Blueprint

### Game Widget
- `StartCountdown()` and `LevelComplete()` methods
- Create UI using visual editor
- Button handlers: `On ButtonRetry` → change level, `On ButtonQuit` → quit level
- Set widget elements to **Not Hit Testable** - `PlayerController->SetInputMode()`, `PlayerController->SetShowMouseCursor(true)`

## AI Recap

### Controllers and Pawns
- **Pawn** - object that can be interacted with by the player
- **Character** - pawn extended with strict rules for running/jumping/flying

### Blackboard and Behaviour Trees
- **Selector** – executes tasks until one returns true
- **Sequence** - runs tasks one after the other
- Set up behaviour tree and nothing happens? Add Blackboard with Position vector, event `ReceiveExecuteAI` with `Finish Execute` node, `GetRandomLocationInNavigableRadius()`, task to find random location and set blackboard value

### Nav Meshes, Nav Links and Modifiers
- **Navigation Meshes** – retrieves location and doesn't move; if you're getting random location but no path, add missing NavMesh
- **NavLinkProxy** – travel from one NavMesh to another
- **Smart Link**: Simple Links (point array, bidirectional, cylinders must touch NavMesh for valid link), `Event ReceiveSmartLinkReached`, cast to character and get location, `SuggestProjectileVelocity Custom Arc` node linked to `LaunchCharacter`
- **Fall/Jump Link** – smart link for jumping, simple link for falling

### Nav Modifiers
- `NavArea` with configurable default cost and fixed area entering cost
- Manipulation of values in NavMesh

### AI Perception and Stimuli

- **Perception vs Stimuli**: perception is the act of perceiving surroundings; stimuli is an act/event/chemical that can be perceived
- **Listening**: AI Perception component on Controller (damage sense, hearing, prediction, sight, team sense, touch)
- **AI Sight**: sight radius, lose sight radius, peripheral vision half-angle degrees (chameleon), max age (how long sense traces last), dominant sense
- **AI Perception Stimuli Source component** on character: add component, set auto-register as source, add multiple perceptions

### Making AI Respond to Stimuli
- `Set AI Perception → Senses Config → Sense → Detection by Affiliation → All to true`
- Add event to AIPerception component: `OnTargetPerceptionUpdated`
- Update Blackboard variables (`CanSeeTarget` boolean key, Target object key)
- Update Behaviour Tree: select nodes, set Observer aborts to Self, set `Is Not Set` for CanSeeTarget Blackboard key

## Environment Query System (EQS)

### What is EQS?
- Add Environment Query asset – generates points in environment based on criteria
- Returns best match or best three matches

### Building EQS
- Generate items on circle around querier
- Add test: what to do with these points? Distance to querier, dot product to check behind, trace to querier – each test filters and scores results

### Where and When to Use EQS
- Run query from within Behaviour Tree
- Set Blackboard value from result of EQS query

### Additional Uses
- Run modes: Single Best Item, Single Random Item, etc.

## Debugging AI

- Enable built-in AI debugging overlays (apostrophe key)
- Debug system overview – numpad keys toggle categories
- Show call stack of Behaviour Tree
- EQS search data visualised in level
- Stimuli and perception visualised
- Toggle breakpoint on nodes and step through
- Navigation visualiser shows paths

## Interfaces and Data Tables (Round Two)

### Blueprint Interfaces
- Use return node with return boolean variable

### C++ Interfaces
- `const bool TypedInteract()`
- `void NonTypedInteract()` - return node parameter called 'Return Value'
- `void SignatureInteract(bool &Return)` - return node parameter called 'Return'

### Implementation
- `_Implementation` method: `ApplyEffect_Implementation()`
- `Execute_*` method: `Execute_ApplyEffect()`

### Data Tables
- Stat systems, progression systems, effect systems, multi-language string support
- Array or nested array? → DataTable
- Include `Engine/DataTable.h`, add `UStruct` inheriting `FTableRowBase`, add `UDataTable` property settable in editor
- Create table array, pick row structure, create rows with values, import from spreadsheets, export to CSV/JSON
- Retrieve row: `Table->FindRow<FType>(Name("Key"))`, `GetDataTableRow()`
- Actor/object can differ and display info on widget systems

## Online Multiplayer

### Online Game Loop
- `OnOverlapBegin` method
- `HasAuthority()` checks whether on authoritative machine
- `ClientReachedEnd_Implementation()` calls `CharacterBase->ServerPlayCelebrateMontage()`

### Replicated Classes
- Actors replicated with `UPROPERTY(ReplicatedUsing)`
- One GamesInstance and one widget (`AddToPlayerScreen()`)
- `AGameState` extends `AGameStateBase` extends `AInfo` extends `AActor` - `UPROPERTY` on replicated value, `ReplicatedUsing = OnRep_GameState` specifies replication method
- `OnOverlapBegin` → `GameState` → `OnPlayerReachedEnd`
- `GetLifetimeReplicatedProps()` returns list of properties to replicate
- **PlayerState** – contains replicated information about player using controller, enum with None/Waiting/Playing/Finished
- **GameInstance** – no replication

### Online AI Implementation
- AI Controller: Auto Possess AI and AI Controller class set in actor instance
- Wants Player State set to true
- Navigation Testing Actor can be used
- Spawning: `GetActorTransform()` and `SpawnActor()`
- Level event graph calls spawn on AI Spawner instance
- Behaviour Tree Tasks: `EQS_TestingPawn`, `Can Ever Affect Navigation` within collision, `BTTTask_BlackBoardBase`, implement `ExecuteTask()`
- Environment Query: add test, filter, score

## Putting It All Together

### Aiming
- `RequestAim()` calls `ServerRequestToggleAim()`
- Change variable server-side, clients get variable

### Stun
- Montage or Animation Blueprint? Animation Blueprint – stunned is a state

### Visual Logger
- Windows → Developer Tools → Visual Logger
- Filter out unwanted elements
- `UE_VLOG_ARROW`

### AI Controller Architecture
- Run Behaviour Tree switches between destinations
- Split into different AI controllers
- Split into different Character classes

---

## Notes on things that stood out

The final week felt like a **series finale episode** – everything that had appeared before, now stitched together: the Three Cs for game feel, kinematics (yes, we're doing math *again*), throw mechanics as a practical synthesis of animation + physics + gameplay, networking that reuses the replicated systems from earlier courses, AI that pulls together state machines, behaviour trees, EQS, and perception.

Two things to note about the capstone nature: some topics recur here (data tables, interfaces, AI perception) that appeared in earlier weeks – that's intentional consolidation, not course repetition. And the online multiplayer section is the only place in the whole series where authority checks, RPC patterns, and replication appear together; that's the moment when everything becomes network-aware rather than single-player.

The practical habit I'm taking forward: `stat unit` for frame-time spikes, `UE_VLOG` for debugging sequences, and the Three Cs as a checklist whenever movement feels wrong. Those three tools cover more of my daily work than I expected.
