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
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:
@@ -0,0 +1,116 @@
|
||||
#include "DungeonRenderer.h"
|
||||
#include <cstdio>
|
||||
|
||||
namespace PocketDungeon {
|
||||
|
||||
static constexpr uint32_t COLOR_BG = 0x10111A;
|
||||
static constexpr uint32_t COLOR_PANEL = 0x1D2030;
|
||||
static constexpr uint32_t COLOR_FLOOR = 0xD8C7A1;
|
||||
static constexpr uint32_t COLOR_WALL = 0x5D574C;
|
||||
static constexpr uint32_t COLOR_STAIRS = 0x6D4CC2;
|
||||
static constexpr uint32_t COLOR_TREASURE = 0xD99B23;
|
||||
static constexpr uint32_t COLOR_PLAYER = 0x365CF5;
|
||||
static constexpr uint32_t COLOR_SLIME = 0x3B9D58;
|
||||
static constexpr uint32_t COLOR_BAT = 0x953B9D;
|
||||
|
||||
void DungeonRenderer::create(lv_obj_t* parent) {
|
||||
root = parent;
|
||||
lv_obj_set_style_bg_color(root, lv_color_hex(COLOR_BG), LV_PART_MAIN);
|
||||
lv_obj_remove_flag(root, LV_OBJ_FLAG_SCROLLABLE);
|
||||
status = lv_label_create(root);
|
||||
lv_obj_set_style_text_color(status, lv_color_hex(0xF2E8D0), LV_PART_MAIN);
|
||||
lv_obj_align(status, LV_ALIGN_TOP_MID, 0, 8);
|
||||
const lv_coord_t screenW = lv_display_get_horizontal_resolution(nullptr);
|
||||
const lv_coord_t screenH = lv_display_get_vertical_resolution(nullptr);
|
||||
const uint16_t maxCellW = static_cast<uint16_t>((screenW - 22) / DUNGEON_COLS);
|
||||
const uint16_t maxCellH = static_cast<uint16_t>((screenH - 70) / DUNGEON_ROWS);
|
||||
const uint16_t cell = maxCellW < maxCellH ? maxCellW : maxCellH;
|
||||
grid = GameKit::GridSpec { DUNGEON_COLS, DUNGEON_ROWS, static_cast<uint16_t>(cell > 10 ? cell : 10), 0, 0 };
|
||||
board = GameKit::makePanel(root, lv_color_hex(COLOR_PANEL), 10);
|
||||
lv_obj_set_size(board, grid.cols * grid.cellPx, grid.rows * grid.cellPx);
|
||||
lv_obj_align(board, LV_ALIGN_CENTER, 0, 8);
|
||||
for (uint8_t y = 0; y < DUNGEON_ROWS; ++y) {
|
||||
for (uint8_t x = 0; x < DUNGEON_COLS; ++x) {
|
||||
cells[y][x] = GameKit::makeCell(board, grid.cellPx - 2, lv_color_hex(COLOR_FLOOR), 4);
|
||||
GameKit::setCell(cells[y][x], x, y, grid.cellPx);
|
||||
labels[y][x] = lv_label_create(cells[y][x]);
|
||||
lv_obj_set_style_text_color(labels[y][x], lv_color_white(), LV_PART_MAIN);
|
||||
lv_obj_center(labels[y][x]);
|
||||
}
|
||||
}
|
||||
message = lv_label_create(root);
|
||||
lv_obj_set_style_text_color(message, lv_color_hex(0xB8BCD8), LV_PART_MAIN);
|
||||
lv_obj_align(message, LV_ALIGN_BOTTOM_MID, 0, -8);
|
||||
}
|
||||
|
||||
lv_color_t DungeonRenderer::tileColor(Tile tile) {
|
||||
switch (tile) {
|
||||
case Tile::Wall: return lv_color_hex(COLOR_WALL);
|
||||
case Tile::Stairs: return lv_color_hex(COLOR_STAIRS);
|
||||
case Tile::Treasure: return lv_color_hex(COLOR_TREASURE);
|
||||
case Tile::Floor:
|
||||
default: return lv_color_hex(COLOR_FLOOR);
|
||||
}
|
||||
}
|
||||
|
||||
const char* DungeonRenderer::tileText(Tile tile) {
|
||||
switch (tile) {
|
||||
case Tile::Stairs: return ">";
|
||||
case Tile::Treasure: return "$";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
lv_color_t DungeonRenderer::entityColor(EntityType type) {
|
||||
switch (type) {
|
||||
case EntityType::Player: return lv_color_hex(COLOR_PLAYER);
|
||||
case EntityType::Bat: return lv_color_hex(COLOR_BAT);
|
||||
case EntityType::Slime:
|
||||
default: return lv_color_hex(COLOR_SLIME);
|
||||
}
|
||||
}
|
||||
|
||||
void DungeonRenderer::clearEntityLabels() {
|
||||
for (uint8_t y = 0; y < DUNGEON_ROWS; ++y) {
|
||||
for (uint8_t x = 0; x < DUNGEON_COLS; ++x) {
|
||||
lv_label_set_text(labels[y][x], "");
|
||||
lv_obj_set_style_text_color(labels[y][x], lv_color_white(), LV_PART_MAIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DungeonRenderer::render(const DungeonModel& model, MoveResult lastResult) {
|
||||
const DungeonState& state = model.getState();
|
||||
char buf[96];
|
||||
std::snprintf(buf, sizeof(buf), "F%u HP:%d Gold:%u Best:%u/%u", state.floor, state.hp, state.gold, model.getBestFloor(), model.getBestGold());
|
||||
lv_label_set_text(status, buf);
|
||||
clearEntityLabels();
|
||||
for (uint8_t y = 0; y < DUNGEON_ROWS; ++y) {
|
||||
for (uint8_t x = 0; x < DUNGEON_COLS; ++x) {
|
||||
const Tile tile = state.tiles[y][x];
|
||||
lv_obj_set_style_bg_color(cells[y][x], tileColor(tile), LV_PART_MAIN);
|
||||
lv_label_set_text(labels[y][x], tileText(tile));
|
||||
}
|
||||
}
|
||||
for (uint8_t i = 0; i < state.entityCount; ++i) {
|
||||
const Entity& entity = state.entities[i];
|
||||
if (!entity.alive) continue;
|
||||
const char* symbol = entity.type == EntityType::Bat ? "b" : "s";
|
||||
lv_label_set_text(labels[entity.pos.y][entity.pos.x], symbol);
|
||||
lv_obj_set_style_text_color(labels[entity.pos.y][entity.pos.x], entityColor(entity.type), LV_PART_MAIN);
|
||||
}
|
||||
lv_label_set_text(labels[state.playerPos.y][state.playerPos.x], "@");
|
||||
lv_obj_set_style_text_color(labels[state.playerPos.y][state.playerPos.x], lv_color_hex(COLOR_PLAYER), LV_PART_MAIN);
|
||||
const char* text = "Move with arrows, swipe, or tap a direction";
|
||||
switch (lastResult) {
|
||||
case MoveResult::Blocked: text = "A wall blocks the way"; break;
|
||||
case MoveResult::Attacked: text = "You strike the monster"; break;
|
||||
case MoveResult::Treasure: text = "Treasure found!"; break;
|
||||
case MoveResult::Stairs: text = "Down the stairs..."; break;
|
||||
case MoveResult::Dead: text = "Game over - tap to restart"; break;
|
||||
default: break;
|
||||
}
|
||||
lv_label_set_text(message, text);
|
||||
}
|
||||
|
||||
} // namespace PocketDungeon
|
||||
Reference in New Issue
Block a user