# LuaGame - Lua Interpreter Game Engine External ELF app that runs Lua games on Tactility OS (ES3C35P 320x480 tested on 192.168.68.107). ## How it works - Embeds Lua 5.4.7 source (no external dependency, avoids missing symbol issues) - Lua init + game loop run in dedicated 16K stack FreeRTOS task to avoid GUI task (4096 bytes) stack overflow - Game framebuffer: 240x240 RGB565 in PSRAM, rendered via LVGL canvas (`lv_canvas_set_buffer` + `lv_obj_invalidate` with `tt_lvgl_lock`) - Direct framebuffer text using 8x8 bitmap font (`font8x8.h`) – 17+ FPS vs 15 FPS with LVGL labels - **Sys API** (original Tactility breakout.lua): - `sys.log(msg)` - `sys.clear(hexColor)` - `sys.print(x,y,text,hexColor)` – direct FB via `draw_text8` - `sys.rect(x,y,w,h,hexColor,filled)` – border or filled - `sys.circle(x,y,r,hexColor,filled)` – midpoint + filled scan - `sys.line(x0,y0,x1,y1,hexColor)` - `sys.touch() -> pressed, tx, ty` (touch mapped to 240 game space) - `sys.tone(note, duration, waveform, volume)` → SfxEngine `playNote` - `sys.sfx(name)` → SfxEngine `play(SfxId)` mapping: confirm, coin, hurt, gameover, levelup, brickhit, etc. - **Pico API** compatibility (from `/Users/adolforeyna/Projects/pico-bare-metal/Adolfo/basic1/games/lua_examples`): - `game.width()`, `height()`, `set_frame_updates(bool)`, `exit()`, `game.vars` persistent table - `renderer.clear(white)`, `pixel(x,y,on)`, `line(x0,y0,x1,y1,on,width)`, `rect(x,y,w,h,on,filled)`, `circle(x,y,r,on,filled)`, `triangle(x0,y0,x1,y1,x2,y2,on,filled)`, `text(x,y,txt,on)`, `text_scaled(x,y,txt,on,scale)` (scale 1-4) - `INPUT` constants: `NONE=0, TOUCH_DOWN=1, TOUCH_MOVE=2, TOUCH_UP=3, BUTTON_0=4, BUTTON_1=5, FRAME_TICK=6, GESTURE=7` - Event system: generates `TOUCH_DOWN/MOVE/UP` from touch state + `FRAME_TICK` every frame, calls `update(event)` returning bool redraw - Detection: if source contains `renderer.` → Pico mode, else sys mode - Embedded games: - `embedded_breakout_lua_src` – fast breakout (ball 4.5 vs 2, paddle 0.25 spin) – default - `pico_games.h` auto-generated with 17 games: 2048, air_hockey, asteroids, ball, breakout, counter, flappy_bird, lunar_lander, memory_match, pacman, pong, simon_says, snake, solitaire, tetris, tic_tac_toe – tested Pong runs at 17.5 FPS - File loading: PSRAM buffer + `luaL_loadbuffer` to avoid `luaL_loadfile` stack issues, supports SD paths `/sdcard/lua/*.lua` ## Symbol fixes Previous missing: `clearerr`, `clock`, `getenv`, `gmtime`, `setlocale`, `setvbuf`, `tmpfile`, `tmpnam`, `ungetc`, `lv_canvas_get_draw_buf`, `lv_draw_buf_invalidate_cache`, `lv_image_cache_drop`. Fixed by local stubs + avoiding unexported APIs, only `lv_canvas_create`, `lv_canvas_set_buffer`, `lv_obj_invalidate`, `tt_lvgl_lock/unlock`. ## Performance - Ball speed: 2 → 4.5 (2.25x faster), configurable in embedded string - FPS: 15 → 17.5 FPS after direct FB text + dedicated game loop task - Memory: internal low ~2-3KB (PSRAM used for FB and Lua heap), stable, no crash 20s+ ## Build / Install ```bash cd /Users/adolforeyna/Projects/Tactility/apps unset PYTHONPATH; unset PYTHONHOME export IDF_PYTHON_ENV_PATH=/Users/adolforeyna/.espressif/python_env/idf5.3_py3.9_env source /Users/adolforeyna/esp/esp-idf/export.sh export TACTILITY_SDK_PATH=/Users/adolforeyna/Projects/Tactility/firmware/release/TactilitySDK export ESP_IDF_VERSION=5.5 python tactility.py Apps/LuaGame build esp32s3 --local-sdk curl -X PUT http://192.168.68.107/api/apps/install -F "file=@Apps/LuaGame/build/LuaGame.app" curl -X POST "http://192.168.68.107/api/apps/run?id=one.tactility.luagame" ``` ## Porting Pico Games Yes – all 17 examples from `pico-bare-metal/Adolfo/basic1/games/lua_examples` use: - `game.vars` state machine - `renderer.*` monochrome API (boolean on/off → mapped to white/black RGB565) - `INPUT.TOUCH_*` + `FRAME_TICK` Our engine now implements compatibility shim in C (see `l_renderer_*`, `l_game_*`, INPUT table). Pong tested: ``` [LuaGame] using Pico test game: Pong (7538 bytes) Pong initialized FPS 17.5 ``` Other games (snake, tetris, 2048, etc.) should work same – they are ~50-880 lines, no file I/O, pure math/table. To add selector UI, list `pico_games[]` via LVGL list and load selected `src`. ## TODO - Game selector UI (menu_wrapper + game_wrapper, hide/show) - Copy pico examples to SD via USB MSC or bundle selector - Audio mapping for Pico games (currently sys.sfx only, could map to renderer events) - Scale canvas to full 320x480 or dynamic `game.width/height` - Fix internal memory low warnings (reduce SfxEngine voices or Lua heap)