diff --git a/animate2.cpp b/animate2.cpp index a3a536e..2718b21 100644 --- a/animate2.cpp +++ b/animate2.cpp @@ -35,7 +35,7 @@ namespace animate2 { sequence.loop_count = 0; playing = true; sequence.timer.start(); - sequence.frame_count = sequence.frames.size(); + sequence.INVARIANT(); } void Animate2::stop() { @@ -96,9 +96,8 @@ namespace animate2 { * elapsed is DELTA, or use elapsed here? */ void Animate2::update() { - dbc::check(sequence.easing_duration > 0.0, "bad easing duration"); dbc::check(playing, "attempt to update animation that's not playing"); - dbc::check(sequence.frame_count == sequence.frames.size(), "frame_count doesn't match frame.size()"); + sequence.INVARIANT(); auto [ticks, alpha] = sequence.timer.commit(); int duration = sequence.durations.at(sequence.current); @@ -119,16 +118,17 @@ namespace animate2 { sequence.loop_count++; sequence.easing_position = 0; playing = onLoop(sequence, transform); + sequence.INVARIANT(); } if(frame_change) play_sound(); if(frame_change && onFrame != nullptr) onFrame(); - - dbc::check(sequence.current < sequence.frame_count, "onLoop fail: current frame out of frames.size()"); } void Animate2::motion(sf::Transformable& sprite, sf::Vector2f pos, sf::Vector2f scale) { + sequence.INVARIANT(); + transform.apply(sequence, pos, scale); if(transform.flipped) { @@ -219,6 +219,8 @@ namespace animate2 { sequence = sequences.at(seq_name); transform = transforms.at(tr_name); + sequence.frame_count = sequence.frames.size(); + // BUG: should this be configurable instead? for(auto duration : sequence.durations) { sequence.easing_duration += float(duration); @@ -228,6 +230,8 @@ namespace animate2 { $frame_rects = calc_frames(); transform.easing_func = ease2::get_easing(transform.easing); transform.motion_func = ease2::get_motion(transform.motion); + + sequence.INVARIANT(); } Animate2 load(const std::string &file, const std::string &anim_name) { @@ -245,4 +249,23 @@ namespace animate2 { return anim; } + + void Sequence::INVARIANT(const std::source_location location) { + dbc::check(frames.size() == durations.size(), + fmt::format("frames.size={} doesn't match durations.size={}", + frames.size(), durations.size()), location); + + dbc::check(easing_duration > 0.0, + fmt::format("bad easing duration: {}", easing_duration), location); + + dbc::check(frame_count == frames.size(), + fmt::format("frame_count={} doesn't match frames.size={}", frame_count, frames.size()), location); + + dbc::check(frame_count == durations.size(), + fmt::format("frame_count={} doesn't match durations.size={}", frame_count, durations.size()), location); + + dbc::check(current < durations.size(), + fmt::format("current={} went past end of fame durations.size={}", + current, durations.size()), location); + } } diff --git a/animate2.hpp b/animate2.hpp index 15f9601..b02e5aa 100644 --- a/animate2.hpp +++ b/animate2.hpp @@ -11,6 +11,7 @@ #include "ease2.hpp" #include #include "json_mods.hpp" +#include namespace animate2 { @@ -44,11 +45,13 @@ namespace animate2 { std::vector durations{}; // in ticks size_t current{0}; int loop_count{0}; - size_t frame_count{0}; + size_t frame_count{frames.size()}; Timer timer{}; int subframe{0}; float easing_duration{0.0f}; float easing_position{0.0f}; + + void INVARIANT(const std::source_location location = std::source_location::current()); }; struct Transform { diff --git a/assets/animate2.json b/assets/animate2.json index 327a5de..16f632e 100644 --- a/assets/animate2.json +++ b/assets/animate2.json @@ -8,7 +8,7 @@ "sequences": { "idle": {"frames": [0], "durations": [47] }, "hurt": {"frames": [0, 1], "durations": [5, 57] }, - "attack": {"frames": [0, 1, 0, 1], "durations": [35, 15, 5, 5] } + "attack": {"frames": [0, 1, 0, 1], "durations": [35, 15, 5, 50] } }, "transforms": { "rushing": { diff --git a/tests/animate2.cpp b/tests/animate2.cpp index 2c30fbb..6b37bcf 100644 --- a/tests/animate2.cpp +++ b/tests/animate2.cpp @@ -22,7 +22,11 @@ Animate2 load_animation(const string& name) { anim.set_form("attack"); anim.transform.looped = false; - anim.sequence.durations = {Random::uniform(1, 5), Random::uniform(1, 5)}; + + for(size_t i = 0; i < anim.sequence.durations.size(); i++) { + anim.sequence.durations[i] = Random::uniform(1, 5); + } + return anim; } @@ -61,6 +65,12 @@ TEST_CASE("new animation system", "[animation-new]") { auto anim = load_animation("rat_king_boss"); PLAY_TEST(anim); + // test that toggled works + anim.transform.toggled = true; + PLAY_TEST(anim); + REQUIRE(anim.sequence.current == anim.sequence.frames.size() - 1); + anim.transform.toggled = false; + bool onLoop_ran = false; anim.onLoop = [&](auto& seq, auto& tr) -> bool { seq.current = 0; @@ -84,16 +94,6 @@ TEST_CASE("new animation system", "[animation-new]") { PLAY_TEST(anim); REQUIRE(anim.sequence.loop_count == 2); - - // stops at end - anim.onLoop = [](auto& seq, auto& tr) -> bool { - if(seq.loop_count == 1) { - seq.current = seq.frame_count - 1; - return false; - } else { - return true; - } - }; }