Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

sector_five

A 2D arcade shooter in Ruby with an optional AI wingman. Originally built from the Learn Game Programming with Ruby tutorial in 2018; modernized, refactored, and extended with classical game AI in 2026.


The Story

I built this game in 2018 while working through a game programming book. It worked, and I moved on. Coming back to it in 2026, I found the kind of code you'd expect from someone learning to program: everything in one class, no tests, a typo in a constant (WIDOW_HEIGHT), and a movement function that had never worked correctly.

The goal of this revision wasn't to rewrite it — it was to do what a senior engineer actually does: understand the existing system, add tests to pin the behavior, refactor to a cleaner architecture, then extend it with something new. The new thing is an AI wingman.


The Game

Top-down arcade shooter. You control a ship at the bottom of the screen. Enemy ships descend from the top. Destroy them before they reach you or you fly too close to the MotherShip.

Controls:

  • Arrow keys — turn and thrust
  • Space — fire bullet
  • C (hold) — fire laser (unlocked at 50 kills)
  • V (hold) — fire blaster (unlocked at 150 kills)

Start screen:

  • W — toggle AI wingman on/off
  • Space — start

The Wingman

The optional AI wingman is built on classical game AI — not an LLM. The reason: arcade games run at 60 frames per second. A wingman that makes an API call to decide where to fly would be both too slow and wildly overkill for a spatial reasoning problem that decades-old algorithms solve perfectly.

The wingman runs a four-state finite state machine:

ESCORTING ──→ ENGAGING    enemy enters engagement range (200px)
ENGAGING  ──→ ESCORTING   no enemies in range
ANY STATE ──→ EVADING     enemy within collision range (60px) — takes priority
EVADING   ──→ RETURNING   collision threat clears
RETURNING ──→ ESCORTING   wingman back in formation slot

Each state delegates to a specialized component:

  • FormationKeeper — computes the wingman's formation position relative to the player, clamped to screen bounds
  • TargetPrioritizer — scores enemies by proximity and trajectory (dot product of velocity toward player)
  • PredictiveAimer — solves the quadratic intercept equation to compute lead angle for a moving target
  • WingmanStateMachine — drives state transitions based on observed game state

The wingman fires at a low probability per tick (not every frame) and occasionally misses. Perfect AI isn't more impressive — it's less fun.


Install and Run

Requires Ruby 3.2+ and the Gosu native library dependencies for your platform. See the Gosu wiki for system-level setup.

bundle install
ruby sector_five.rb

Architecture

lib/
  entities/         # Ship, Player, Wingman, Enemy, Projectile, Bullet, Laser, Blaster, Explosion
  systems/          # CollisionDetector, WeaponProgression
  scenes/           # StartScene, GameScene, EndScene
  wingman/          # FormationKeeper, TargetPrioritizer, PredictiveAimer, WingmanStateMachine
spec/               # mirrors lib/ — pure-logic components only
sector_five.rb      # entry point

GameWindow manages scene transitions and delegates update/draw/button_down to the active scene. GameScene owns all game state and coordinates entities, systems, and the wingman each tick.

The wingman AI components are pure Ruby modules with no Gosu dependency — fully unit-testable and deliberately separated from the Wingman entity that wires them together.


Testing

bundle exec rspec

~65 examples covering collision math, weapon progression thresholds, projectile motion, ship physics, and all four AI components. Game code that requires Gosu (rendering, input, window) is excluded from tests by design.

bundle exec rspec spec/wingman/   # AI components only

Roadmap

v1.x possibilities:

  • Smarter enemies that dodge bullets (reuses PredictiveAimer logic)
  • --difficulty flag to tune wingman miss rate and reaction time
  • Replay system

Cosmetic stretch (if LLMs earn a place):

  • Between-wave wingman banter — language work at acceptable latency, not gameplay decisions

Credits

Music by Kevin MacLeod (incompetech.com), licensed under Creative Commons Attribution. See credits.txt for full attribution.

Original tutorial: Learn Game Programming with Ruby by Mark Sobkowicz.


License

MIT — see LICENSE.

About

A 2D arcade shooter in Ruby with an optional AI wingman built on classical game AI (state machines, predictive aiming, formation flying). Originally a 2018 tutorial project, refactored and extended in 2026."

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages