Dev Log

11 August 2025

  • Make tests use FString::Format
  • Reorganise test string handling to reduce allocations
    • Add TestDisplayTraits<T> to automatically handle formatting with FString::Format
  • 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 FTickCountdown a 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 SandboxCore plugin and changed the tests from automation tests to low-level Catch2 tests
  • Clamp fighter move distances to prevent overshoot
  • Add some variadic helpers for nullptr and 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 NativePreConstruct for UValueWidget previews
  • Allow fighters to intercept nearby enemies when moving to their objectives
  • Add TimeSeriesData class 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

A capital ship
A capital ship
Fighters
Fighters
A battle in progress
A battle in progress