Refactor the animate2 and then start working on the motion feature.

This commit is contained in:
Zed A. Shaw 2026-01-21 13:13:58 -05:00
parent 992b8f0e0a
commit 60c405b1fc
9 changed files with 408 additions and 290 deletions

146
animate2.cpp Normal file
View file

@ -0,0 +1,146 @@
#include "animate2.hpp"
#include <memory>
#include <chrono>
#include "dbc.hpp"
#include "rand.hpp"
namespace animate2 {
std::vector<sf::IntRect> Animate2::calc_frames() {
std::vector<sf::IntRect> 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.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() {
update_frame();
}
void Animate2::motion(sf::Vector2f& pos, sf::Vector2f& scale) {
$transform.twitching($sequence);
$transform.lerp($sequence, pos, scale);
}
float Transform::twitching(Sequence& seq) {
float subframe = seq.timer.getElapsedTime().asSeconds();
float tick = 1 - std::powf(ease_rate, subframe + 0.0001);
fmt::println("TICK {}; subframe: {}", tick, subframe);
switch(easing) {
case ease::NONE:
return 0.0;
case ease::SINE:
return std::abs(std::sin(subframe * ease_rate));
case ease::OUT_CIRC:
return ease::out_circ(tick);
case ease::OUT_BOUNCE:
return ease::out_bounce(tick);
case ease::IN_OUT_BACK:
return ease::in_out_back(tick);
case ease::RANDOM:
return Random::uniform_real(0.0001f, 1.0f);
case ease::NORM_DIST:
return Random::normal(0.5f, 0.1f);
case ease::LINEAR:
return tick;
default:
dbc::sentinel(
fmt::format("Invalid easing {} given to animation",
int(easing)));
}
}
void Transform::lerp(Sequence& seq, sf::Vector2f& scale_out, sf::Vector2f& pos_out) {
float tick = twitching(seq);
if(stationary) {
switch(motion) {
case ease::SHAKE: {
pos_out.x += std::lerp(min_x, max_x, tick);
} break;
case ease::BOUNCE: {
pos_out.y -= std::lerp(min_y, max_y, tick);
} break;
case ease::RUSH: {
scale_out.x = std::lerp(min_x, max_x, tick);
scale_out.y = std::lerp(min_y, max_y, tick);
pos_out.y = pos_out.y - (pos_out.y * scale_out.y - pos_out.y);
} break;
case ease::SQUEEZE: {
scale_out.x *= std::lerp(min_x, max_x, tick);
} break;
case ease::SQUASH: {
scale_out.y *= std::lerp(min_y, max_y, tick);
} break;
case ease::STRETCH: {
scale_out.x = std::lerp(min_x, max_x, tick);
} break;
case ease::GROW: {
scale_out.y = std::lerp(min_y, max_y, tick);
} break;
case ease::SLIDE: {
pos_out.x = std::lerp(min_x, max_x, tick);
pos_out.y = std::lerp(min_y, max_y, tick);
} break;
default:
dbc::sentinel("Unknown animation.motion setting.");
}
} else {
scale_out.x = std::lerp(scale_out.x * min_x, scale_out.x * max_x, tick);
scale_out.y = std::lerp(scale_out.y * min_y, scale_out.y * max_y, tick);
}
}
}