Add Lua scripting support to desktop emulator

- Created emulator-specific lua_game_emulator.cpp using filesystem instead of FatFS
- Created lua_game_loader_emulator.cpp to scan games/lua_examples directory
- Updated CMakeLists.txt to include Lua 5.4 engine and bindings
- Updated to SFML 3.0 API compatibility (event handling, sprite initialization)
- Updated Game class to use public members for Lua bindings
- Updated GameLauncher to use std::function for lambda captures
- Added continuous 60 FPS rendering for smooth display
- Emulator now loads and runs all three example Lua games
This commit is contained in:
Adolfo Reyna
2026-02-07 12:14:33 -05:00
parent e6e4eca188
commit 285dffc32e
10 changed files with 447 additions and 51 deletions

View File

@@ -2,10 +2,11 @@
#include "low_level_display_sfml.h"
#include "../display/low_level_render.h"
#include "../display/low_level_gui.h"
#include "game_launcher.h"
#include "../lib/game_launcher.h"
#include "../games/demo_game.h"
#include "../games/tic_tac_toe.h"
#include "../games/monopoly/monopoly_game.h"
#include "../games/lua_game_loader.h"
#include "input_manager.h"
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
@@ -34,6 +35,11 @@ int main() {
// Create GameLauncher
GameLauncher launcher(WIDTH, HEIGHT, &renderer, &gui, &input_manager);
// Register Lua games from lua_examples directory
LuaGameLoader::register_all_games(&launcher);
// Register built-in C++ games
launcher.register_game("Tic-Tac-Toe", "Classic 2-player game",
[](uint16_t w, uint16_t h, LowLevelRenderer* r, LowLevelGUI* g, InputManager* im) -> Game* {
return new TicTacToeGame(w, h, r, g, im);
@@ -54,15 +60,15 @@ int main() {
while (display.isOpen() && running) {
// Handle SFML events and translate to InputEvent
InputEvent event = {INPUT_NONE, 0, 0, 0, 0, 0, false};
sf::Event sfEvent;
while (display.pollEvent(sfEvent)) {
if (sfEvent.type == sf::Event::Closed) {
while (const auto sfEvent = display.pollEvent()) {
if (const auto* closed = sfEvent->getIf<sf::Event::Closed>()) {
display.close();
running = false;
} else if (sfEvent.type == sf::Event::MouseButtonPressed) {
} else if (const auto* mousePressed = sfEvent->getIf<sf::Event::MouseButtonPressed>()) {
event.type = INPUT_TOUCH_DOWN;
event.x = sfEvent.mouseButton.x;
event.y = sfEvent.mouseButton.y;
event.x = mousePressed->position.x;
event.y = mousePressed->position.y;
event.valid = true;
// Check for virtual buttons
@@ -70,14 +76,14 @@ int main() {
if (input_manager.check_virtual_buttons(event.x, event.y, virtual_type)) {
event.type = virtual_type;
}
} else if (sfEvent.type == sf::Event::KeyPressed) {
if (sfEvent.key.code == sf::Keyboard::Space) {
} else if (const auto* keyPressed = sfEvent->getIf<sf::Event::KeyPressed>()) {
if (keyPressed->code == sf::Keyboard::Key::Space) {
event.type = INPUT_BUTTON_0;
event.valid = true;
} else if (sfEvent.key.code == sf::Keyboard::Enter) {
} else if (keyPressed->code == sf::Keyboard::Key::Enter) {
event.type = INPUT_BUTTON_1;
event.valid = true;
} else if (sfEvent.key.code == sf::Keyboard::Escape) {
} else if (keyPressed->code == sf::Keyboard::Key::Escape) {
// Simulate long-press exit
if (launcher.is_game_selected()) {
launcher.reset();
@@ -103,18 +109,19 @@ int main() {
}
}
if (needs_redraw) {
renderer.clear_buffer();
if (launcher.is_game_selected()) {
current_game = launcher.get_selected_game();
current_game->draw();
} else {
launcher.draw();
}
display.draw_buffer(framebuffer.data());
display.refresh();
needs_redraw = false;
// Always redraw every frame for emulator
renderer.clear_buffer();
if (launcher.is_game_selected()) {
current_game = launcher.get_selected_game();
current_game->draw();
} else {
launcher.draw();
}
display.draw_buffer(framebuffer.data());
display.refresh();
// Small delay to prevent busy-waiting (60 FPS)
sf::sleep(sf::milliseconds(16));
}
return 0;
}