- Integrated Lua 5.4 engine (32-bit mode for embedded ARM) - Created LuaGame wrapper class implementing Game interface - Added C++ bindings exposing renderer, game state, and input to Lua - Implemented SD card loader for automatic .lua game discovery - Updated GameLauncher to support std::function for lambda captures - Made Game class members public for Lua bindings access - Added example Lua games: counter, snake, bouncing ball - Included comprehensive API documentation Games can now be written as .lua text files on SD card and loaded without recompilation. Build size: 747KB UF2, Lua VM uses ~50-80KB RAM.
132 lines
4.6 KiB
C++
132 lines
4.6 KiB
C++
// ============================================================================
|
|
// GAME LAUNCHER IMPLEMENTATION
|
|
// ============================================================================
|
|
// Menu system for selecting and launching games
|
|
|
|
#include "game_launcher.h"
|
|
#include "input_manager.h"
|
|
#include "display/low_level_render.h"
|
|
#include "display/low_level_gui.h"
|
|
#include <stdio.h>
|
|
|
|
GameLauncher::GameLauncher(uint16_t width, uint16_t height,
|
|
LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager)
|
|
: width(width), height(height), renderer(renderer), gui(gui), input_manager(input_manager),
|
|
selected_index(0), selected_game(nullptr) {
|
|
}
|
|
|
|
void GameLauncher::register_game(const char* name, const char* description,
|
|
std::function<Game*(uint16_t, uint16_t, LowLevelRenderer*, LowLevelGUI*, InputManager*)> factory) {
|
|
GameEntry entry;
|
|
entry.name = name;
|
|
entry.description = description;
|
|
entry.factory = factory;
|
|
games.push_back(entry);
|
|
|
|
printf("Registered game: %s - %s\n", name, description);
|
|
}
|
|
|
|
void GameLauncher::draw() {
|
|
// Draw main window
|
|
LowLevelWindow* window = gui->draw_new_window(10, 10, width - 20, height - 20, "Game Launcher");
|
|
|
|
renderer->set_font(&font_5x5_obj);
|
|
|
|
// Draw title
|
|
renderer->draw_string_scaled(30, 40, "Select a Game:", 2);
|
|
|
|
// Draw game list with GUI buttons
|
|
for (size_t i = 0; i < games.size(); i++) {
|
|
int y = MENU_Y_START + (i * MENU_ITEM_HEIGHT);
|
|
|
|
// Draw button (pressed/highlighted if selected)
|
|
bool is_selected = ((int)i == selected_index);
|
|
gui->draw_button(window, 20, y, games[i].name, is_selected, true);
|
|
|
|
// Draw description below button
|
|
renderer->set_font(&font_5x5_obj); // Restore small font for description
|
|
renderer->set_text_color(true); // Normal text color
|
|
renderer->draw_string_scaled(50, y + 36, games[i].description, 1);
|
|
}
|
|
|
|
// Draw instructions at bottom
|
|
const char* instructions;
|
|
if (input_manager->has_buttons()) {
|
|
instructions = "Touch game or use KEY0/KEY1";
|
|
} else {
|
|
instructions = "Touch game to play";
|
|
}
|
|
renderer->set_font(&font_5x5_obj);
|
|
renderer->draw_string_scaled(30, height - 35, instructions, 2);
|
|
}
|
|
|
|
bool GameLauncher::update(const InputEvent& event) {
|
|
bool needs_refresh = false;
|
|
|
|
switch (event.type) {
|
|
case INPUT_TOUCH_DOWN: {
|
|
printf("Touch at (%d,%d) in launcher\n", event.x, event.y);
|
|
|
|
// Check if touch is on a game entry
|
|
for (size_t i = 0; i < games.size(); i++) {
|
|
int y = MENU_Y_START + (i * MENU_ITEM_HEIGHT);
|
|
|
|
// Touch area is the entire menu item
|
|
if (event.y >= y - 5 && event.y < y + MENU_ITEM_HEIGHT - 5) {
|
|
// Game selected - create instance
|
|
printf("Selected game: %s\n", games[i].name);
|
|
selected_game = games[i].factory(width, height, renderer, gui, input_manager);
|
|
if (selected_game) {
|
|
selected_game->init();
|
|
return true; // Signal game selected
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case INPUT_BUTTON_0: {
|
|
// Navigate menu
|
|
if (games.size() > 0) {
|
|
selected_index = (selected_index + 1) % games.size();
|
|
needs_refresh = true;
|
|
printf("Menu selection: %d (%s)\n", selected_index, games[selected_index].name);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case INPUT_BUTTON_1: {
|
|
// Select current game
|
|
if (selected_index >= 0 && selected_index < (int)games.size()) {
|
|
printf("Selected game: %s\n", games[selected_index].name);
|
|
selected_game = games[selected_index].factory(width, height, renderer, gui, input_manager);
|
|
if (selected_game) {
|
|
selected_game->init();
|
|
return true; // Signal game selected
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return needs_refresh;
|
|
}
|
|
|
|
Game* GameLauncher::get_selected_game() {
|
|
return selected_game;
|
|
}
|
|
|
|
void GameLauncher::reset() {
|
|
// Clean up current game if any
|
|
if (selected_game) {
|
|
delete selected_game;
|
|
selected_game = nullptr;
|
|
}
|
|
selected_index = 0;
|
|
printf("Launcher reset - returning to menu\n");
|
|
}
|