diff --git a/CMakeLists.txt b/CMakeLists.txt index 17cee1a..e282aae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,6 +192,14 @@ add_executable(Dicewars_Siedler src/main.cpp src/engine/renderer/components/WorldSpriteRenderingData.h src/engine/renderer/shaders/WorldSpriteShader.cpp src/engine/renderer/shaders/WorldSpriteShader.h + src/engine/core/animations/AnimationCurve.h + src/engine/core/animations/AnimationTrack.h + src/engine/core/animations/AnimationComponent.cpp + src/engine/core/animations/AnimationComponent.h + src/engine/core/animations/AnimationSystem.cpp + src/engine/core/animations/AnimationSystem.h + src/engine/core/EngineTime.cpp + src/engine/core/EngineTime.h ) target_compile_options(Dicewars_Siedler PRIVATE diff --git a/src/engine/core/Application.cpp b/src/engine/core/Application.cpp index 3e8a26b..1b28242 100644 --- a/src/engine/core/Application.cpp +++ b/src/engine/core/Application.cpp @@ -4,11 +4,19 @@ #include "Application.h" +#include "EngineTime.h" #include "../layer/Layer.h" #include "../platform/glfw/InputManager.h" Application* Application::instance = nullptr; +void Application::updateTime() { + const auto now = static_cast(glfwGetTime()); + EngineTime::deltaTime = now - lastFrame; + EngineTime::totalTime += EngineTime::deltaTime; + lastFrame = now; +} + void Application::pushLayer(Layer* layer) { layers.push_back(layer); layer->onAttach(); @@ -34,6 +42,7 @@ Application::~Application() void Application::run() { while (!window->shouldClose()) { + updateTime(); for (Layer* layer : layers) { layer->onUpdate(); diff --git a/src/engine/core/Application.h b/src/engine/core/Application.h index d9de98a..860f8fc 100644 --- a/src/engine/core/Application.h +++ b/src/engine/core/Application.h @@ -34,6 +34,10 @@ private: std::vector layers; EventBus eventBus; + void updateTime(); + + float lastFrame; + protected: void pushLayer(Layer* layer); }; diff --git a/src/engine/core/EngineTime.cpp b/src/engine/core/EngineTime.cpp new file mode 100644 index 0000000..15364ec --- /dev/null +++ b/src/engine/core/EngineTime.cpp @@ -0,0 +1,8 @@ +// +// Created by sebastian on 14.02.26. +// + +#include "EngineTime.h" + +float EngineTime::deltaTime = 0.0f; +float EngineTime::totalTime = 0.0f; \ No newline at end of file diff --git a/src/engine/core/EngineTime.h b/src/engine/core/EngineTime.h new file mode 100644 index 0000000..6b76f21 --- /dev/null +++ b/src/engine/core/EngineTime.h @@ -0,0 +1,16 @@ +// +// Created by sebastian on 14.02.26. +// + +#ifndef DICEWARS_SIEDLER_ENGINETIME_H +#define DICEWARS_SIEDLER_ENGINETIME_H + + +class EngineTime { +public: + static float deltaTime; + static float totalTime; +}; + + +#endif //DICEWARS_SIEDLER_ENGINETIME_H \ No newline at end of file diff --git a/src/engine/core/animations/AnimationComponent.cpp b/src/engine/core/animations/AnimationComponent.cpp new file mode 100644 index 0000000..8a5fa46 --- /dev/null +++ b/src/engine/core/animations/AnimationComponent.cpp @@ -0,0 +1,5 @@ +// +// Created by sebastian on 14.02.26. +// + +#include "AnimationComponent.h" \ No newline at end of file diff --git a/src/engine/core/animations/AnimationComponent.h b/src/engine/core/animations/AnimationComponent.h new file mode 100644 index 0000000..80456dc --- /dev/null +++ b/src/engine/core/animations/AnimationComponent.h @@ -0,0 +1,17 @@ +// +// Created by sebastian on 14.02.26. +// + +#ifndef DICEWARS_SIEDLER_ANIMATIONCOMPONENT_H +#define DICEWARS_SIEDLER_ANIMATIONCOMPONENT_H +#include "AnimationTrack.h" +#include "../ECS/Component.h" + + +class AnimationComponent : public Component { +public: + std::vector tracks; +}; + + +#endif //DICEWARS_SIEDLER_ANIMATIONCOMPONENT_H \ No newline at end of file diff --git a/src/engine/core/animations/AnimationCurve.h b/src/engine/core/animations/AnimationCurve.h new file mode 100644 index 0000000..43255ac --- /dev/null +++ b/src/engine/core/animations/AnimationCurve.h @@ -0,0 +1,52 @@ +// +// Created by sebastian on 14.02.26. +// + +#ifndef DICEWARS_SIEDLER_ANIMATIONCURVE_H +#define DICEWARS_SIEDLER_ANIMATIONCURVE_H +#include + +enum class CurveType { + Sine, + Triangle, + SmoothStep, + EaseInOut, + Constant +}; + +struct AnimationCurve { + CurveType type = CurveType::Sine; + float amplitude = 1.0f; + float frequency = 1.0f; + float phase = 0.0f; + float offset = 0.0f; + + float evaluate(float time) const { + float t = time * frequency + phase; + + switch (type) { + case CurveType::Sine: + return offset + std::sin(t) * amplitude; + + case CurveType::Triangle: + return offset + (2.0f * amplitude / M_PI) * std::asin(std::sin(t)); + + case CurveType::SmoothStep: { + float x = 0.5f + 0.5f * std::sin(t); + return offset + amplitude * (x * x * (3.0f - 2.0f * x)); + } + + case CurveType::EaseInOut: { + float x = 0.5f + 0.5f * std::sin(t); + return offset + amplitude * (1.0f - std::cos(x * M_PI)); + } + + case CurveType::Constant: + return offset; + } + return offset; + } +}; + + +#endif //DICEWARS_SIEDLER_ANIMATIONCURVE_H \ No newline at end of file diff --git a/src/engine/core/animations/AnimationSystem.cpp b/src/engine/core/animations/AnimationSystem.cpp new file mode 100644 index 0000000..d19389d --- /dev/null +++ b/src/engine/core/animations/AnimationSystem.cpp @@ -0,0 +1,17 @@ +// +// Created by sebastian on 14.02.26. +// + +#include "AnimationSystem.h" + +#include "AnimationComponent.h" + +void AnimationSystem::update(EntityManager &em, const float time) { + for (EntityID e : em.getAllEntities()) { + auto anim = em.getComponent(e); + if (!anim) continue; + for (const auto& track : anim->tracks) { + track.update(time); + } + } +} diff --git a/src/engine/core/animations/AnimationSystem.h b/src/engine/core/animations/AnimationSystem.h new file mode 100644 index 0000000..8e3a904 --- /dev/null +++ b/src/engine/core/animations/AnimationSystem.h @@ -0,0 +1,16 @@ +// +// Created by sebastian on 14.02.26. +// + +#ifndef DICEWARS_SIEDLER_ANIMATIONSYSTEM_H +#define DICEWARS_SIEDLER_ANIMATIONSYSTEM_H +#include "../ECS/EntityManager.h" + + +class AnimationSystem { +public: + static void update(EntityManager& em, float time); +}; + + +#endif //DICEWARS_SIEDLER_ANIMATIONSYSTEM_H \ No newline at end of file diff --git a/src/engine/core/animations/AnimationTrack.h b/src/engine/core/animations/AnimationTrack.h new file mode 100644 index 0000000..05226e1 --- /dev/null +++ b/src/engine/core/animations/AnimationTrack.h @@ -0,0 +1,26 @@ +// +// Created by sebastian on 14.02.26. +// + +#ifndef DICEWARS_SIEDLER_ANIMATIONTRACK_H +#define DICEWARS_SIEDLER_ANIMATIONTRACK_H +#include +#include + +#include "AnimationCurve.h" +using AnimationTarget = std::function; + +struct AnimationTrack { + AnimationCurve curve; + AnimationTarget target; + bool enabled = true; + + void update(float time) const { + if (!enabled) return; + const float value = curve.evaluate(time); + target(value); + } +}; + + +#endif //DICEWARS_SIEDLER_ANIMATIONTRACK_H \ No newline at end of file diff --git a/src/game/GameLayer.cpp b/src/game/GameLayer.cpp index 1e0060d..51f4536 100644 --- a/src/game/GameLayer.cpp +++ b/src/game/GameLayer.cpp @@ -4,6 +4,9 @@ #include "GameLayer.h" +#include "../engine/core/EngineTime.h" +#include "../engine/core/animations/AnimationComponent.h" +#include "../engine/core/animations/AnimationSystem.h" #include "../engine/core/ECS/ModelStateComponent.h" #include "../engine/core/ECS/WorldSpriteComponent.h" #include "../engine/platform/glfw/InputManager.h" @@ -59,9 +62,23 @@ void GameLayer::onAttach() TransformComponent transformComponent(glm::vec3(0,0,0), glm::vec3(0), 1.0f); testEntity = BuildingFactory::create(*entityManager, TemporaryBuildingDefinitionFactory::createForestHutDefinition(), transformComponent, 0, 0); - auto worldspriteComponent = WorldSpriteComponent(); - worldspriteComponent.texture = std::make_shared(modelTexture); - entityManager->addComponent(testEntity, std::make_shared(worldspriteComponent)); + auto worldSpritePtr = std::make_shared(); + worldSpritePtr->texture = std::make_shared(modelTexture); + entityManager->addComponent(testEntity, worldSpritePtr); + + auto anim = std::make_shared(); + + float baseY = worldSpritePtr->offset.y; + + anim->tracks.push_back({ + AnimationCurve{CurveType::Sine, 0.3f, 5.f}, + [worldSpritePtr, baseY](float v) { + worldSpritePtr->offset.y = baseY + v; + } + }); + + entityManager->addComponent(testEntity, anim); + events.subscribe([this](const TurnChangedEvent& event) { ProducingSystem::onTurnEnded(*entityManager); @@ -98,7 +115,7 @@ void GameLayer::onUpdate() modelStateComponent->params["fillRatio"] += 0.1f; } - + AnimationSystem::update(*entityManager, EngineTime::totalTime); camera->move(moveDir, 0.5f); tileHighlightSystem->update(*entityManager, *mousePicker, *camera); buildingPlacementSystem->update(*entityManager, *gameMode, 0, *turnState);