docs(LuaGame): update README with audio, FPS 17.5, Pico compatibility
- 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
This commit is contained in:
+45
-28
@@ -4,30 +4,38 @@ External ELF app that runs Lua games on Tactility OS (ES3C35P 320x480 tested on
|
|||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
- Embeds Lua 5.4.7 source (no external dependency, avoids missing symbol issues)
|
- Embeds Lua 5.4.7 source (no external dependency, avoids missing symbol issues)
|
||||||
- Lua init runs in dedicated 16K stack FreeRTOS task to avoid GUI task (4096 bytes) stack overflow
|
- 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
|
- Game framebuffer: 240x240 RGB565 in PSRAM, rendered via LVGL canvas (`lv_canvas_set_buffer` + `lv_obj_invalidate` with `tt_lvgl_lock`)
|
||||||
- Sys API (as used in breakout.lua):
|
- 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.log(msg)`
|
||||||
- `sys.clear(hexColor)`
|
- `sys.clear(hexColor)`
|
||||||
- `sys.print(x,y,text,hexColor)` - uses LVGL labels overlay
|
- `sys.print(x,y,text,hexColor)` – direct FB via `draw_text8`
|
||||||
- `sys.rect(x,y,w,h,hexColor,filled)`
|
- `sys.rect(x,y,w,h,hexColor,filled)` – border or filled
|
||||||
- `sys.circle(x,y,r,hexColor,filled)`
|
- `sys.circle(x,y,r,hexColor,filled)` – midpoint + filled scan
|
||||||
- `sys.line(x0,y0,x1,y1,hexColor)`
|
- `sys.line(x0,y0,x1,y1,hexColor)`
|
||||||
- `sys.touch() -> pressed, tx, ty` (touch coords mapped to 240 game space)
|
- `sys.touch() -> pressed, tx, ty` (touch mapped to 240 game space)
|
||||||
- `sys.tone`, `sys.sfx` stubs (logs)
|
- `sys.tone(note, duration, waveform, volume)` → SfxEngine `playNote`
|
||||||
- Embedded breakout.lua as fallback, but tries to load from SD in order:
|
- `sys.sfx(name)` → SfxEngine `play(SfxId)` mapping: confirm, coin, hurt, gameover, levelup, brickhit, etc.
|
||||||
- `/sdcard/lua/breakout.lua`
|
- **Pico API** compatibility (from `/Users/adolforeyna/Projects/pico-bare-metal/Adolfo/basic1/games/lua_examples`):
|
||||||
- `/sdcard/lua/game.lua`
|
- `game.width()`, `height()`, `set_frame_updates(bool)`, `exit()`, `game.vars` persistent table
|
||||||
- `/data/lua/breakout.lua`
|
- `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)
|
||||||
- `/sdcard/breakout.lua`
|
- `INPUT` constants: `NONE=0, TOUCH_DOWN=1, TOUCH_MOVE=2, TOUCH_UP=3, BUTTON_0=4, BUTTON_1=5, FRAME_TICK=6, GESTURE=7`
|
||||||
- File loading uses PSRAM buffer + `luaL_loadbuffer` to avoid `luaL_loadfile` stack issues.
|
- 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
|
## Symbol fixes
|
||||||
Previous attempts hit missing symbols: `clearerr`, `clock`, `getenv`, `gmtime`, `setlocale`, `setvbuf`, `tmpfile`, `tmpnam`, `ungetc`, plus LVGL `lv_canvas_get_draw_buf`, `lv_draw_buf_invalidate_cache`, `lv_image_cache_drop`.
|
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:
|
Fixed by local stubs + avoiding unexported APIs, only `lv_canvas_create`, `lv_canvas_set_buffer`, `lv_obj_invalidate`, `tt_lvgl_lock/unlock`.
|
||||||
- Providing local stubs for missing libc functions
|
|
||||||
- Removing use of unexported LVGL cache APIs, using only `lv_canvas_create`, `lv_canvas_set_buffer`, `lv_obj_invalidate`
|
## Performance
|
||||||
- Verifying with `verify_symbols.py` - 0 missing.
|
- 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
|
## Build / Install
|
||||||
```bash
|
```bash
|
||||||
@@ -42,14 +50,23 @@ curl -X PUT http://192.168.68.107/api/apps/install -F "file=@Apps/LuaGame/build/
|
|||||||
curl -X POST "http://192.168.68.107/api/apps/run?id=one.tactility.luagame"
|
curl -X POST "http://192.168.68.107/api/apps/run?id=one.tactility.luagame"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Testing
|
## Porting Pico Games
|
||||||
- Serial logs: `/dev/cu.usbmodem1101` 115200
|
Yes – all 17 examples from `pico-bare-metal/Adolfo/basic1/games/lua_examples` use:
|
||||||
- Screenshot: `curl -s http://192.168.68.107/api/screenshot -o /tmp/fb.png`
|
- `game.vars` state machine
|
||||||
- Current status: boots, loads `/sdcard/lua/breakout.lua` (5207 bytes), no stack overflow, renders bricks/ball/paddle, handles float coords for `circle`.
|
- `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
|
## TODO
|
||||||
- Implement proper game selection UI for `/sdcard/lua/` directory
|
- Game selector UI (menu_wrapper + game_wrapper, hide/show)
|
||||||
- Map touch to paddle correctly (currently uses canvas coords)
|
- Copy pico examples to SD via USB MSC or bundle selector
|
||||||
- Implement audio via SfxEngine
|
- Audio mapping for Pico games (currently sys.sfx only, could map to renderer events)
|
||||||
- Scale canvas to full display or allow dynamic resolution via `sys.width/height`
|
- Scale canvas to full 320x480 or dynamic `game.width/height`
|
||||||
- Add file browser in-app
|
- Fix internal memory low warnings (reduce SfxEngine voices or Lua heap)
|
||||||
|
|||||||
Reference in New Issue
Block a user