#pragma once #include "animatable.hh" namespace creeper { template concept transition_state_trait = requires(T& t) { typename T::ValueT; { t.get_value() } -> std::same_as; { t.get_target() } -> std::same_as; { t.set_value(std::declval()) }; { t.set_target(std::declval()) }; { t.update() } -> std::same_as; }; // Functor like lambda template struct TransitionTask : public ITransitionTask { public: explicit TransitionTask(std::shared_ptr state, std::shared_ptr token) noexcept : state { std::move(state) } , running { std::move(token) } { } ~TransitionTask() override = default; auto update() noexcept -> bool override { return *running && state->update(); // } private: std::shared_ptr state; std::shared_ptr running; }; template struct TransitionValue { public: using T = State::ValueT; explicit TransitionValue(Animatable& animatable, std::shared_ptr state) noexcept : animatable { animatable } , state { std::move(state) } { } auto get_state() const noexcept -> const State& { return *state; } auto get_value() const noexcept { return state->get_value(); } auto get_target() const noexcept { return state->get_target(); } operator T() const noexcept { return state->get_value(); } auto transition_to(const T& to) noexcept -> void { // Update target of state state->set_target(to); // Clear last transition task if (running) { *running = false; } running = std::make_shared(true); // Push new transition task auto task = std::make_unique>(state, running); animatable.push_transition_task(std::move(task)); } auto snap_to(T to) noexcept -> void { state->set_value(std::move(to)); state->set_target(std::move(to)); if (running) *running = false; } private: std::shared_ptr state; std::shared_ptr running; Animatable& animatable; }; template inline auto make_transition(Animatable& core, std::shared_ptr state) { return std::make_unique>(core, state); } }