#include "Game.h" #include #include #include namespace { const char *DocumentPathFor(GameState state) { switch (state) { case START_MENU: return "assets/main-menu.rml"; case PAUSE_MENU: return "assets/pause-menu.rml"; case STATS_MENU: return "assets/stats-menu.rml"; case OPTIONS_MENU: return "assets/options-menu.rml"; case IN_GAME: return "assets/game-ui.rml"; } return nullptr; } bool IsMenuState(GameState state) { return state == OPTIONS_MENU || state == STATS_MENU; } } // namespace bool Game::Init(Rml::Context *context) { if (!context) return false; ctx = context; return true; } bool Game::SetupRmlDataBinding(Rml::DataModelHandle &model_handle) { Rml::DataModelConstructor dmc = ctx->CreateDataModel("game_data"); if (!dmc) { TraceLog(LOG_ERROR, "Failed to construct data model."); return false; } // ---------- Member bindings ---------- dmc.Bind("game_state", &game_data.game_state); // ---------- Event callback bindings ---------- dmc.BindEventCallback("start_game", [this](Rml::DataModelHandle, Rml::Event &, const Rml::VariantList &) { TrySetGameState(IN_GAME); }); dmc.BindEventCallback("pause_game", [this](Rml::DataModelHandle, Rml::Event &, const Rml::VariantList &) { TrySetGameState(PAUSE_MENU); }); dmc.BindEventCallback( "unpause_game", [this](Rml::DataModelHandle, Rml::Event &, const Rml::VariantList &) { TrySetGameState(IN_GAME); }); dmc.BindEventCallback( "open_options_menu", [this](Rml::DataModelHandle, Rml::Event &, const Rml::VariantList &) { TrySetGameState(OPTIONS_MENU); }); dmc.BindEventCallback( "end_current_game", [this](Rml::DataModelHandle, Rml::Event &, const Rml::VariantList &) { TrySetGameState(START_MENU); }); dmc.BindEventCallback("go_back", [this](Rml::DataModelHandle, Rml::Event &, const Rml::VariantList &) { GoBack(); }); model_handle = dmc.GetModelHandle(); return true; } Rml::ElementDocument *Game::LoadOrGetDocument(GameState state) { if (auto it = documents.find(state); it != documents.end()) return it->second; const char *path = DocumentPathFor(state); if (!path) return nullptr; Rml::ElementDocument *doc = ctx->LoadDocument(path); if (!doc) { TraceLog(LOG_ERROR, "Failed to load document: %s", path); return nullptr; } documents[state] = doc; return doc; } void Game::ShowDocumentForState(GameState state) { if (activeDocument) { activeDocument->Hide(); activeDocument = nullptr; } if (Rml::ElementDocument *doc = LoadOrGetDocument(state)) { doc->Show(); activeDocument = doc; } } void Game::TrySetGameState(GameState newState) { GameState currentState = CurrentState(); if (IsMenuState(newState) && !IsMenuState(currentState)) { previousState = currentState; } switch (newState) { case START_MENU: if (currentState == IN_GAME) ResetGame(); break; case IN_GAME: if (currentState == START_MENU) StartNewGame(); break; default: break; } game_data.game_state = newState; ShowDocumentForState(newState); } void Game::GoBack() { if (IsMenuState(CurrentState())) { TrySetGameState(previousState); } } void Game::StartNewGame() { // TODO // --- placeholder testing stuff --- playerPos = {GetScreenWidth() / 2.0f, GetScreenHeight() / 2.0f}; } void Game::ResetGame() { // TODO } void Game::Update() { HandleInput(); if (CurrentState() != IN_GAME) return; // TODO // --- placeholder testing stuff --- float dt = GetFrameTime(); if (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP)) playerPos.y -= playerSpeed * dt; if (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN)) playerPos.y += playerSpeed * dt; if (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT)) playerPos.x -= playerSpeed * dt; if (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT)) playerPos.x += playerSpeed * dt; } void Game::Draw2D() { if (CurrentState() != IN_GAME) return; // TODO // --- placeholder testing stuff --- // DrawText("Hello from raylib!", 50, 50, 20, RAYWHITE); if (CurrentState() != IN_GAME) return; DrawCircleV(playerPos, 24.0f, BLUE); DrawText("WASD/Arrows to move, ESC to pause", 20, 20, 20, RAYWHITE); } void Game::HandleInput() { if (!IsKeyReleased(KEY_ESCAPE)) return; switch (CurrentState()) { case IN_GAME: TrySetGameState(PAUSE_MENU); break; case PAUSE_MENU: TrySetGameState(IN_GAME); break; case OPTIONS_MENU: case STATS_MENU: GoBack(); break; default: break; } }