Blast Course 2
Developed at Amiguito Studios
The explosive sequel to Blast Course. A first-person puzzle-platformer centered around the high-speed art of Rocket Jumping.
My Role
Game Programmer
Team Size
20+ Developers
Development
Ongoing
Platform
TBD
Engineering Systems
Polymorphic Projectile Architecture
To ensure high performance and strict predictability in a fast-paced game, I bypassed Unreal Engine's native UProjectileMovementComponent. Instead, I engineered a highly modular, Tick-driven mathematical movement system utilizing SweepSingleByChannel.
- Component-Agnostic Collisions: Environmental interactions are handled cleanly by detecting "Defuser" surfaces via
UMaterialInterface. - Polymorphic Extensions: The robust
ABaseRocketallows child classes (like Bounce or Remote rockets) to implement complex behaviors, such as vector reflection, simply by overriding the virtualImpact()function. - The "Unconscious" Actor: Rockets have zero awareness of the memory pool. They simply execute their lifecycle and broadcast an
OnRocketFinishedmulticast delegate when ready for reclamation.
Dual Object Pooling
Spawning hundreds of rockets and explosions at runtime causes massive memory fragmentation and garbage collection spikes. To guarantee a locked frame rate, I built two distinct pooling strategies directly into the ACustomGameMode.
- O(1) Circular Buffer: Transient, visual-heavy explosions do not require complex lifecycle tracking. They utilize a high-performance modulo-based ring buffer for instant memory access.
- Active/Free Queues: Rockets utilize stricter management via decoupled
TArrayqueues. - Aggressive Recycling Failsafe: If a player exhausts the pre-allocated free pool, the system forces the oldest active rocket to detonate, ensuring the game never hitches due to limit exhaustion or mid-combat memory allocation.
ABaseRocket* ACustomGameMode::AcquireRocketFromPool(ERocketType _eType) {
FRocketPool& rPool = m_mRocketPools[_eType];
TObjectPtr<ABaseRocket> pRocket = nullptr;
if (!rPool.Free.IsEmpty()) pRocket = rPool.Free.Pop();
else if (rPool.Active.Num() > 0) {
// Aggressive recycling: force oldest active rocket to explode
pRocket = rPool.Active[0];
rPool.Active.RemoveAt(0);
pRocket->ForceExplosion();
}
return pRocket.Get();
}
Extended UMG Architecture
Controlling exact pixel dimensions and aspect ratios from C++ while maintaining a WYSIWYG experience for UI Artists in the Unreal Editor is notoriously difficult. I engineered an extended hierarchy to decouple layout logic from Blueprint constraints.
- Recursive State Management: The base
UCustomUserWidgetbypasses native limitations by recursively propagating customShowWidget()andHideWidget()states down deeply nested hierarchies. - Live Editor Synchronization: I developed
UResizableUserWidgetto intercept the engine'sSynchronizeProperties(). If a UI designer scales a widget in the editor, the C++ calculates the driving axis and dynamically scales the height to preserve the aspect ratio in real-time. - Encapsulated Leaf Nodes: Wrappers like
UCustomButtonWidgetcleanly map custom C++ logic to nativeESlateVisibilitystates.
void UResizableUserWidget::SynchronizeProperties() {
Super::SynchronizeProperties();
// Preserve aspect ratio if the flag is enabled in the editor.
if (m_bPreserveAspectRatio) {
if (m_fAspectRatio < 0.f && m_vWidgetSize.Y != 0.f) {
m_fAspectRatio = m_vWidgetSize.X / m_vWidgetSize.Y;
}
ApplyAspectRatio();
}
else m_fAspectRatio = 0.f;
SetWidgetSize(m_vWidgetSize);
UpdateSizeToContent();
m_vLastSize = m_vWidgetSize;
}