ADD: Implement Basic Turnsystem with UI Update

This commit is contained in:
sebastian 2026-02-13 20:42:19 +01:00
parent 7adf0164c3
commit 1735d89eca
19 changed files with 214 additions and 14 deletions

View File

@ -162,6 +162,15 @@ add_executable(Dicewars_Siedler src/main.cpp
src/game/hexWorld/building/BuildingConfig.cpp src/game/hexWorld/building/BuildingConfig.cpp
src/game/hexWorld/building/BuildingConfig.h src/game/hexWorld/building/BuildingConfig.h
src/engine/toolbox/util.h src/engine/toolbox/util.h
src/engine/core/events/EventBus.cpp
src/engine/core/events/EventBus.h
src/game/hexWorld/events/TurnChangedEvent.cpp
src/game/hexWorld/events/TurnChangedEvent.h
src/game/hexWorld/events/ResourceCollectEvent.cpp
src/game/hexWorld/events/ResourceCollectEvent.h
src/game/hexWorld/gameplay/TurnSystem.cpp
src/game/hexWorld/gameplay/TurnSystem.h
src/game/hexWorld/gameplay/TurnState.h
) )
target_compile_options(Dicewars_Siedler PRIVATE target_compile_options(Dicewars_Siedler PRIVATE

View File

@ -8,6 +8,7 @@
#include <vector> #include <vector>
#include "Window.h" #include "Window.h"
#include "events/EventBus.h"
class Layer; class Layer;
@ -23,6 +24,7 @@ public:
static Application& getInstance(); static Application& getInstance();
[[nodiscard]] Window& getWindow() const {return *window;} [[nodiscard]] Window& getWindow() const {return *window;}
EventBus& getEventBus() {return eventBus;}
private: private:
bool running = true; bool running = true;
std::unique_ptr<Window> window; std::unique_ptr<Window> window;
@ -30,6 +32,7 @@ private:
static Application* instance; static Application* instance;
std::vector<Layer*> layers; std::vector<Layer*> layers;
EventBus eventBus;
protected: protected:
void pushLayer(Layer* layer); void pushLayer(Layer* layer);

View File

@ -0,0 +1,5 @@
//
// Created by sebastian on 13.02.26.
//
#include "EventBus.h"

View File

@ -0,0 +1,39 @@
//
// Created by sebastian on 13.02.26.
//
#ifndef DICEWARS_SIEDLER_EVENTBUS_H
#define DICEWARS_SIEDLER_EVENTBUS_H
#include <functional>
#include <oneapi/tbb/profiling.h>
class EventBus {
public:
template<typename Event>
using Handler = std::function<void(const Event&)>;
template<typename Event>
void subscribe(Handler<Event> handler) {
auto& handlers = getHandlers<Event>();
handlers.emplace_back(std::move(handler));
}
template<typename Event>
void emit(const Event& event) {
auto& handlers = getHandlers<Event>();
for (auto& h : handlers) {
h(event);
}
}
private:
template<typename Event>
std::vector<Handler<Event>>& getHandlers() {
static std::vector<Handler<Event>> handlers;
return handlers;
}
};
#endif //DICEWARS_SIEDLER_EVENTBUS_H

View File

@ -22,5 +22,9 @@ void UiText::setText(const std::string &text) {
void UiText::onCollectRenderData(UiRenderBundle& ui_render_bundle) { void UiText::onCollectRenderData(UiRenderBundle& ui_render_bundle) {
if (!visible) return; if (!visible) return;
if (this->text == "Runde: 0") {
printf("Runde: 0\n");
}
ui_render_bundle.addText(this); ui_render_bundle.addText(this);
} }

View File

@ -13,8 +13,8 @@ class Font;
class UiText : public UiComponent { class UiText : public UiComponent {
public: public:
UiText(Font& font, std::string text, LayoutStyle& style, glm::vec3 size); UiText(Font& font, std::string text, LayoutStyle& style, glm::vec3 color);
UiText(Font& font, std::string text, LayoutStyle& style); UiText(Font& font, std::string text, LayoutStyle& color);
void setText(const std::string& text); void setText(const std::string& text);
[[nodiscard]] const Font& getFont() const { return font; } [[nodiscard]] const Font& getFont() const { return font; }

View File

@ -8,10 +8,15 @@
bool InputManager::current[GLFW_MOUSE_BUTTON_LAST] = { false }; bool InputManager::current[GLFW_MOUSE_BUTTON_LAST] = { false };
bool InputManager::previous[GLFW_MOUSE_BUTTON_LAST] = { false }; bool InputManager::previous[GLFW_MOUSE_BUTTON_LAST] = { false };
bool InputManager::currentKeys[GLFW_KEY_LAST] = { false };
bool InputManager::previousKeys[GLFW_KEY_LAST] = { false };
bool InputManager::isKeyPressed(int keycode) { bool InputManager::isKeyPressed(int keycode) {
auto window = static_cast<GLFWwindow*>(Application::getInstance().getWindow().GetNativeWindow()); return currentKeys[keycode] && !previousKeys[keycode];
return glfwGetKey(window, keycode) == GLFW_PRESS; }
bool InputManager::isKeyReleased(int keycode) {
return !currentKeys[keycode] && previousKeys[keycode];
} }
bool InputManager::isMouseButtonPressed(int button) { bool InputManager::isMouseButtonPressed(int button) {
@ -22,11 +27,23 @@ bool InputManager::isMouseButtonReleased(int button) {
return !current[button] && previous[button]; return !current[button] && previous[button];
} }
bool InputManager::isKeyDown(int keycode) {
return currentKeys[keycode];
}
void InputManager::update() { void InputManager::update() {
auto window = static_cast<GLFWwindow*>(Application::getInstance().getWindow().GetNativeWindow());
for (int i=0; i < GLFW_MOUSE_BUTTON_LAST; ++i) { for (int i=0; i < GLFW_MOUSE_BUTTON_LAST; ++i) {
previous[i] = current[i]; previous[i] = current[i];
current[i] = glfwGetMouseButton(static_cast<GLFWwindow*>(Application::getInstance().getWindow().GetNativeWindow()), i) == GLFW_PRESS; current[i] = glfwGetMouseButton(window, i) == GLFW_PRESS;
} }
for (int i=0; i < GLFW_KEY_LAST; ++i) {
previousKeys[i] = currentKeys[i];
currentKeys[i] = glfwGetKey(window, i) == GLFW_PRESS;
}
} }
glm::vec2 InputManager::getMousePosition() { glm::vec2 InputManager::getMousePosition() {

View File

@ -11,7 +11,7 @@
class InputManager { class InputManager {
public: public:
static bool isKeyPressed(int keycode);
static glm::vec2 getMousePosition(); static glm::vec2 getMousePosition();
static glm::vec2 getMousePositionNormalized(); static glm::vec2 getMousePositionNormalized();
@ -21,12 +21,20 @@ public:
static bool isMouseButtonPressed(int button); static bool isMouseButtonPressed(int button);
static bool isMouseButtonReleased(int button); static bool isMouseButtonReleased(int button);
static bool isKeyDown(int keycode);
static bool isKeyPressed(int keycode);
static bool isKeyReleased(int keycode);
static void update(); static void update();
private: private:
static bool current[GLFW_MOUSE_BUTTON_LAST]; static bool current[GLFW_MOUSE_BUTTON_LAST];
static bool previous[GLFW_MOUSE_BUTTON_LAST]; static bool previous[GLFW_MOUSE_BUTTON_LAST];
static bool currentKeys[GLFW_KEY_LAST];
static bool previousKeys[GLFW_KEY_LAST];
}; };

View File

@ -25,7 +25,7 @@ void GameLayer::onAttach()
texturedModel = *OBJLoader::loadModel("assets/dragon/dragon.obj", "assets/dragon/dragon.png", loader); texturedModel = *OBJLoader::loadModel("assets/dragon/dragon.obj", "assets/dragon/dragon.png", loader);
entities.push_back(std::make_shared<Entity>(Entity(std::make_shared<TexturedModel>(texturedModel), glm::vec3(0,0,-25), 0,0,0, 1.f))); entities.push_back(std::make_shared<Entity>(Entity(std::make_shared<TexturedModel>(texturedModel), glm::vec3(0,0,-25), 0,0,0, 1.f)));
camera = std::make_unique<Camera>(); camera = std::make_unique<Camera>();
light = std::make_unique<Light>(glm::vec3(0,10,0), glm::vec3(1,1,1)); light = std::make_unique<Light>(glm::vec3(50,100,50), glm::vec3(1,1,1));
mousePicker = std::make_unique<MousePicker>(renderer->getProjectionMatrix(), MathUtils::createViewMatrix(*camera)); mousePicker = std::make_unique<MousePicker>(renderer->getProjectionMatrix(), MathUtils::createViewMatrix(*camera));
//Map Generation //Map Generation
@ -77,10 +77,10 @@ void GameLayer::onUpdate()
mousePicker->update(*camera); mousePicker->update(*camera);
//printf("Mouse Ray: %f, %f, %f\n", mousePicker->getCurrentRay().x, mousePicker->getCurrentRay().y, mousePicker->getCurrentRay().z); //printf("Mouse Ray: %f, %f, %f\n", mousePicker->getCurrentRay().x, mousePicker->getCurrentRay().y, mousePicker->getCurrentRay().z);
glm::vec3 moveDir = glm::vec3(0,0,0); glm::vec3 moveDir = glm::vec3(0,0,0);
if (InputManager::isKeyPressed(GLFW_KEY_W)) moveDir.z -= 1.0f; if (InputManager::isKeyDown(GLFW_KEY_W)) moveDir.z -= 1.0f;
if (InputManager::isKeyPressed(GLFW_KEY_S)) moveDir.z += 1.0f; if (InputManager::isKeyDown(GLFW_KEY_S)) moveDir.z += 1.0f;
if (InputManager::isKeyPressed(GLFW_KEY_A)) moveDir.x -= 1.0f; if (InputManager::isKeyDown(GLFW_KEY_A)) moveDir.x -= 1.0f;
if (InputManager::isKeyPressed(GLFW_KEY_D)) moveDir.x += 1.0f; if (InputManager::isKeyDown(GLFW_KEY_D)) moveDir.x += 1.0f;
if (InputManager::isKeyPressed(GLFW_KEY_1)) { if (InputManager::isKeyPressed(GLFW_KEY_1)) {
gameMode->setActiveBuilding(BuildingType::FOREST_HUT); gameMode->setActiveBuilding(BuildingType::FOREST_HUT);
@ -88,6 +88,10 @@ void GameLayer::onUpdate()
gameMode->setActiveBuilding(BuildingType::STONE_MASON); gameMode->setActiveBuilding(BuildingType::STONE_MASON);
} }
if (InputManager::isKeyPressed(GLFW_KEY_KP_ADD)) {
turnSystem->nextTurn(*turnState, Application::getInstance().getEventBus());
}
camera->move(moveDir, 0.5f); camera->move(moveDir, 0.5f);
tileHighlightSystem->update(*entityManager, *mousePicker, *camera); tileHighlightSystem->update(*entityManager, *mousePicker, *camera);

View File

@ -15,6 +15,7 @@
#include "hexWorld/Map.h" #include "hexWorld/Map.h"
#include "hexWorld/ecs/systems/BuildingPlacementSystem.h" #include "hexWorld/ecs/systems/BuildingPlacementSystem.h"
#include "hexWorld/ecs/systems/TileHighlightSystem.h" #include "hexWorld/ecs/systems/TileHighlightSystem.h"
#include "hexWorld/gameplay/TurnSystem.h"
class GameLayer: public Layer { class GameLayer: public Layer {
@ -45,6 +46,8 @@ private:
std::unique_ptr<EntityManager> entityManager = std::make_unique<EntityManager>(); std::unique_ptr<EntityManager> entityManager = std::make_unique<EntityManager>();
std::unique_ptr<Map> map; std::unique_ptr<Map> map;
std::unique_ptr<TurnSystem> turnSystem = std::make_unique<TurnSystem>();
std::unique_ptr<TurnState> turnState = std::make_unique<TurnState>();
}; };

View File

@ -7,17 +7,19 @@
#include <iostream> #include <iostream>
#include <ostream> #include <ostream>
#include "../engine/core/Application.h"
#include "../engine/core/gui/text/Font.h" #include "../engine/core/gui/text/Font.h"
#include "../engine/core/gui/uiComponent/UiButton.h" #include "../engine/core/gui/uiComponent/UiButton.h"
#include "../engine/core/gui/uiComponent/UiImage.h" #include "../engine/core/gui/uiComponent/UiImage.h"
#include "../engine/core/gui/uiComponent/UiText.h" #include "../engine/core/gui/uiComponent/UiText.h"
#include "../engine/renderer/loader/Loader.h" #include "../engine/renderer/loader/Loader.h"
#include "../engine/renderer/model/GUITexture.h" #include "../engine/renderer/model/GUITexture.h"
#include "hexWorld/events/TurnChangedEvent.h"
#include "ui/components/UiInventoryContainer.h" #include "ui/components/UiInventoryContainer.h"
#include "ui/components/UiRessourceWidget.h" #include "ui/components/UiRessourceWidget.h"
#include "ui/components/factorys/RessourceWidgetFactory.h" #include "ui/components/factorys/RessourceWidgetFactory.h"
UILayer::UILayer() { UILayer::UILayer(): events(Application::getInstance().getEventBus()) {
Loader& loader = Loader::instance(); Loader& loader = Loader::instance();
guiRenderer = std::make_unique<GUIRenderer>(loader); guiRenderer = std::make_unique<GUIRenderer>(loader);
textRenderer = std::make_unique<TextRenderer>(); textRenderer = std::make_unique<TextRenderer>();
@ -28,7 +30,7 @@ void UILayer::onAttach() {
rootContainer = std::make_unique<UiContainer>(); rootContainer = std::make_unique<UiContainer>();
rootContainer->getLayoutStyle().flexDirection = FlexDirection::Row; rootContainer->getLayoutStyle().flexDirection = FlexDirection::Column;
auto imageStyle = LayoutStyle(); auto imageStyle = LayoutStyle();
imageStyle.width = SizeValue(0.25f, SizeUnit::Percent); imageStyle.width = SizeValue(0.25f, SizeUnit::Percent);
@ -63,7 +65,7 @@ void UILayer::onAttach() {
//rootContainer->addChild(std::move(button)); //rootContainer->addChild(std::move(button));
smallFont =std::make_unique<Font>("/usr/share/fonts/TTF/DejaVuSans.ttf", 18); smallFont =std::make_unique<Font>("/usr/share/fonts/TTF/DejaVuSans.ttf", 18);
mediumFont = std::make_unique<Font>("/usr/share/fonts/TTF/DejaVuSans.ttf", 28);
auto inventoryContainer = std::make_unique<UiInventoryContainer>(*smallFont); auto inventoryContainer = std::make_unique<UiInventoryContainer>(*smallFont);
@ -75,6 +77,21 @@ void UILayer::onAttach() {
inventoryContainerID = rootContainer->addChild(std::move(inventoryContainer)); inventoryContainerID = rootContainer->addChild(std::move(inventoryContainer));
LayoutStyle turnStyle;
turnStyle.width = SizeValue(200.f, SizeUnit::Pixels);
turnStyle.height = SizeValue(30.f, SizeUnit::Pixels); // nur für Layout, echte Höhe kommt aus Font
turnStyle.margin.left = {20.f, SizeUnit::Pixels}; // Abstand zum Inventory
turnStyle.margin.top = {10.f, SizeUnit::Pixels};
auto turnLabel = std::make_unique<UiText>(*mediumFont, "Runde: 1", turnStyle, glm::vec3(1,1,1));
turnTextID = rootContainer->addChild(std::move(turnLabel));
events.subscribe<TurnChangedEvent>([this](const TurnChangedEvent& event) {
auto turnTextLabel = dynamic_cast<UiText*>(rootContainer->getChildAtIndex(turnTextID));
if (turnTextLabel) {
turnTextLabel->setText("Runde: " + std::to_string(event.newTurn));
};
});
} }
void UILayer::onUpdate() { void UILayer::onUpdate() {

View File

@ -7,6 +7,7 @@
#include <memory> #include <memory>
#include "GameMode.h" #include "GameMode.h"
#include "../engine/core/events/EventBus.h"
#include "../engine/core/gui/text/Font.h" #include "../engine/core/gui/text/Font.h"
#include "../engine/core/gui/uiMain/UiContainer.h" #include "../engine/core/gui/uiMain/UiContainer.h"
#include "../engine/layer/Layer.h" #include "../engine/layer/Layer.h"
@ -21,9 +22,13 @@ private:
std::unique_ptr<TextRenderer> textRenderer; std::unique_ptr<TextRenderer> textRenderer;
std::unique_ptr<Font> font; std::unique_ptr<Font> font;
std::unique_ptr<Font> smallFont; std::unique_ptr<Font> smallFont;
std::unique_ptr<Font> mediumFont;
std::unique_ptr<UiContainer> rootContainer; std::unique_ptr<UiContainer> rootContainer;
size_t inventoryContainerID; size_t inventoryContainerID;
size_t turnTextID;
EventBus& events;
public: public:
UILayer(); UILayer();
void onAttach() override; void onAttach() override;

View File

@ -0,0 +1,5 @@
//
// Created by sebastian on 13.02.26.
//
#include "ResourceCollectEvent.h"

View File

@ -0,0 +1,18 @@
//
// Created by sebastian on 13.02.26.
//
#ifndef DICEWARS_SIEDLER_RESOURCECOLLECTEVENT_H
#define DICEWARS_SIEDLER_RESOURCECOLLECTEVENT_H
#include "../../../engine/core/ECS/EntityManager.h"
class ResourceCollectEvent {
public:
EntityID buildingEntityID;
RessourceType ressourceType;
int amount;
};
#endif //DICEWARS_SIEDLER_RESOURCECOLLECTEVENT_H

View File

@ -0,0 +1,5 @@
//
// Created by sebastian on 13.02.26.
//
#include "TurnChangedEvent.h"

View File

@ -0,0 +1,15 @@
//
// Created by sebastian on 13.02.26.
//
#ifndef DICEWARS_SIEDLER_TURNCHANGEDEVENT_H
#define DICEWARS_SIEDLER_TURNCHANGEDEVENT_H
class TurnChangedEvent {
public:
int newTurn;
};
#endif //DICEWARS_SIEDLER_TURNCHANGEDEVENT_H

View File

@ -0,0 +1,12 @@
//
// Created by sebastian on 13.02.26.
//
#ifndef DICEWARS_SIEDLER_TURNSTATE_H
#define DICEWARS_SIEDLER_TURNSTATE_H
struct TurnState {
int currentTurn = 1;
};
#endif //DICEWARS_SIEDLER_TURNSTATE_H

View File

@ -0,0 +1,13 @@
//
// Created by sebastian on 13.02.26.
//
#include "TurnSystem.h"
#include "../events/TurnChangedEvent.h"
void TurnSystem::nextTurn(TurnState &turn, EventBus &events) {
turn.currentTurn++;
events.emit(TurnChangedEvent{turn.currentTurn});
}

View File

@ -0,0 +1,18 @@
//
// Created by sebastian on 13.02.26.
//
#ifndef DICEWARS_SIEDLER_TURNSYSTEM_H
#define DICEWARS_SIEDLER_TURNSYSTEM_H
#include "TurnState.h"
#include "../../../engine/core/ECS/EntityManager.h"
#include "../../../engine/core/events/EventBus.h"
class TurnSystem {
public:
void nextTurn(TurnState& turn, EventBus& events);
};
#endif //DICEWARS_SIEDLER_TURNSYSTEM_H