A horde-based twin-stick shooter built around a slow-motion mechanic tied to hit accuracy, five enemy archetypes, and a multi-phase boss.
January — April 2024
Slow and Steady was built for IAT 410, SFU's senior game development capstone. The brief was open-ended: build a complete 2D game from scratch as a four-person team. We picked a horde-based twin-stick shooter, which gave us room to focus on combat feel and enemy variety.
The core loop centers on precision aiming, a slow-motion mechanic tied to hit accuracy, and escalating enemy waves that force the player to adapt strategy as encounters scale. Five enemy archetypes plus a multi-phase boss give the later waves distinct tactical problems instead of just higher numbers.
Lead programmer and QA tester on a four-person team (alongside a project manager/media specialist, a designer/level designer, and a support programmer/visual artist). I wrote the large majority of the game's code: movement and aiming, hitscan shooting, the shared enemy health system, enemy AI, and the slow-motion mechanic, and I handled QA testing for the team.
Core Gameplay Mechanics and Responsive Design: Built the core movement and aiming systems: WASD/arrow-key movement decoupled from mouse-driven aim direction, so the player can strafe and shoot independently — the foundation every other combat system in the game builds on.
Enhanced Shooting Dynamics: Implemented hitscan-style shooting with physics-based collision detection and bullet tracers, giving immediate visual confirmation on every shot without waiting on projectile travel time.
Health Systems and Progressive Challenges: Built a shared enemy health system that scales across archetypes without per-enemy special-casing, plus a wave spawner that ramps difficulty and enemy composition over time rather than just raw enemy count.
Enemy Advanced AI and Tactical Depth: Added new enemy AI archetypes with distinct behaviors on top of the shared health/state system, and a reload-bar UI element that turns weapon cooldown into a visible pacing decision instead of a hidden timer.
Development started with the core movement and aiming loop, then layered in enemy AI with A* pathfinding, a health/damage system shared across enemy types, and a wave spawner to structure encounters. The slow-motion mechanic and its accuracy-based recharge came later, once the base combat loop was solid enough to build a skill-expression system on top of. Final weeks went into performance work (projectile pooling) and the Cybertruck boss fight, a multi-phase encounter built to stress-test every system built up to that point. Art, UI, and audio were built in parallel by the rest of the team.
Our playtests followed a fixed five-question script (movement responsiveness, shooting precision, kill satisfaction, enemy AI behavior, and camera perspective), run over Discord with screen-share and in person. Testers called the shooting clean but too easy: with nothing to dodge, the sniper felt unstoppable and enemies posed no threat. That drove the next build: enemies that fire dodgeable bullets, more varied enemy types, enemies that face different directions instead of gliding, objective and remaining-enemy indicators, a customizable minimap, and a fix so the slow-motion bar stops charging once it has been fully consumed.
The slow-motion rework came out of that same sniper-is-unstoppable feedback. The mechanic drops Time.timeScale to a fraction of normal on a precision hit, so enemies, bullets, and animations all visibly crawl — but the first version made aiming crawl with them, since the aim raycast was ticking off the same scaled Time.deltaTime as everything else. It killed the exact feeling the mechanic was supposed to create: instead of a sharpened, hyper-aware player standing apart from a slowed-down world, the player just felt sluggish too. The fix was to pull the aim trace and mouse-look update off scaled time entirely and run them on Time.unscaledDeltaTime, so the reticle stays exactly as responsive during slow-mo as it is at full speed while everything else lags behind it. I also lerped the timeScale transition in and out instead of snapping it, since a hard cut was popping the audio pitch and causing one-frame physics jitter on enemies mid-animation.
The biggest technical lesson was keeping combat systems modular enough that a late addition — the slow-motion mechanic — could plug into player movement, camera, and enemy AI without a rewrite of any of them. That meant designing the original systems with hooks for time-scale changes from the start, before slow-motion was even a confirmed feature. Debugging combat feel was mostly about instrumentation: the hit-marker and kill-confirmation audio started as class feedback on our proposal pitch (make every kill feel satisfying), and watching playtesters confirmed it: without it, they couldn't tell when a shot had landed.