refactored to multiple games implementation
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
Multigame Migration Plan
|
||||
Overview
|
||||
Refactor the existing monolithic tic-tac-toe implementation into a modular game architecture that allows multiple games to run on the RP2350 platform while preserving the interrupt-driven, dual-core reactive architecture.
|
||||
|
||||
Goals
|
||||
Abstract game logic from hardware/display management
|
||||
Create reusable input processing system
|
||||
Enable multiple games to coexist in the codebase
|
||||
Maintain the efficient reactive architecture (event-driven, dual-core)
|
||||
Keep hardware-specific code isolated in basic1.cpp
|
||||
Architecture Components
|
||||
1. Input Event System
|
||||
Files: lib/input_event.h
|
||||
|
||||
Defines shared input event structures used by both InputManager and Game classes:
|
||||
|
||||
InputType enum (NONE, TOUCH_DOWN, TOUCH_MOVE, TOUCH_UP, BUTTON_0, BUTTON_1, GESTURE)
|
||||
InputEvent struct with coordinates, gesture codes, button IDs, pressure, validity flag
|
||||
2. Input Manager
|
||||
Files: lib/input_manager.h, lib/input_manager.cpp
|
||||
|
||||
Handles all input processing and debouncing:
|
||||
|
||||
Constructor: InputManager(LowLevelTouch* touch, GameConfig* config)
|
||||
Methods: process_touch_input(uint32_t* last_time), process_button_input()
|
||||
Returns InputEvent objects to be passed to games
|
||||
Manages touch debouncing and gesture recognition
|
||||
Does NOT handle button GPIO setup (stays in basic1.cpp)
|
||||
3. Abstract Game Base Class
|
||||
Files: lib/game.h
|
||||
|
||||
Defines the interface all games must implement:
|
||||
|
||||
Constructor: Game(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui)
|
||||
Protected members: width, height, renderer, gui
|
||||
Pure virtual methods:
|
||||
virtual void init() = 0 - Initialize game state
|
||||
virtual bool update(const InputEvent& event) = 0 - Process input, return true if redraw needed
|
||||
virtual void draw() = 0 - Render game to buffer
|
||||
Virtual destructor: virtual ~Game() {}
|
||||
4. Tic-Tac-Toe Game Implementation
|
||||
Files: games/tic_tac_toe.h, games/tic_tac_toe.cpp
|
||||
|
||||
Concrete implementation of the Game interface:
|
||||
|
||||
Private GameState struct with board, current player, winner, statistics
|
||||
Private method: check_winner()
|
||||
Private constants: BOARD_SIZE, CELL_SIZE, BOARD_Y, LINE_WIDTH
|
||||
Overrides: init(), update(const InputEvent& event), draw()
|
||||
Encapsulates all tic-tac-toe logic extracted from basic1.cpp lines 162-770
|
||||
5. Main Loop Refactor
|
||||
File: basic1.cpp
|
||||
|
||||
Simplified main program focusing on hardware management:
|
||||
|
||||
Keep: Display initialization, dual-core setup, interrupt handlers, GPIO configuration
|
||||
Remove: Game-specific logic (moves to TicTacToeGame)
|
||||
Add: InputManager instantiation, Game* pointer instantiation
|
||||
Modify main loop:
|
||||
Migration Steps
|
||||
Step 1: Create Input Event Header
|
||||
Extract input structures from basic1.cpp (lines 134-156) to new file lib/input_event.h.
|
||||
|
||||
Validation:
|
||||
|
||||
Compile successfully
|
||||
No duplicate definitions
|
||||
Both basic1.cpp and new files include this header
|
||||
Step 2: Create Input Manager
|
||||
Move input processing functions (lines 313-442) to new InputManager class.
|
||||
|
||||
Validation:
|
||||
|
||||
Constructor properly stores touch pointer and config
|
||||
process_touch_input() returns valid InputEvent on touch
|
||||
process_button_input() returns valid InputEvent on button press
|
||||
Debouncing still works correctly
|
||||
Compile and run - verify touch/button detection unchanged
|
||||
Step 3: Create Abstract Game Class
|
||||
Create lib/game.h with base class definition.
|
||||
|
||||
Validation:
|
||||
|
||||
Header compiles successfully
|
||||
Pure virtual methods defined correctly
|
||||
Protected members accessible to derived classes
|
||||
Step 4: Extract Tic-Tac-Toe Game
|
||||
Create TicTacToeGame class inheriting from Game.
|
||||
|
||||
Validation:
|
||||
|
||||
Move GameState struct (lines 162-176) - verify all members present
|
||||
Move check_winner() (lines 447-495) - verify logic identical
|
||||
Move game_init() to init() override (lines 505-522)
|
||||
Move game_update() to update() override (lines 536-668)
|
||||
Move game_draw() to draw() override (lines 671-770)
|
||||
Move constants: BOARD_SIZE, CELL_SIZE, BOARD_Y
|
||||
Compile successfully
|
||||
Step 5: Refactor Main Loop
|
||||
Update basic1.cpp to use new architecture.
|
||||
|
||||
Validation:
|
||||
|
||||
Remove old GameState state variable
|
||||
Remove old game functions
|
||||
Instantiate InputManager after hardware init
|
||||
Instantiate TicTacToeGame as Game*
|
||||
Update main loop to use polymorphic calls
|
||||
Compile successfully
|
||||
Run and verify: Touch input works, buttons work, game plays correctly
|
||||
Verify dual-core refresh still works (Core 1 handles display)
|
||||
Test full game: place pieces, win conditions, restart
|
||||
Step 6: Update Build System
|
||||
Modify CMakeLists.txt to include new source files.
|
||||
|
||||
Validation:
|
||||
|
||||
Add lib/input_manager.cpp
|
||||
Add games/tic_tac_toe.cpp
|
||||
Clean build succeeds
|
||||
Binary size reasonable (no major bloat)
|
||||
Step 7: Final Testing
|
||||
Comprehensive system test.
|
||||
|
||||
Validation:
|
||||
|
||||
Touch detection works (tap cells)
|
||||
Button navigation works (KEY0/KEY1)
|
||||
Game logic correct (wins, ties, restart)
|
||||
Display refreshes properly (no artifacts)
|
||||
Statistics persist across games
|
||||
Debug output shows correct events
|
||||
System remains responsive during e-ink refresh
|
||||
Future Extensions
|
||||
Adding New Games
|
||||
To add a new game (e.g., Snake, Pong):
|
||||
|
||||
Create games/snake.h and games/snake.cpp
|
||||
Inherit from Game base class
|
||||
Implement init(), update(), draw()
|
||||
Define game-specific state as private members
|
||||
Add to CMakeLists.txt
|
||||
Change game selection in basic1.cpp: Game* current_game = new SnakeGame(...)
|
||||
Game Launcher (Future)
|
||||
Create GameLauncher class to display menu
|
||||
Allow runtime game switching
|
||||
Handle cleanup: delete current_game; current_game = new SnakeGame(...)
|
||||
Store game selection preference in flash
|
||||
Key Design Principles
|
||||
Hardware Isolation: All GPIO, interrupts, hardware config stay in basic1.cpp
|
||||
State Encapsulation: Each game owns its state completely
|
||||
Polymorphism: Use Game* pointer for runtime flexibility
|
||||
Event-Driven: Games respond to InputEvent objects only
|
||||
Reactive Rendering: Only redraw when update() returns true
|
||||
Dual-Core Efficiency: Core 0 handles logic, Core 1 handles display refresh
|
||||
Reference in New Issue
Block a user