
Projectile Ability System
I designed and implemented a modular projectile-based ability system in Unity, centered around a reusable state machine that governs ability activation, execution, and recovery. The project was intentionally scoped as a systems-focused exercise, emphasizing clear lifecycle management, separation of concerns, and data-driven behavior through inspector-based configuration, while supporting extensibility and visual debugging.
Abilities progress through clearly defined lifecycle states (Ready, Windup, Firing, Winddown, Cooldown), with all timing, transitions, and gating handled centrally by a shared base class. State entry and exit events allow external systems such as UI, audio, player movement control, and VFX to react without tightly coupling logic to the ability itself.
Projectile behavior is fully decoupled from the ability lifecycle. Each projectile receives configuration data and timing parameters at spawn, allowing it to independently manage launch, homing, scaling, lock-on detection, collision, and termination. This design ensures predictable behavior even after the ability has advanced to later states.
The system is demonstrated through a projectile-driven ship ability designed for a 2D shooter context, featuring configurable firing behavior, targeting logic, spawn variance, and timing controls. Extensive debug visualization and inspector tooling were used proactively to validate calculations, iterate on gameplay feel, and ensure correctness during development.
While the current implementation focuses on projectiles, the underlying state machine cleanly separates lifecycle management from behavior, making it reusable for other abilities that share the same activation flow.
PRIMARY ROLES
Abilities are implemented using a clearly defined lifecycle that controls when an ability can act, how long each phase lasts, and how systems respond to state changes. The lifecycle consists of five explicit states: Ready, Windup, Firing, Winddown, and Cooldown.
All timing, progression, and state transitions are managed by a shared abstract base class. Concrete abilities override state entry hooks to implement behavior, while the base class guarantees consistent execution order and timing across all abilities.
State transitions raise entry and exit events, allowing external systems such as UI, audio, player movement control, or AI to react without introducing direct dependencies. This event-driven approach keeps the lifecycle logic centralized, predictable, and easy to extend.
The result is a clean separation between lifecycle control and gameplay behavior, reducing duplication and making complex abilities easier to reason about and maintain.
Projectile behavior is implemented as a fully self-contained controller with an explicit two-phase lifecycle. During the launch phase, projectiles move forward with no homing, scale toward an intermediate size, and respect ability-defined timing. Once the firing window ends, projectiles transition into a homing phase, rotating smoothly toward an active target until termination.
Projectiles support multiple targeting strategies. A base target position is resolved and cached by the ability during windup to ensure consistent behavior during firing. Optional lock-on detection can dynamically override this target using either ray-based or overlap-based detection, depending on configuration.
Rotation speed, homing behavior, scaling, collision handling, and destruction rules are all driven by a data-only configuration struct. This allows the same projectile code to support straight shots, homing missiles, area-seeking projectiles, or purely cosmetic effects without modification.
By decoupling projectile logic from the ability state machine, projectiles remain stable and predictable even after the ability has transitioned to later states.
All major gameplay variables are exposed through the Unity Editor using inspector-driven configuration assets and serialized fields. Projectile behavior is defined entirely through data, including movement speeds, rotation rates, scaling phases, lock-on modes, detection ranges, and collision rules.
The ability control projectile spawning through configurable counts, spread angles, radial or cone distributions, and optional random variance. Target destinations can be resolved from multiple sources such as forward projections, fixed offsets, externally provided targets, or the ability origin itself, allowing a single ability implementation to support a wide range of behaviors.
Visual and audio elements are referenced externally, allowing projectile prefabs, explosion effects, and sound cues to be swapped freely without modifying system logic. This data-driven approach enables a wide range of behaviors, supporting rapid iteration and experimentation while maintaining a stable, reusable, and extensible codebase.
Debugging and visualization tools were integrated directly into the system to support iteration and validation. Optional runtime debug text displays ability state, timers, and normalized progress, making state flow easy to inspect during play.
Editor gizmos visualize aim direction, spread bounds, resolved target positions, lock-on detection ranges, and collision rays. These tools expose otherwise invisible calculations directly in the scene view, significantly reducing iteration time and increasing confidence when tuning complex interactions.
By prioritizing debuggability during development, the system remains transparent, testable, and easy to extend.