1a1e391a14
- Document SfxEngine audio mapping - Document 4.5x ball speed, 17.5 FPS after direct FB font - Document Pico API shim (renderer, game, INPUT) and 17 games portability - Tested Pong runs with no Lua errors
73 lines
4.5 KiB
Markdown
73 lines
4.5 KiB
Markdown
# 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)
|