Dev Log
11 August 2025
- Make tests use
FString::Format - Reorganise test string handling to reduce allocations
- Add
TestDisplayTraits<T>to automatically handle formatting withFString::Format
- Add
- Make separate tick loop for HUD updates
- The HUD should tick in real time and be unaffected by the simulation speed
10 August 2025
- Pull HUD manager tick out of the simulation loop
- Add
TestEqualityTraits<T>to centralise testing equality logic
9 August 2025
- Create function to generate widget blueprints with the C++ widgets already bound
- Move the HUD manager from the player controller into the orchestrator
- General improvements to testing system
- Fix bug with capital ship kills being broadcast every tick leading to scores increasing constantly
- Add optional health to capital ship proxy so they can be individually set
- Minor bug fixes
- Allow proxy actors to have a name in testing contexts
- Add widget for kills by each team
8 August 2025
- Remove lives widget
- Remove gold rings widget
- Use polling for HUD updates instead of delegates
7 August 2025
- Add player ship destruction
- Make lasers inherit shooter velocity
- Add
FPeriodicCountdownTimers, float based countdown timers with an array of periods - Add a UMG widget to display entity counts
- Create mission status UMG widget
- Add
TPeriodicTickCountdown, an integer based counter that contains a period to reset to when each timer is reset - Move HUD code out of the player controller and into a new
FHUDManager
6 August 2025
- Change some internal functions to templates
- Add hysteresis to fighter positioning instead of always being at 50% of the laserâs max distance
- Make attack reposition checks periodic
- Make
FTickCountdowna template so you can use different int counter types - Add test for fighter LOS position adjustment
- Make fighters reposition when they donât have LOS and theyâre not moving to a new location
- Add int/float biases to each fighter to add some deterministic ârandomnessâ to their choices
- Make the mission manager use fixed ticks
- Make the simulation orchestrator handle destroying proxy actors
- Decouple the mission manager from the player
- Fix player ship aim offset
5 August 2025
Trying to get tests working. Looking into new data visualisation strategies.
- Add tests for fighters intercepting a capital ship
- Fixed bug with fighter indexing when capitals were queuing orders
- Added test result exporting to data assets/tables/float curves
- Add
FTickCountdown, a tick-based timer - Add
SimulationClockInterface, a limited way of getting simulation time info from the simulation orchestrator - Add data assets to bundle data like actor configs
- Add tests for the simulation orchestrator
- Support simulation pausing
- Make fighter enemy scanning periodic
- Moved some code into the
SandboxCoreplugin and changed the tests from automation tests to low-level Catch2 tests - Clamp fighter move distances to prevent overshoot
- Add some variadic helpers for
nullptrand size checks in my loop kernel functions
4 August 2025
- Use sockets for fighter firing offsets instead of actor components
- Make fighters and capital ships much larger
- The fighters are much more readable in battle now
- Reorganised a bunch of internal assets
- Implemented fixed tick rate in main orchestrator
- Allow variable simulation speeds (Tests now run at 20x speed)
- Visual updates are decoupled from the simulation
- Use
NativePreConstructforUValueWidgetpreviews - Allow fighters to intercept nearby enemies when moving to their objectives
- Add
TimeSeriesDataclass for sampling{time, value}pairs from tests for easy post processing - Add
FTestTimeline, a container of{time, fn}for queueing test simulation events
3 August 2025
Add team-based colours to laser hits for combat readability. General internal improvements to logging and internal data structures.
2 August 2025
Tore the barrel roll code out. RIP Starfox clone.
Made a UMG widget to display 2D vectors. This will be needed for future ideas where we could control ship systems with a sample and hold system using the analog stick.
Sample and hold is in. I now have a weird control scheme. XY direction is chosen by holding R1 and then selecting a direction on the analog stick. This is locked when when you release R1.
Then the left analog stick is used for rolling and for Z motion. The right stick is always for pitch and yaw.
Itâs an odd scheme. You need to continually adjust your motion. It doesnât feel bad.
Iâm a bit tired with games feeling a bit samey. Iâd like to experiment with something that maybe isnât good or is sub-optimal but we see if anything interesting comes from the constraints.
1 August 2025
Make a new TimeSeriesData class.
This makes it easy to sample data in CQ tests.
I then made a single cast delegate for the tick end in the orchestrator for testing.
We set up the test, run it for N seconds, and then weâve a ton of data that we can post process in one go. Pretty much how weâd do analog IC simulations.
Added some Catch2 based benchmarks with a CLI arg to tune the size.
Moving away from a Starfox 64 style control scheme to a more traditional twin stick shooter.
Fighters now lead their shots and are much more deadly. The Starfox style movement couldnât cut it. Weâve now got movement in the YZ axes for dodging.
Screenshots
28 July 2025
Implemented fighters stopping at an attack radius around the target.
26 July 2025
Storing entity radii in the registry for simple volume querying. Fighters now do a LOS check before firing. It doesnât solve all cases of friendly fire but itâs better than nothing.
Hours of pain due to my tests. I tried to be simple and not introduce a direct damage system for the tests. When I changed how my ships flew, they began to overlap during the tests. When my test driver did some scripted kills, it did damage to a location which ended up killing the wrong entities. It was hard to debug.
Iâve added a second direct damage path in parallel with the collision-based damage path.
25 July 2025
Created a SandboxNative module for game code that doesnât require the engine or editor.
This allows me to make SandboxNativeTests which uses Catch2 based low-level tests.
Set individualised spawn timers for capital ships.
Capital ship proxies can override the actor configâs initial spawn delay and spawn cooldown.
Refactored the CQ test code to remove repetition in test setup.
Built a simple test to evaluate the attack task for fighters.
Cleaned up some batch actor code.
Moved non-USTRUCT structs into namespaces so they could have shorter names.
21 July 2025
Reordered the spawn phase for capital ship fighters.
Originally the timeline was:
- Capital ships spawn fighters
- Capital ships refresh their view of the fighters
- Capital ships send orders to fighters (these take effect immediately)
- Sort internal fighter data by their current task for easy batching
- (general game simulation)
- Fighters prune dead entities if any were killed
- Tick end
This involves changes to the fightersâ data layout three times in the tick (spawn, sort, prune). It was messy and the dataâs representation was less stable than I wanted.
Capitals now queue spawn requests which are committed at the end of the frame, right after the kills. We now have two layout changes instead of one. Capitals now see a stable view of the fighters during their decision phase.
I intend to make the orders also use a queue system. I can either delay to the tick end or the start of the next tick. Either way, all the state changes will be localised to one tick boundary.
My check() calls CQ tests are proving their worth.
The transition to tick-end spawns was pretty simple.
Issues with the data were caught immediately by the check() calls and the tests confirmed the resulting gameplay was unchanged.
19 July 2025
A day of pain with debugging the fighter tasks system. The issue was in the tests. My mistake was to use indexing when itâs not really stable anymore. I need to work exclusively with handles.
18 July 2025
More work on the fighter state machine. The challenge is keeping them all contiguous without multiple sorts. In the end a brute force check was fine. I use SOA layouts and with 3600 fighters, the check only took 1.7 Îźs according to Unreal Insights (including the 100ns profiling overhead).
The rest of the day was pain. Trying to fix issues with syncing the state.
15 July 2025
Worked on the fighter state machine. For now weâll have three states:
- Idle
- Move to location
- Attack
Each state is a superset of the other. To simplify the logic, Iâve let the fighters move in a 6DOF Descent-like style. This skips having to put in attack runs. The fighters can just stop dead at their targets and shoot at them if no one else is around. Fighters will have an attack band within which they shoot. If theyâre too close, we can just make them reverse.
11 July 2025
- Finished off the work to unify target handling in the editor.
- Fighters are now reassigned to a new capital ship when their parent dies
Unified target handling
The proxy classes are being extended to hold this interface.
class ITestEntity {
GENERATED_BODY()
public:
virtual auto get_entity_handle() const noexcept -> FRegistryEntityHandle = 0;
};
Itâs used to allow arbitrary targeting in the editor.
5 July 2025
- Merged entity registry update function and the death update function
- Have capital ships not spawn fighters if they have no target
Fought for hours with Unrealâs functional testing framework. For whatever reason, itâs the most unstable system when I use it. The most recent issue was:
- The level would load
- The actors were there (or some were)
- The test actor kept reading back zeros and null data from my entity registry
- Breakpoints werenât hitting for the non-test actor
It was like the actors werenât being copied over to the new level properly. I discovered CQ Tests which allow level loading. They appear to work.
4 July 2025
Set up a hub page for Blender. I donât use it often enough to remember things so this will be very useful.
Game design
- Added a fire rate toggle
- Fighters now react to being shot and fight back
- Made a new 3D model for the fighters
- Fighters and capital ships have mask textures and glow with the team colours
- Fighters and capital ships choose new targets when the original target dies
Fire rate
Iâd like to explore how different rates feel.
- Single shot
- Burst (existing mode)
- Auto fire
I think I will need some kind of heat system to dissuade holding autofire down.
Screenshots