135 lines
3.7 KiB
C++
135 lines
3.7 KiB
C++
#pragma once
|
|
#include <memory>
|
|
#include <chrono>
|
|
#include <SFML/Graphics/Rect.hpp>
|
|
#include <SFML/Graphics/Sprite.hpp>
|
|
#include <SFML/Graphics/Shader.hpp>
|
|
#include <SFML/Graphics/View.hpp>
|
|
#include <SFML/System/Clock.hpp>
|
|
#include <SFML/System/Time.hpp>
|
|
#include <functional>
|
|
#include "ease2.hpp"
|
|
#include <fmt/core.h>
|
|
#include "json_mods.hpp"
|
|
|
|
namespace animate2 {
|
|
|
|
template <typename T> struct NameOf;
|
|
|
|
struct Sheet {
|
|
int frames{0};
|
|
int frame_width{0};
|
|
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{};
|
|
|
|
std::pair<int, double> commit();
|
|
void start();
|
|
void reset();
|
|
void restart();
|
|
sf::Time getElapsedTime();
|
|
};
|
|
|
|
struct Sequence {
|
|
std::vector<int> frames{};
|
|
std::vector<std::chrono::milliseconds> durations{};
|
|
size_t current{0};
|
|
int loop_count{0};
|
|
size_t frame_count{0};
|
|
Timer timer{};
|
|
float subframe{0.0f};
|
|
};
|
|
|
|
struct Transform {
|
|
// how to know when a transform ends?
|
|
float min_x{1.0f};
|
|
float min_y{1.0f};
|
|
float max_x{1.0f};
|
|
float max_y{1.0f};
|
|
bool flipped{false};
|
|
float ease_rate{0.5f};
|
|
bool scaled{false};
|
|
|
|
// handled by onLoop
|
|
bool toggled{false};
|
|
bool looped{false};
|
|
std::string easing{"in_out_back"};
|
|
std::string motion{"move_rush"};
|
|
|
|
// change to using a callback function for these
|
|
ease2::EaseFunc easing_func{ease2::get_easing(easing)};
|
|
ease2::MotionFunc motion_func{ease2::get_motion(motion)};
|
|
|
|
std::shared_ptr<sf::Shader> shader{nullptr};
|
|
|
|
void lerp(Sequence& seq, sf::Vector2f& pos_out, sf::Vector2f& scale_out);
|
|
};
|
|
|
|
/* Gets the number of times it looped, and returns if it should stop. */
|
|
using OnLoopHandler = std::function<bool(Sequence& seq, Transform& tr)>;
|
|
using OnFrameHandler = std::function<void()>;
|
|
|
|
inline bool DefaultOnLoop(Sequence& seq, Transform& tr) {
|
|
if(tr.toggled) {
|
|
seq.current = seq.frame_count - 1;
|
|
} else {
|
|
seq.current = 0;
|
|
}
|
|
|
|
return tr.looped;
|
|
}
|
|
|
|
using Form = std::pair<std::string, std::string>;
|
|
using Sound = std::pair<size_t, std::string>;
|
|
|
|
class Animate2 {
|
|
public:
|
|
Sheet sheet;
|
|
std::unordered_map<std::string, Sequence> sequences;
|
|
std::unordered_map<std::string, Transform> transforms;
|
|
std::unordered_map<std::string, Form> forms;
|
|
std::unordered_map<std::string, std::vector<Sound>> sounds;
|
|
OnFrameHandler onFrame = nullptr;
|
|
|
|
Sequence sequence{};
|
|
Transform transform{};
|
|
|
|
std::vector<sf::IntRect> $frame_rects{calc_frames()};
|
|
OnLoopHandler onLoop = DefaultOnLoop;
|
|
bool playing = false;
|
|
|
|
// mostly for debugging purposes
|
|
std::string form_name="idle";
|
|
std::string sequence_name="";
|
|
std::string transform_name="";
|
|
|
|
std::vector<sf::IntRect> calc_frames();
|
|
void play();
|
|
void play_sound();
|
|
void stop();
|
|
bool has_form(const std::string& as_form);
|
|
void set_form(const std::string& form);
|
|
void apply(sf::Sprite& sprite);
|
|
void apply(sf::View& view_out, sf::Vector2f pos, sf::Vector2f size);
|
|
void apply_effect(std::shared_ptr<sf::Shader> effect);
|
|
void update();
|
|
void motion(sf::Sprite& sprite, sf::Vector2f pos, sf::Vector2f scale);
|
|
std::pair<int, double> commit();
|
|
};
|
|
|
|
Animate2 load(const std::string &file, const std::string &anim_name);
|
|
|
|
ENROLL_COMPONENT(Sheet, frames, frame_width, frame_height);
|
|
ENROLL_COMPONENT(Sequence, frames, durations);
|
|
ENROLL_COMPONENT(Transform, min_x, min_y, max_x, max_y,
|
|
flipped, ease_rate, scaled, toggled, looped, easing, motion);
|
|
ENROLL_COMPONENT(Animate2, sheet, sequences, transforms, forms, sounds);
|
|
}
|