Duration: October 2025 - Present
Type: Personal Project
Role: Gameplay Programmer
Engine and Tools: Unreal Engine 5, C++ & Blueprints
Jetpack FPS is a self-directed personal project built in Unreal Engine 5 using C++ and Blueprints. Inspired by the fast, expressive movement systems in games like Black Ops 3, the goal was to engineer a prototype that captures the feeling of fluid, momentum-based traversal - where every movement state flows naturally into the next.
This is a movement-focused prototype - no enemies, no objectives. The entire scope of the project is dedicated to getting traversal right: how it feels to sprint, slide, wallrun, and jetpack through a space. Movement is the soul of an FPS, and this project is built around proving that.
Multi-State Locomotion Architecture: Designed a modular state machine with 8 locomotion states - Walk, Sprint, Crouch, Slide, WallRun, Jetpack, Prone, and Airborne. Each state transition is centralized through a single SetMovementState function with an OnMovementStateChange callback, handling side effects like capsule resizing, gravity scaling, and jump count resets. Conflict resolution logic prevents overlapping systems from fighting each other - for example, ADS cancelling auto-sprint, or jetpack cancelling an active ledge slide.
Analog Jetpack System: Implemented a curve-driven jetpack where thrust intensity ramps up based on how long the player holds the input - using a CurveFloat sampled from HoldAlpha (HoldDuration / MaxHoldDuration). Fuel drain is scaled per tick by thrust intensity so short taps consume almost nothing while sustained holds drain quickly. Timer-based update loops (rather than per-frame Tick) ensure the fuel behavior is frame-rate independent. Identified and resolved a synchronization bug where micro-tap thrust applied before the first drain tick, causing fuel to never decrement on short presses.
Custom C++ Async Root Motion Plugin: Extended a Blueprint async action plugin in C++ to wrap Unreal's FRootMotionSource_ConstantForce, exposing cancellable curve-driven movement forces to Blueprint workflows with OnComplete and OnFail delegates. This replaced LaunchCharacter impulse calls - which felt snappy and disconnected - with forces that build, sustain, and bleed off naturally, giving the jetpack and slide a momentum-based feel. The plugin stores a RootMotionSourceID for clean lifecycle management and cancellation.
FPS Animation Integration: Integrated an FPS animation pack into a third-person character Blueprint using interface-driven component access - decoupling the character from the animation components (CameraAnimator, ViewmodelController, GAIT locomotion) through Blueprint interfaces. This enables seamless first-person viewmodel transitions across all locomotion states with layered ADS, recoil, FOV, and camera tilt effects without the character Blueprint needing direct references to animation components.
UE4 to UE5 Migration: Migrated the Unreal Engine 4 ShooterGame template to Unreal Engine 5.5 via C++, resolving numerous deprecated API breakages and updating the codebase to use modern UE5 conventions. Enabled Lumen Global Illumination, Virtual Shadow Maps, Nanite, and Temporal Super Resolution - repurposing the HighRise level from the template as the playable demo environment for this project.
The project started with a simple question: what makes FPS movement feel good? I began by building the state machine foundation - getting clean transitions between basic locomotion states before adding complexity. The jetpack system went through multiple iterations: starting with AddForce calls, moving to LaunchCharacter, and finally landing on root motion sources after identifying that impulse-based approaches couldn't produce the sustained, controllable feel I was after. The C++ plugin was written to solve a specific problem - Blueprint had no clean way to apply a cancellable, duration-based force with completion callbacks. Debugging the timer synchronization bug in the fuel system was a key learning moment: matching the drain timer interval to the thrust timer interval (both at 0.02s) fixed a subtle edge case where micro-taps never triggered a drain tick. The UE5 migration came later, once the core systems were stable, and unlocked the Lumen lighting and Nanite geometry that give the demo its final visual quality.
Building this prototype taught me more about game feel engineering than any course I've taken. The gap between 'technically correct' and 'feels right' is enormous - and closing that gap requires iterating on things that are hard to quantify: does the jetpack feel weighty enough? Does the slide feel committed without feeling punishing? Working at both the Blueprint and C++ level in the same project gave me a much clearer picture of when each layer is the right tool. The C++ plugin in particular was a step outside my comfort zone and one of the most valuable things I built - it forced me to understand Unreal's movement architecture at a deeper level than Blueprints alone would allow.