feat: add Pocket Dungeon game prototype
Main / Build (BookPlayer) (push) Has been cancelled
Main / Build (Brainfuck) (push) Has been cancelled
Main / Build (Breakout) (push) Has been cancelled
Main / Build (Calculator) (push) Has been cancelled
Main / Build (Diceware) (push) Has been cancelled
Main / Build (EpubReader) (push) Has been cancelled
Main / Build (GPIO) (push) Has been cancelled
Main / Build (GraphicsDemo) (push) Has been cancelled
Main / Build (HelloWorld) (push) Has been cancelled
Main / Build (M5UnitTest) (push) Has been cancelled
Main / Build (Magic8Ball) (push) Has been cancelled
Main / Build (MediaKeys) (push) Has been cancelled
Main / Build (MystifyDemo) (push) Has been cancelled
Main / Build (SerialConsole) (push) Has been cancelled
Main / Build (Snake) (push) Has been cancelled
Main / Build (TamaTac) (push) Has been cancelled
Main / Build (TodoList) (push) Has been cancelled
Main / Build (TwoEleven) (push) Has been cancelled
Main / Bundle (push) Has been cancelled

This commit is contained in:
aeroreyna
2026-07-16 22:31:55 -04:00
parent 214287193e
commit d976595879
23 changed files with 862 additions and 0 deletions
@@ -0,0 +1,97 @@
#include "PocketDungeon.h"
#include <tt_lvgl_toolbar.h>
namespace PocketDungeon {
static constexpr uint32_t TICK_MS = 200;
static constexpr const char* PREF_BEST_FLOOR = "bestFloor";
static constexpr const char* PREF_BEST_GOLD = "bestGold";
void PocketDungeon::onShow(AppHandle app, lv_obj_t* parent) {
lv_obj_remove_flag(parent, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_style_pad_all(parent, 0, LV_PART_MAIN);
root = parent;
(void) tt_lvgl_toolbar_create_for_app(parent, app);
model.setBests(static_cast<uint16_t>(prefs.getInt(PREF_BEST_FLOOR, 1)), static_cast<uint16_t>(prefs.getInt(PREF_BEST_GOLD, 0)));
model.reset(lv_tick_get());
if (sfx == nullptr) {
sfx = new SfxEngine();
if (sfx->start()) sfx->applyVolumePreset(SfxEngine::VolumePreset::Quiet);
}
onEnter(parent);
loop.start(TICK_MS, this);
}
void PocketDungeon::onHide(AppHandle app) {
(void) app;
loop.stop();
onExit();
saveBests();
if (sfx != nullptr) {
sfx->stop();
delete sfx;
sfx = nullptr;
}
root = nullptr;
}
void PocketDungeon::onEnter(lv_obj_t* sceneRoot) {
renderer.create(sceneRoot);
GameKit::attachInput(sceneRoot, this);
lastResult = MoveResult::None;
render();
}
void PocketDungeon::onExit() {}
void PocketDungeon::onInput(const GameKit::InputEvent& input) {
int dx = 0;
int dy = 0;
switch (input.kind) {
case GameKit::InputKind::Up: dy = -1; break;
case GameKit::InputKind::Down: dy = 1; break;
case GameKit::InputKind::Left: dx = -1; break;
case GameKit::InputKind::Right: dx = 1; break;
default: break;
}
if (model.getState().gameOver) {
model.reset(lv_tick_get());
lastResult = MoveResult::None;
render();
return;
}
if (dx != 0 || dy != 0) {
lastResult = model.movePlayer(dx, dy);
playResultSound(lastResult);
if (lastResult == MoveResult::Dead) saveBests();
render();
}
}
void PocketDungeon::onTick(const GameKit::Tick& tick) {
(void) tick;
}
void PocketDungeon::render() {
renderer.render(model, lastResult);
}
void PocketDungeon::saveBests() {
prefs.putInt(PREF_BEST_FLOOR, model.getBestFloor());
prefs.putInt(PREF_BEST_GOLD, model.getBestGold());
}
void PocketDungeon::playResultSound(MoveResult result) {
if (sfx == nullptr) return;
switch (result) {
case MoveResult::Attacked: sfx->play(SfxId::Hurt); break;
case MoveResult::Treasure: sfx->play(SfxId::Coin); break;
case MoveResult::Stairs: sfx->play(SfxId::Warp); break;
case MoveResult::Dead: sfx->play(SfxId::GameOver); break;
case MoveResult::Moved: sfx->play(SfxId::Blip); break;
case MoveResult::Blocked: sfx->play(SfxId::Error); break;
default: break;
}
}
} // namespace PocketDungeon