Vanilla is a roguelike game written in Ruby, inspired by the original 1980's Rogue game. It features procedurally generated mazes, player movement, and a flexible architecture based on the Entity-Component-System pattern with an event-driven system for logging and debugging.
Navigate your character (@) through the maze to find the stairs (%) that lead to the next level. As you progress, the mazes become more complex and dangerous!
- Ruby (version specified in
.ruby-version, currently 3.4.1) - rbenv (recommended for Ruby version management)
- Homebrew (for macOS users)
./install.sh- Install dependencies:
brew bundle- Install the required Ruby version:
rbenv install- Install bundler and dependencies:
gem install bundler
bundle installThe simplest way to play the game is to use the executable:
./bin/play.rbUse either Vim-style keys or arrow keys to navigate your character:
- H or ← - Move left
- J or ↓ - Move down
- K or ↑ - Move up
- L or → - Move right
- q - Quit the game (may require multiple presses if you've been using arrow keys)
Vanilla uses RSpec for unit testing. To run the test suite:
bundle exec rspecTo run specific tests:
# Run tests for a specific component
bundle exec rspec spec/lib/vanilla/components/
# Run a specific test file
bundle exec rspec spec/lib/vanilla/support/tile_type_spec.rb
bundle exec rspec spec/lib/vanilla/components/render_component_spec.rbVanilla is built using a combination of design patterns that provide flexibility, modularity, and debuggability:
- Game Class: Implements the Game Loop pattern, managing the game lifecycle from initialization to cleanup
- Level Management: Manages the maze/dungeon structure and player position
- Entity-Component-System: Organizes game objects and behaviors in a modular fashion
- Event System: Provides event-driven architecture for logging, debugging, and game state tracking
- Maze Generation: Various algorithms for procedural maze creation
- Rendering System: Handles the visual representation of the game state
bin/play.rb (Entry Point)
|
+--> Vanilla::Game (Game Logic)
|
+--> @world = Vanilla::World (ECS Coordinator)
| |
| +--> @entities (Hash of Entity objects)
| +--> @systems (Array of [System, Priority] pairs)
| +--> @event_queue, @command_queue, @display, etc.
|
+--> @player (Entity created via EntityFactory)
+--> @maze_system (and other systems, added to @world)
+--> Game Loop (calls @world.update)
The core of Vanilla's architecture is built on the ECS pattern:
- Entities: Game objects with a unique ID (e.g., Player, Monsters)
- Components: Data containers that define aspects of entities (e.g., Position, Tile)
- Systems: Logic that operates on entities with specific components (e.g., MovementSystem)
This pattern allows for flexible composition of game objects and clear separation between data and behavior.
Input handling uses the Command pattern:
InputHandlertranslates key inputs into command objectsMoveCommand,ExitCommand, and other commands encapsulate actionsNullCommandimplements the Null Object pattern for handling unknown inputs
The event system provides several benefits:
- Debugging: Capture and analyze game events for troubleshooting
- Decoupling: Components communicate without direct dependencies
- Game State Recording: Record event logs for replay and analysis
- Visualization: Tools for visualizing event sequences and timing
Vanilla implements several maze generation algorithms to create different types of labyrinths:
For each cell in the grid, it randomly creates a passage either north or east. This is the default algorithm.
A random walk algorithm that creates completely unbiased mazes.
Creates mazes with long corridors and fewer dead ends.
Divides the space recursively, creating more boxy and rectangular mazes.
Vanilla includes a comprehensive logging system. Logs are stored in the logs/ directory with timestamped filenames.
You can set the log level using the VANILLA_LOG_LEVEL environment variable:
VANILLA_LOG_LEVEL=debug ./bin/play.rbAvailable log levels: debug, info, warn, error, fatal
While running the game you can see the logs in real time to help debugging issues:
./scripts/log_monitor.rbThe event system includes visualization tools to help understand game behavior:
ruby scripts/visualize_events.rbThis will display the available sessions and allow you to select one to visualize.
vanilla/
├── bin/ # Executable scripts
├── docs/ # Architecture documentation
├── event_logs/ # Stored event logs
├── event_visualizations/ # Generated event visualizations
├── examples/ # Example code and demos
├── lib/ # Main source code
│ └── vanilla/
│ ├── algorithms/ # Maze generation algorithms
│ ├── components/ # ECS components
│ ├── entities/ # Game entities (Player, Monster)
│ ├── events/ # Event system implementation
│ │ └── storage/ # Event storage mechanisms
│ ├── map_utils/ # Grid and cell implementations
│ ├── systems/ # ECS systems (Movement, Monster)
│ └── support/ # Utility classes
├── logs/ # Game logs
├── scripts/ # Utility scripts
├── spec/ # Test files
└── coverage/ # Test coverage reports
Contributions are welcome! The project is still a work in progress with several areas for improvement:
- Complete ECS Implementation: Adding more systems and components
- Event System Enhancements: Additional event types and visualization options
- Game Features: Combat system, inventory management, more monster types
- UI Improvements: Better visualization, game stats display
- Performance Optimizations: Spatial partitioning, rendering optimizations
Vanilla is available under the MIT License.