#include "animate2.hpp" #include #include #include "dbc.hpp" #include "rand.hpp" namespace animate2 { std::vector Animate2::calc_frames() { std::vector frames; for(int frame_i : $sequence.frames) { frames.emplace_back( sf::Vector2i{$sheet.frame_width * frame_i, 0}, // NOTE: one row only for now sf::Vector2i{$sheet.frame_width, $sheet.frame_height}); } return frames; } void Animate2::play() { dbc::check(!playing, "can't call play while playing?"); $sequence.current = 0; $sequence.subframe = 0.0f; $sequence.loop_count = 0; playing = true; $sequence.timer.start(); } void Animate2::stop() { playing = false; $sequence.timer.reset(); } // need one for each kind of thing to animate // NOTE: possibly find a way to only run apply on frame change? void Animate2::apply(sf::Sprite& sprite) { dbc::check($sequence.current < $frame_rects.size(), "current frame past $frame_rects"); // NOTE: pos is not updated yet auto& rect = $frame_rects.at($sequence.current); sprite.setTextureRect(rect); } // replaces step void Animate2::update_frame() { 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()"); auto duration = $sequence.durations.at($sequence.current); bool frame_change = false; if($sequence.timer.getElapsedTime() >= duration) { $sequence.timer.restart(); $sequence.current++; frame_change = true; } if($sequence.current >= $sequence.frame_count) { $sequence.loop_count++; playing = onLoop($sequence, $transform); } if(frame_change && onFrame != nullptr) onFrame(); dbc::check($sequence.current < $sequence.frame_count, "onLoop fail: current frame out of frames.size()"); } void Animate2::update() { $sequence.subframe += $transform.speed; update_frame(); } void Animate2::motion(sf::Vector2f& pos, sf::Vector2f& scale) { $transform.twitching($sequence); $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); } void Transform::lerp(Sequence& seq, sf::Vector2f& pos_out, sf::Vector2f& scale_out) { float tick = std::abs(twitching(seq)); return motion(*this, pos_out, scale_out, tick); } }