HardDriverz is an arcade racing game where players customize karts to compete through twisty, futuristic tracks that defy gravity. Pick up unique power-ups to get ahead of other racers as you compete to be the fastest on the circuit.
Gameplay Trailer
My Contributions
I served as the UI Systems Programmer on this team project, solely responsible for the in-game HUD framework and the global event bus that powers it. My work spanned two major areas:
- Event-Driven HUD Framework (
UMG_HudPannel,BPC_KartHud). Designed and implemented a split-screen-aware HUD system that dynamically rearranges layout, anchors, and widget instances based on the active player count. Each HUD element (Lap Counter, Pickup, Ranking, Timer) is a self-contained, event-receiving component with its own lifecycle. - Blueprint-Based Global Event Bus (
BP_EventModule,TABLE_RegisterEvent). Architected a centralized message bus that decouples gameplay systems from UI. Designers register new events via a DataTable row. No code changes required. Any system can broadcast or subscribe without holding direct references to other actors.
Technical Overview
The core challenge in HardDriverz was maintaining UI performance and layout integrity across diverse player counts in a high-speed racing game. I architected a data-driven UI framework that leverages an asynchronous global message bus to decouple gameplay logic from high-frequency UI updates.
Instead of traditional polling or hard-coded UI references, I implemented a “Push” architecture where the game state manages its own events, and the HUD acts as a reactive listener.
Architectural Highlight
I designed the communication layer through a centralized Event Module, allowing every component, from weapon pickups to lap updates, to broadcast state changes without needing a direct reference to the UI widgets.
graph TD
subgraph Gameplay Logic
P[Player Pawn] --> BPC_KH[BPC_KartHud Component]
P --> BPC_L[BPC_LapCounter Logic]
P --> BPC_P[Pickup System]
end
subgraph Messaging Layer
EB[BP_EventModule Message Bus]
DB[TABLE_RegisterEvent] -- Defines --> EB
BPC_L -- Broadcasts --> EB
BPC_P -- Broadcasts --> EB
end
subgraph UI Framework
UHP[UMG_HudPannel Controller]
EB -- Triggers Update --> UHP
UHP --> LC[UMG_HudLapCounter]
UHP --> RK[UMG_HudRanking]
UHP --> PK[UMG_HudPickup]
UHP --> TM[UMG_HudTimer]
end
Core Implementation Skills
Adaptive HUD Framework (UMG_HudPannel)
The primary UI container, UMG_HudPannel, was designed to handle high-cardinality data and dynamic screen real estate.
- Multi-View Logic: Using an enumeration-based system (
E_Layout), I implementedfunc_RearrangeLayoutto automatically shift UI anchors and widget instances between Single Player, Horizontal Split, and Four-Way Split modes. - Dependency Injection via BPC_KartHud: I utilized
BPC_KartHudas a bridge component, injecting valid gameplay references into the HUD during the initialization phase to avoid runtimeGetActorOfClasscalls.
Componentized Lifecycle Management
Each HUD element was built as a standalone, event-receiving unit. This modularity allows for rapid iteration on individual features (Ranking, Timer, Lap Counters) without risking the stability of the entire HUD stack.
- Ranking & Progress: The ranking system utilizes the global bus to update player hierarchy in real-time based on distance-to-spline metrics.
- Adaptive Timing: The timer and lap counter components utilize cached event data to update only when a valid state change (e.g., crossing a sector gate) is detected, minimizing UI tick overhead.
- Pickup Display: The pickup widget listens for item acquisition events and displays the current power-up state, fully decoupled from the pickup gameplay logic.
Data-Driven Global Event Bus
The foundational layer is the BP_EventModule, which standardizes communication across the entire project.
- Low-Code Registration: By using
TABLE_RegisterEvent, I allowed designers to add new game events (e.g., “Nitro Used”, “Target Locked”) via a simple DataTable row. - Event Holder Pattern: Each event is backed by a
DA_EventHolderdata asset, ensuring that event signatures remain consistent even when used across diverse systems like VFX, SFX, and UI.
Design Philosophy
Across the HUD framework and event bus, several principles guided the architecture:
Reactive Over Polling — The entire UI layer operates on a push model. No widget polls for state on tick. Every update is triggered by an event broadcast through the global bus, keeping per-frame overhead near zero regardless of widget count.
Layout as Data — Split-screen configurations are not separate widget trees. A single UMG_HudPannel instance reads an E_Layout enum and repositions anchors, sizes, and visibility programmatically. Adding a new layout mode means adding an enum value and its anchor data, not duplicating widgets.
Component Isolation — Each HUD element (Ranking, Timer, Lap Counter, Pickup) owns its own initialization, teardown, and event subscriptions. One component crashing or being removed has zero impact on the rest of the HUD stack. This made parallel development across team members frictionless.
Designer-Friendly Extensibility — The TABLE_RegisterEvent DataTable lets designers define new game events without touching Blueprint graphs or code. Combined with the DA_EventHolder data asset pattern, event signatures stay type-safe while remaining accessible to non-programmers.
Minimal Coupling — Gameplay systems never hold references to UI widgets. BPC_KartHud acts as the sole injection point during initialization, and all runtime communication flows through the event bus. This means any gameplay system can be tested independently of the UI, and vice versa.