refactored to multiple games implementation

This commit is contained in:
Adolfo Reyna
2026-01-30 21:33:42 -05:00
parent d81d547983
commit 2a6861fdf5
11 changed files with 1216 additions and 539 deletions

82
lib/game.h Normal file
View File

@@ -0,0 +1,82 @@
// ============================================================================
// ABSTRACT GAME BASE CLASS
// ============================================================================
// Defines the interface all games must implement
// Provides polymorphic game architecture for modular design
#ifndef GAME_H
#define GAME_H
#include <stdint.h>
#include "input_event.h"
#include "display/low_level_render.h"
#include "display/low_level_gui.h"
/**
* @brief Abstract base class for all games
*
* Games inherit from this class and implement the three core methods:
* - init(): Set up initial game state
* - update(): Process input events and update game logic
* - draw(): Render the game to the display buffer
*
* The main loop in basic1.cpp calls these methods polymorphically,
* allowing different games to run with the same infrastructure.
*/
class Game {
public:
/**
* @brief Construct a new Game
* @param width Display width in pixels
* @param height Display height in pixels
* @param renderer Pointer to low-level rendering interface
* @param gui Pointer to GUI drawing primitives
*/
Game(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui)
: width(width), height(height), renderer(renderer), gui(gui) {
}
/**
* @brief Virtual destructor for proper cleanup of derived classes
*/
virtual ~Game() {}
/**
* @brief Initialize game state
*
* Called once when the game starts. Set up initial values,
* reset statistics, prepare the game board, etc.
*/
virtual void init() = 0;
/**
* @brief Update game state based on input event
*
* Process the input event and update game logic accordingly.
* This is where game rules, win conditions, state transitions happen.
*
* @param event Input event from InputManager
* @return true if screen redraw is needed, false otherwise
*/
virtual bool update(const InputEvent& event) = 0;
/**
* @brief Draw the game to the display buffer
*
* Render all game graphics using the renderer and gui objects.
* This is called after update() returns true.
* The actual screen refresh happens in the main loop on Core 1.
*/
virtual void draw() = 0;
protected:
// Display dimensions
uint16_t width;
uint16_t height;
// Rendering interfaces (provided by basic1.cpp)
LowLevelRenderer* renderer;
LowLevelGUI* gui;
};
#endif // GAME_H

34
lib/input_event.h Normal file
View File

@@ -0,0 +1,34 @@
// ============================================================================
// INPUT EVENT HEADER
// ============================================================================
// Shared input event structures used by InputManager and Game classes
// Extracted from basic1.cpp for modular game architecture
#ifndef INPUT_EVENT_H
#define INPUT_EVENT_H
#include <stdint.h>
// Input event types
enum InputType {
INPUT_NONE = 0,
INPUT_TOUCH_DOWN,
INPUT_TOUCH_MOVE,
INPUT_TOUCH_UP,
INPUT_BUTTON_0,
INPUT_BUTTON_1,
INPUT_GESTURE
};
// Unified input event structure
struct InputEvent {
InputType type;
int16_t x;
int16_t y;
uint8_t gesture_code; // For gesture events
uint8_t button_id; // For button events
uint8_t pressure; // Touch pressure/weight
bool valid; // Set to true if event is valid
};
#endif // INPUT_EVENT_H

154
lib/input_manager.cpp Normal file
View File

@@ -0,0 +1,154 @@
// ============================================================================
// INPUT MANAGER IMPLEMENTATION
// ============================================================================
// Processes touch and button inputs into InputEvent objects
#include "input_manager.h"
#include "pico/stdlib.h"
#include "board_config.h"
#include <stdio.h>
// External interrupt flags from basic1.cpp
extern volatile bool touch_interrupt_flag;
extern volatile bool touch_event_down;
extern volatile bool button_key0_pressed;
extern volatile bool button_key1_pressed;
// GameConfig struct definition (matches basic1.cpp)
struct GameConfig {
uint32_t touch_debounce_ms;
uint32_t button_debounce_ms;
bool enable_gestures;
bool enable_continuous_draw;
bool debug_verbose;
};
InputManager::InputManager(LowLevelTouch* touch, const GameConfig* config)
: touch(touch), config(config) {
}
InputEvent InputManager::process_touch_input(uint32_t* last_time) {
InputEvent event = {INPUT_NONE, 0, 0, 0, 0, 0, false};
// Check if touch interrupt flag is set
if (!touch_interrupt_flag) {
return event; // No touch event
}
printf("Processing touch: flag=%d, event_down=%d\n", touch_interrupt_flag, touch_event_down);
// Don't clear the flag yet - we may still be processing continuous touch
// Check if touch is active
if (!touch_event_down) {
// Touch released - reset timing for next touch
touch_interrupt_flag = false;
*last_time = 0; // Reset so next touch is treated as new touch-down
event.type = INPUT_TOUCH_UP;
event.valid = true;
printf("Touch UP\n");
return event;
}
// Touch is down - check debounce timing
uint32_t now = to_ms_since_boot(get_absolute_time());
if (now - *last_time < config->touch_debounce_ms) {
return event; // Too soon, skip
}
// Read touch data
TouchData touch_data;
if (!touch || !touch->read_touch(&touch_data)) {
// Clear flag even if read failed to prevent getting stuck
touch_interrupt_flag = false;
printf("Touch read FAILED\n");
return event; // Read failed
}
// Clear the interrupt flag after successfully reading touch data
// This allows the next touch interrupt to be detected
touch_interrupt_flag = false;
printf("Touch DOWN at (%d,%d)\n", touch_data.points[0].x, touch_data.points[0].y);
// Populate event structure
event.x = touch_data.points[0].x;
event.y = touch_data.points[0].y;
event.pressure = touch_data.points[0].pressure;
event.gesture_code = touch_data.gesture;
event.valid = true;
// Determine event type
if (*last_time == 0) {
event.type = INPUT_TOUCH_DOWN;
} else {
event.type = INPUT_TOUCH_MOVE;
}
// Handle gesture events
if (config->enable_gestures && touch_data.gesture != 0) {
event.type = INPUT_GESTURE;
if (config->debug_verbose) {
printf("Gesture: 0x%02X (%s)\n", event.gesture_code, get_gesture_name(event.gesture_code));
}
}
*last_time = now;
return event;
}
InputEvent InputManager::process_button_input() {
InputEvent event = {INPUT_NONE, 0, 0, 0, 0, 0, false};
#ifdef BUTTON_KEY0_PIN
// Check KEY0
if (button_key0_pressed) {
button_key0_pressed = false;
sleep_ms(config->button_debounce_ms);
if (gpio_get(BUTTON_KEY0_PIN) == 0) { // Verify still pressed
event.type = INPUT_BUTTON_0;
event.button_id = 0;
event.valid = true;
if (config->debug_verbose) {
printf("Button KEY0 action triggered\n");
}
return event;
}
}
#ifdef BUTTON_KEY1_PIN
// Check KEY1
if (button_key1_pressed) {
button_key1_pressed = false;
sleep_ms(config->button_debounce_ms);
if (gpio_get(BUTTON_KEY1_PIN) == 0) { // Verify still pressed
event.type = INPUT_BUTTON_1;
event.button_id = 1;
event.valid = true;
if (config->debug_verbose) {
printf("Button KEY1 action triggered\n");
}
return event;
}
}
#endif
#endif
return event;
}
const char* InputManager::get_gesture_name(uint8_t gesture_code) {
switch(gesture_code) {
case 0x10: return "Move Up";
case 0x14: return "Move Right";
case 0x18: return "Move Down";
case 0x1C: return "Move Left";
case 0x48: return "Zoom In";
case 0x49: return "Zoom Out";
default: return "Unknown";
}
}

64
lib/input_manager.h Normal file
View File

@@ -0,0 +1,64 @@
// ============================================================================
// INPUT MANAGER HEADER
// ============================================================================
// Handles all input processing and debouncing for touch and button inputs
// Converts hardware events into InputEvent objects for games to consume
#ifndef INPUT_MANAGER_H
#define INPUT_MANAGER_H
#include <stdint.h>
#include "input_event.h"
#include "display/low_level_touch.h"
// Forward declaration - avoid pulling in full basic1.cpp
struct GameConfig;
/**
* @brief Input Manager - Processes touch and button inputs
*
* Responsibilities:
* - Reading touch controller data
* - Debouncing touch and button events
* - Converting raw inputs to InputEvent objects
* - Gesture recognition
*
* Does NOT handle:
* - Button GPIO initialization (stays in basic1.cpp)
* - Interrupt handler registration (stays in basic1.cpp)
*/
class InputManager {
public:
/**
* @brief Construct InputManager with hardware references
* @param touch Pointer to touch controller interface
* @param config Pointer to game configuration
*/
InputManager(LowLevelTouch* touch, const GameConfig* config);
/**
* @brief Process touch input from controller
* @param last_time Pointer to last touch timestamp for debouncing
* @return InputEvent (valid=false if no valid input)
*/
InputEvent process_touch_input(uint32_t* last_time);
/**
* @brief Process button input from GPIO flags
* @return InputEvent (valid=false if no valid input)
*/
InputEvent process_button_input();
/**
* @brief Get human-readable gesture name
* @param gesture_code Gesture code from touch controller
* @return Constant string with gesture name
*/
static const char* get_gesture_name(uint8_t gesture_code);
private:
LowLevelTouch* touch;
const GameConfig* config;
};
#endif // INPUT_MANAGER_H