From b7394f832da8c3b3caa88318754707fe2431e7a3 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Tue, 27 Jan 2026 12:52:33 -0500 Subject: [PATCH] Now have a timer for animations that does ticks with deltatime...maybe it works. --- animate2.cpp | 32 ++++++++++++++++++++++++++++++++ animate2.hpp | 20 +++++++++++++++++++- simplefsm.hpp | 2 +- tests/animate2.cpp | 29 ++++++++++++++++++++++++++++- tools/animator.cpp | 44 +++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 121 insertions(+), 6 deletions(-) diff --git a/animate2.cpp b/animate2.cpp index d50fce4..a310e25 100644 --- a/animate2.cpp +++ b/animate2.cpp @@ -76,6 +76,38 @@ namespace animate2 { $transform.lerp($sequence, pos, scale); } + void Timer::start() { + clock.start(); + } + + void Timer::reset() { + clock.reset(); + } + + void Timer::restart() { + clock.restart(); + } + + sf::Time Timer::getElapsedTime() { + return clock.getElapsedTime(); + } + + void Timer::begin() { + prev_time = clock.getElapsedTime().asSeconds(); + } + + std::pair Timer::commit() { + current_time = clock.getElapsedTime().asSeconds(); + frame_duration = current_time - prev_time; + accumulator += frame_duration; + + double tick_count = accumulator / DELTA; + double alpha = modf(tick_count, &tick_count); + accumulator -= tick_count * DELTA; + + return {int(tick_count), alpha}; + } + float Transform::twitching(Sequence& seq) { float tick = 1 - std::powf(ease_rate, seq.subframe + 0.0001); return easing(tick); diff --git a/animate2.hpp b/animate2.hpp index b153da9..548e648 100644 --- a/animate2.hpp +++ b/animate2.hpp @@ -7,6 +7,7 @@ #include #include #include "ease2.hpp" +#include namespace animate2 { struct Sheet { @@ -16,13 +17,30 @@ namespace animate2 { int frame_height{0}; }; + struct Timer { + double DELTA = 1.0/60.0; + double accumulator = 0.0; + double prev_time = 0.0; + double current_time = 0.0; + double frame_duration = 0.0; + double alpha = 0.0; + sf::Clock clock{}; + + void begin(); + std::pair commit(); + void start(); + void reset(); + void restart(); + sf::Time getElapsedTime(); + }; + struct Sequence { std::vector frames{}; std::vector durations{}; size_t current{0}; int loop_count{0}; size_t frame_count{frames.size()}; - sf::Clock timer{}; + Timer timer{}; float subframe{0.0f}; }; diff --git a/simplefsm.hpp b/simplefsm.hpp index b2378cc..4eb5718 100644 --- a/simplefsm.hpp +++ b/simplefsm.hpp @@ -5,7 +5,7 @@ #ifndef FSM_DEBUG #define FSM_STATE(C, S, E, ...) case C::S: S(E, ##__VA_ARGS__); break #else -int last_event=-1; +static int last_event=-1; #define FSM_STATE(C, S, E, ...) case C::S: if(last_event != int(E)) { last_event = int(E); fmt::println(">> " #C " " #S " event={}, state={}", int(E), int($state));}; S(E, ##__VA_ARGS__); break #endif diff --git a/tests/animate2.cpp b/tests/animate2.cpp index 8bd74b2..db9d28f 100644 --- a/tests/animate2.cpp +++ b/tests/animate2.cpp @@ -51,12 +51,16 @@ Animate2 crafter() { return {sheet, sequence, transform}; } +void FAKE_RENDER() { + std::this_thread::sleep_for(Random::milliseconds(5, 32)); +} + void PLAY_TEST(Animate2 &anim) { anim.play(); while(anim.playing) { anim.update(); - std::this_thread::sleep_for(Random::milliseconds(1, 100)); + FAKE_RENDER(); } REQUIRE(anim.playing == false); @@ -114,6 +118,7 @@ TEST_CASE("new animation system", "[animation-new]") { }; } + TEST_CASE("confirm frame sequencing works", "[animation-new]") { textures::init(); animation::init(); @@ -165,15 +170,37 @@ TEST_CASE("confirm transition changes work", "[animation-new]") { anim.play(); + sf::Clock clock; + clock.start(); + sf::Time start; + sf::Time delta; + + while(anim.playing) { + start = clock.getElapsedTime(); + anim.update(); anim.motion(pos, scale); std::this_thread::sleep_for(10ms); fmt::println("POSITION: {},{}; SCALE: {},{}; current: {}; subframe: {}", pos.x, pos.y, scale.x, scale.y, anim.$sequence.current, anim.$sequence.subframe); + + delta = clock.getElapsedTime() - start; + fmt::println("FRAME RATE {}", 1.0f / delta.asSeconds()); } REQUIRE(anim.playing == false); REQUIRE(pos != sf::Vector2f{0,0}); REQUIRE(scale != sf::Vector2f{0,0}); } + +TEST_CASE("playing with delta time", "[animation-new]") { + animate2::Timer timer; + + for(int i = 0; i < 20; i++) { + timer.begin(); + FAKE_RENDER(); + auto [tick_count, alpha] = timer.commit(); + fmt::println("tick: {}, alpha: {}", tick_count, alpha); + } +} diff --git a/tools/animator.cpp b/tools/animator.cpp index 633fc71..1ce2a67 100644 --- a/tools/animator.cpp +++ b/tools/animator.cpp @@ -1,3 +1,4 @@ +#define FSM_DEBUG 1 #include "sound.hpp" #include "ai.hpp" #include "animation.hpp" @@ -11,6 +12,9 @@ #include #include "gui/event_router.hpp" #include "gui/guecstra.hpp" +#include "animate2.hpp" + +bool YES_SYNC=true; namespace animator { struct UI { @@ -53,6 +57,7 @@ namespace animator { enum class State { START=__LINE__, + ANIMATE=__LINE__, END=__LINE__, }; @@ -63,20 +68,41 @@ namespace animator { void init(const std::string &sprite_name) { $ui.init(sprite_name); - $window.setVerticalSyncEnabled(VSYNC); - if(FRAME_LIMIT) $window.setFramerateLimit(FRAME_LIMIT); + + if(YES_SYNC) { + $window.setVerticalSyncEnabled(VSYNC); + if(FRAME_LIMIT) $window.setFramerateLimit(FRAME_LIMIT); + } + $window.setPosition({0,0}); } void event(game::Event ev, std::any data={}) { switch($state) { FSM_STATE(State, START, ev); + FSM_STATE(State, ANIMATE, ev); FSM_STATE(State, END, ev); } } void START(game::Event ev) { - state(State::START); + switch(ev) { + case game::Event::TICK: + state(State::ANIMATE); + break; + default: + state(State::START); + } + } + + void ANIMATE(game::Event ev) { + switch(ev) { + case game::Event::TICK: + // stuff + break; + default: + state(State::START); + } } void END(game::Event ev) { @@ -132,8 +158,20 @@ int main(int argc, char* argv[]) { animator::FSM main; main.init(argv[1]); + animate2::Timer timer; + timer.start(); + while(main.active()) { + timer.begin(); main.render(); + auto [ticks, alpha] = timer.commit(); + fmt::println("TICK: {}, alpha: {}", ticks, alpha); + + for(int i = 0; i < ticks; i++) { + main.event(game::Event::TICK, {}); + } + + // do something with alpha.... main.handle_keyboard_mouse(); }