refactored to multiple games implementation
This commit is contained in:
82
lib/game.h
Normal file
82
lib/game.h
Normal 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
34
lib/input_event.h
Normal 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
154
lib/input_manager.cpp
Normal 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
64
lib/input_manager.h
Normal 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
|
||||
Reference in New Issue
Block a user