384 lines
16 KiB
Markdown
384 lines
16 KiB
Markdown
# Mice!
|
|
|
|
Mice! is a strategic game where players must kill rats with bombs before they reproduce and become too numerous. The game is a clone of the classic game Rats! for Windows 95.
|
|
|
|
## Compatibility
|
|
*It's developed in Python 3.13, please use it*
|
|
|
|
## Features
|
|
|
|
- **Maze Generation**: Randomly generated mazes using Depth First Search (DFS) algorithm.
|
|
- **Original Level Support**: Loads the original `level.dat` from `assets/Rat/level.dat` when present and falls back to `maze.json` otherwise.
|
|
- **Units**: Different types of units such as rats, bombs, and points with specific behaviors.
|
|
- **Graphics**: Custom graphics for maze tiles, units, and effects.
|
|
- **Sound Effects**: Audio feedback for various game events.
|
|
- **Scoring**: Points system to track player progress.
|
|
- **Performance**: Optimized collision detection system supporting 200+ simultaneous units using NumPy vectorization.
|
|
|
|
## Utilities
|
|
|
|
### Microphone Visualizer
|
|
|
|
A small SDL2 microphone visualizer is available in `tools/mic_visualizer.py`.
|
|
|
|
- List capture devices: `python tools/mic_visualizer.py --list-devices`
|
|
- Open the default microphone: `python tools/mic_visualizer.py`
|
|
- Open a specific input: `python tools/mic_visualizer.py --device-index 1`
|
|
- On muOS, use `mice_mic.sh` as a launcher in `ROMS/Ports` and it will run fullscreen with gamepad quit support.
|
|
|
|
## Engine Architecture
|
|
|
|
The Mice! game engine is built on a modular architecture designed for flexibility and maintainability. The engine follows a component-based design pattern where different systems handle specific aspects of the game.
|
|
|
|
### Core Engine Components
|
|
|
|
#### 1. **Collision System** (`engine/collision_system.py`)
|
|
- **CollisionSystem Class**: High-performance collision detection using NumPy vectorization
|
|
- **Features**:
|
|
- Spatial hashing with grid-based lookups (O(1) average case)
|
|
- Support for 6 collision layers (RAT, BOMB, GAS, MINE, POINT, EXPLOSION)
|
|
- Hybrid approach: simple iteration for <10 candidates, NumPy vectorization for ≥10
|
|
- Pre-allocated arrays with capacity management to minimize overhead
|
|
- Area queries for explosion damage (get_units_in_area)
|
|
- Cell-based queries for gas/mine detection (get_units_in_cell)
|
|
- **Performance**:
|
|
- Handles 200+ units at ~3ms per frame
|
|
- Reduces collision checks from O(n²) to O(n) using spatial partitioning
|
|
- Vectorized distance calculations for massive parallel processing
|
|
|
|
#### 2. **Rendering System** (`engine/sdl2.py`)
|
|
- **GameWindow Class**: Central rendering manager using SDL2
|
|
- **Features**:
|
|
- Hardware-accelerated rendering via SDL2
|
|
- Texture management and caching
|
|
- Sprite rendering with transparency support (SDL_BLENDMODE_BLEND for alpha blending)
|
|
- Text rendering with custom fonts
|
|
- Resolution-independent scaling
|
|
- Fullscreen/windowed mode switching
|
|
- Blood stain rendering with RGBA format and proper alpha channel
|
|
- **Optimizations**:
|
|
- Cached viewport bounds to avoid repeated calculations
|
|
- Pre-cached image sizes for all assets at startup
|
|
- Blood overlay layer system (no background regeneration needed)
|
|
- Pre-generated blood stain pool (10 variants) for instant spawning
|
|
- **Implementation**:
|
|
- Uses SDL2 renderer for efficient GPU-accelerated drawing
|
|
- Implements double buffering for smooth animation
|
|
- Manages texture atlas for optimized memory usage
|
|
- Handles viewport transformations for different screen resolutions
|
|
|
|
#### 3. **Input System** (`engine/controls.py`)
|
|
- **KeyBindings Class**: Handles all user input
|
|
- **Features**:
|
|
- Keyboard input mapping and handling
|
|
- Joystick/gamepad support
|
|
- Configurable key bindings
|
|
- Input state management
|
|
- **Implementation**:
|
|
- Event-driven input processing
|
|
- Key state buffering for smooth movement
|
|
- Support for multiple input devices simultaneously
|
|
- Customizable control schemes
|
|
|
|
#### 3. **Map System** (`engine/maze.py`)
|
|
- **Map Class**: Manages the game world structure
|
|
- **Features**:
|
|
- Maze data loading and parsing
|
|
- DAT archive parsing for the original 32 built-in RATS levels
|
|
- Collision detection system
|
|
- Tile-based world representation
|
|
- Pathfinding support for AI units
|
|
- **Implementation**:
|
|
- Grid-based coordinate system
|
|
- Efficient collision detection using spatial partitioning
|
|
- Support for different tile types (walls, floors, special tiles)
|
|
- Integration with maze generation algorithms
|
|
|
|
#### 4. **Audio System**
|
|
- **Sound Management**: Handles all audio playback
|
|
- **Features**:
|
|
- Sound effect playback
|
|
- Background music support
|
|
- Volume control
|
|
- Multiple audio channels
|
|
- **Implementation**:
|
|
- Uses subprocess module for audio playback
|
|
- Asynchronous sound loading and playing
|
|
- Audio file format support (WAV, MP3, OGG)
|
|
|
|
### Game Loop Architecture
|
|
|
|
The main game loop follows an optimized 4-pass pattern:
|
|
1. **Pre-Registration Phase**: Populate collision system with unit positions before movement
|
|
2. **Update Phase**: Execute unit logic and movement (bombs/gas can now query collision system)
|
|
3. **Re-Registration Phase**: Update collision system with new positions after movement
|
|
4. **Collision & Render Phase**: Check collisions and draw all game objects
|
|
|
|
```
|
|
Pre-Register → Move → Re-Register → Collisions → Render → Present → Repeat
|
|
```
|
|
|
|
This architecture ensures weapons (bombs, gas) can detect victims during their execution phase while maintaining accurate collision data.
|
|
|
|
## Units Implementation
|
|
|
|
The game uses an object-oriented approach for all game entities. Each unit type inherits from a base unit class and implements specific behaviors.
|
|
|
|
### Base Unit Architecture
|
|
|
|
All units share common properties and methods:
|
|
- **Position and Movement**: 2D coordinates with movement capabilities
|
|
- **Unique Identification**: UUID-based unique identifiers
|
|
- **Collision Detection**: Bounding box collision system
|
|
- **State Management**: Current state tracking (alive, dead, exploding, etc.)
|
|
- **Rendering**: Sprite-based visual representation
|
|
|
|
### Unit Types Implementation
|
|
|
|
#### 1. **Rat Units** (`units/rat.py`)
|
|
|
|
**Base Rat Class**:
|
|
- **AI Behavior**: Implements pathfinding using A* algorithm
|
|
- **Movement**: Grid-based movement with smooth interpolation
|
|
- **State Machine**: Multiple states (wandering, fleeing, reproducing)
|
|
|
|
**Male Rat Class**:
|
|
- **Reproduction Logic**: Seeks female rats for mating
|
|
- **Territorial Behavior**: Defends territory from other males
|
|
- **Lifespan Management**: Age-based death system
|
|
|
|
**Female Rat Class**:
|
|
- **Pregnancy System**: Gestation period simulation
|
|
- **Offspring Generation**: Creates new rat units
|
|
- **Maternal Behavior**: Protects offspring from threats
|
|
|
|
**Implementation Details**:
|
|
```python
|
|
# Optimized rat behavior with pre-calculated render positions
|
|
class Rat:
|
|
def move(self):
|
|
self.process_ai() # Decision making
|
|
self.handle_movement() # Position updates
|
|
self._update_render_position() # Cache render coordinates
|
|
|
|
def collisions(self):
|
|
# Use optimized collision system with vectorization
|
|
collisions = self.game.collision_system.get_collisions_for_unit(
|
|
self.id, self.bbox, self.collision_layer
|
|
)
|
|
# Process only Rat-to-Rat collisions
|
|
for _, other_id in collisions:
|
|
other_unit = self.game.get_unit_by_id(other_id)
|
|
if isinstance(other_unit, Rat):
|
|
self.handle_rat_collision(other_unit)
|
|
|
|
def draw(self):
|
|
# Use cached render positions (no recalculation)
|
|
self.game.render_engine.draw_image(
|
|
self.render_x, self.render_y, self.sprite, tag="unit"
|
|
)
|
|
```
|
|
|
|
#### 2. **Bomb Units** (`units/bomb.py`)
|
|
|
|
**Bomb Class**:
|
|
- **Timer System**: Countdown mechanism before explosion
|
|
- **Placement Logic**: Player-controlled positioning
|
|
- **Damage Calculation**: Blast radius and damage computation
|
|
|
|
**Explosion Class**:
|
|
- **Visual Effects**: Animated explosion graphics
|
|
- **Damage Dealing**: Affects units within blast radius
|
|
- **Temporary Entity**: Self-destructs after animation
|
|
|
|
**Implementation Details**:
|
|
- **State Machine**: Armed → Countdown → Exploding → Cleanup
|
|
- **Optimized Damage System**: Uses collision_system.get_units_in_area() with vectorized distance calculations
|
|
- **Effect Propagation**: Chain reaction support for multiple bombs
|
|
- **Area Query Example**:
|
|
```python
|
|
def die(self):
|
|
# Collect explosion positions
|
|
explosion_positions = self.calculate_blast_radius()
|
|
# Query all rats in blast area using vectorized collision system
|
|
victims = self.game.collision_system.get_units_in_area(
|
|
explosion_positions,
|
|
layer_filter=CollisionLayer.RAT
|
|
)
|
|
for unit_id in victims:
|
|
rat = self.game.get_unit_by_id(unit_id)
|
|
if rat:
|
|
rat.die()
|
|
```
|
|
|
|
#### 3. **Point Units** (`units/points.py`)
|
|
|
|
**Point Class**:
|
|
- **Collection Mechanics**: Player interaction system
|
|
- **Value System**: Different point values for different achievements
|
|
- **Visual Feedback**: Pickup animations and effects
|
|
|
|
### Unit Interaction System
|
|
|
|
Units interact through a centralized collision and event system:
|
|
|
|
1. **Collision Detection**:
|
|
- **Spatial hashing**: Grid-based broad phase with O(1) lookups
|
|
- **NumPy vectorization**: Parallel distance calculations for large candidate sets
|
|
- **Hybrid approach**: Direct iteration for <10 candidates, vectorization for ≥10
|
|
- **Layer filtering**: Efficient collision filtering by unit type (RAT, BOMB, GAS, etc.)
|
|
- **Area queries**: Optimized explosion and gas effect calculations
|
|
|
|
2. **Event System**:
|
|
- Unit death events
|
|
- Reproduction events
|
|
- Explosion events (with area damage)
|
|
- Point collection events (90 frames lifetime ~1.5s at 60 FPS)
|
|
|
|
3. **AI Communication**:
|
|
- Shared pathfinding data
|
|
- Pheromone trail system for rat behavior
|
|
- Danger awareness (bombs, explosions)
|
|
|
|
4. **Spawn Protection**:
|
|
- Rats won't spawn on cells occupied by weapons (mines, bombs, gas)
|
|
- Automatic fallback to adjacent cells if primary position blocked
|
|
- Prevents unfair early-game deaths
|
|
|
|
## Technical Details
|
|
|
|
- **Language**: Python 3.13
|
|
- **Libraries**:
|
|
- `numpy` 2.3.4 for vectorized collision detection
|
|
- `sdl2` for graphics and window management
|
|
|
|
## Map Editor
|
|
|
|
The project now includes a Tkinter editor for `level.dat` archives:
|
|
|
|
- Launch with `python tools/level_editor.py`
|
|
- Open a specific archive with `python tools/level_editor.py --file assets/Rat/level.dat`
|
|
- Start on a specific level with `python tools/level_editor.py --file assets/Rat/level.dat --level 7`
|
|
- The editor requires a Python installation with the standard `tkinter` module available at OS level
|
|
|
|
Editor capabilities:
|
|
|
|
- Edits the full 32-level DAT archive used by the game
|
|
- Creates new DAT archives with 32 default levels
|
|
- Paints `EMPTY`, `WALL`, and `TUNNEL` tiles with brush, fill, and rectangle tools
|
|
- Supports undo/redo, level copy/paste, and level duplication between slots
|
|
- Imports a single level from JSON and exports the current level back to JSON
|
|
- Validates common gameplay issues such as missing spawn cells, open borders, and disconnected traversable areas
|
|
|
|
## Level Sources
|
|
|
|
- Preferred source: `assets/Rat/level.dat`
|
|
- Fallback source: `maze.json`
|
|
- Current behavior: the loader can read any level from the DAT archive via `--level N`, while still falling back to `maze.json` when the DAT is unavailable.
|
|
- Tile semantics are now preserved internally from the original format: `0=EMPTY`, `1=WALL`, `2=TUNNEL`.
|
|
- Rendering uses those semantics directly: walls use themed grass/flower tiles, tunnel cells use themed cave tiles, and empty cells remain the generic walkable tunnel floor used by the Python version.
|
|
|
|
### Run examples
|
|
|
|
- `python rats.py`
|
|
- `python rats.py --level 7`
|
|
- `python rats.py --map maze.json`
|
|
- `Pillow` for image processing
|
|
- `uuid` for unique unit identification
|
|
- `subprocess` for playing sound effects
|
|
- `tkinter` for maze generation visualization
|
|
- **Performance Optimizations**:
|
|
- **Collision System**: NumPy-based spatial hashing reducing O(n²) to O(n)
|
|
- **Rendering Cache**: Pre-calculated render positions, viewport bounds, and image sizes
|
|
- **Blood Overlay**: Separate sprite layer eliminates background regeneration
|
|
- **Hybrid Processing**: Automatic switching between direct iteration and vectorization
|
|
- **Pre-allocated Arrays**: Capacity-based resizing minimizes NumPy vstack overhead
|
|
- **Texture Atlasing**: Reduced memory usage and GPU calls
|
|
- **Object Pooling**: Blood stain pool (10 pre-generated variants)
|
|
- **Delta Time Updates**: Frame rate independence
|
|
- **Memory Management**:
|
|
- Automatic cleanup of dead units
|
|
- Texture caching and reuse
|
|
- Efficient data structures for 200+ simultaneous units
|
|
- Blood stain sprite pool to avoid runtime generation
|
|
|
|
## Environment Variables
|
|
|
|
- `SDL_VIDEODRIVER`: Set the video driver (x11, wayland, etc.)
|
|
- `RESOLUTION`: Set the screen resolution (format: WIDTHxHEIGHT)
|
|
- `FULLSCREEN`: Enable/disable fullscreen mode (true/false)
|
|
- `SOUND_ENABLED`: Enable/disable sound effects (true/false)
|
|
|
|
## Installation
|
|
|
|
1. **Clone the repository**:
|
|
```bash
|
|
git clone https://github.com/yourusername/mice-maze-game.git
|
|
cd mice-maze-game
|
|
```
|
|
2. **Create a virtual environment**:
|
|
```bash
|
|
python3 -m venv venv
|
|
source venv/bin/activate
|
|
```
|
|
3. **Install the dependencies**:
|
|
```bash
|
|
pip install -r requirements.txt
|
|
```
|
|
4. **Run the game**:
|
|
```bash
|
|
python rats.py
|
|
```
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
mice/
|
|
├── engine/ # Core engine components
|
|
│ ├── collision_system.py # NumPy-based vectorized collision detection
|
|
│ ├── controls.py # Input handling system
|
|
│ ├── graphics.py # Blood overlay and rendering optimizations
|
|
│ ├── maze.py # Map and collision system
|
|
│ ├── sdl2.py # Rendering and window management
|
|
│ └── unit_manager.py # Unit spawning and lifecycle management
|
|
├── units/ # Game entity implementations
|
|
│ ├── unit.py # Base unit class with collision layers
|
|
│ ├── bomb.py # Bomb and explosion logic with area damage
|
|
│ ├── gas.py # Gas weapon with cell-based detection
|
|
│ ├── mine.py # Proximity mine with trigger system
|
|
│ ├── rat.py # Rat AI with optimized rendering cache
|
|
│ └── points.py # Collectible points (90 frames lifetime)
|
|
├── assets/ # Game resources
|
|
│ ├── images/ # Sprites and textures
|
|
│ └── fonts/ # Text rendering fonts
|
|
├── sound/ # Audio files
|
|
├── maze.py # Maze generation algorithms
|
|
├── rats.py # Main game entry point with 4-pass game loop
|
|
├── requirements.txt # Python dependencies (including numpy)
|
|
├── .env # Environment configuration
|
|
└── README.md # This documentation
|
|
```
|
|
|
|
## Game Files Details
|
|
|
|
- `maze.py`: Contains the `MazeGenerator` class implementing DFS algorithm for procedural maze generation
|
|
- `rats.py`: Main game controller with 4-pass optimized game loop, manages collision system and unit lifecycle
|
|
- `engine/collision_system.py`: NumPy-based spatial hashing system supporting 200+ units at 3ms/frame
|
|
- `engine/graphics.py`: Blood overlay system with pre-generated stain pool and rendering optimizations
|
|
- `engine/controls.py`: Input abstraction layer with configurable key bindings
|
|
- `engine/maze.py`: World representation with collision detection and pathfinding support
|
|
- `engine/sdl2.py`: Low-level graphics interface wrapping SDL2 with alpha blending and texture caching
|
|
- `engine/unit_manager.py`: Centralized unit spawning with weapon collision avoidance
|
|
- `units/unit.py`: Base unit class with collision layer support
|
|
- `units/bomb.py`: Explosive units with vectorized area damage calculations
|
|
- `units/gas.py`: Area denial weapon using cell-based victim detection
|
|
- `units/mine.py`: Proximity-triggered explosives
|
|
- `units/rat.py`: AI-driven entities with cached render positions and collision filtering
|
|
- `units/points.py`: Collectible scoring items (90 frame lifetime, ~1.5s at 60 FPS)
|
|
- `assets/`: Game resources including sprites, textures, and fonts
|
|
- `sound/`: Audio assets for game events and feedback
|
|
- `scores.txt`: Persistent high score storage
|
|
- `.env`: Runtime configuration and environment settings
|
|
- `.gitignore`: Version control exclusion rules
|
|
|