Animator tool can now play, stop, loop, and toggle an animation.
This commit is contained in:
parent
7d79e75651
commit
df730047ac
3 changed files with 200 additions and 142 deletions
|
|
@ -38,7 +38,7 @@ Animate2 crafter() {
|
||||||
.max_y{0.8f},
|
.max_y{0.8f},
|
||||||
.simple{false},
|
.simple{false},
|
||||||
.flipped{false},
|
.flipped{false},
|
||||||
.ease_rate{0.5f},
|
.ease_rate{5.0f},
|
||||||
.scaled{true},
|
.scaled{true},
|
||||||
.toggled{false},
|
.toggled{false},
|
||||||
.looped{false},
|
.looped{false},
|
||||||
|
|
@ -159,7 +159,8 @@ TEST_CASE("confirm transition changes work", "[animation-new]") {
|
||||||
animation::init();
|
animation::init();
|
||||||
|
|
||||||
auto sprite = *textures::get_sprite("rat_king_boss").sprite;
|
auto sprite = *textures::get_sprite("rat_king_boss").sprite;
|
||||||
auto pos = sprite.getPosition();
|
sf::Vector2f pos{100,100};
|
||||||
|
sprite.setPosition(pos);
|
||||||
auto scale = sprite.getScale();
|
auto scale = sprite.getScale();
|
||||||
auto anim = crafter();
|
auto anim = crafter();
|
||||||
|
|
||||||
|
|
@ -167,6 +168,7 @@ TEST_CASE("confirm transition changes work", "[animation-new]") {
|
||||||
REQUIRE(anim.onFrame == nullptr);
|
REQUIRE(anim.onFrame == nullptr);
|
||||||
|
|
||||||
anim.play();
|
anim.play();
|
||||||
|
REQUIRE(anim.playing == true);
|
||||||
|
|
||||||
sf::Clock clock;
|
sf::Clock clock;
|
||||||
clock.start();
|
clock.start();
|
||||||
|
|
@ -188,7 +190,7 @@ TEST_CASE("confirm transition changes work", "[animation-new]") {
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(anim.playing == false);
|
REQUIRE(anim.playing == false);
|
||||||
REQUIRE(pos != sf::Vector2f{0,0});
|
REQUIRE(pos == sf::Vector2f{100, 100});
|
||||||
REQUIRE(scale != sf::Vector2f{0,0});
|
REQUIRE(scale != sf::Vector2f{0,0});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,149 +5,14 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "shaders.hpp"
|
#include "shaders.hpp"
|
||||||
#include "backend.hpp"
|
#include "backend.hpp"
|
||||||
#include "events.hpp"
|
|
||||||
#include "constants.hpp"
|
#include "constants.hpp"
|
||||||
#include "gui/event_router.hpp"
|
|
||||||
#include "constants.hpp"
|
|
||||||
#include <guecs/ui.hpp>
|
|
||||||
#include "gui/event_router.hpp"
|
|
||||||
#include "gui/guecstra.hpp"
|
|
||||||
#include "animate2.hpp"
|
#include "animate2.hpp"
|
||||||
|
#include "tools/animator.hpp"
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
bool YES_SYNC=true;
|
bool YES_SYNC=true;
|
||||||
|
|
||||||
namespace animator {
|
|
||||||
struct UI {
|
|
||||||
guecs::UI $ui;
|
|
||||||
|
|
||||||
void init(const std::string& sprite_name) {
|
|
||||||
$ui.position(0,0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
||||||
$ui.layout(
|
|
||||||
"[play|*%=(300,400)viewer|_|_]"
|
|
||||||
"[stop|_|_|_]"
|
|
||||||
"[next|_|_|_]"
|
|
||||||
"[prev|_|_|_]");
|
|
||||||
|
|
||||||
for(auto& [name, cell] : $ui.cells()) {
|
|
||||||
auto comp = $ui.entity(name);
|
|
||||||
if(name == "viewer") {
|
|
||||||
$ui.set<guecs::Sprite>(comp, {
|
|
||||||
sprite_name, 0, false});
|
|
||||||
} else {
|
|
||||||
$ui.set<guecs::Rectangle>(comp, {});
|
|
||||||
$ui.set<guecs::Text>(comp, {guecs::to_wstring(name)});
|
|
||||||
$ui.set<guecs::Effect>(comp, {});
|
|
||||||
$ui.set<guecs::Clickable>(comp, {[](auto){
|
|
||||||
fmt::println("I don't know what to do here.");
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$ui.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void render(sf::RenderWindow& window) {
|
|
||||||
$ui.render(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mouse(float x, float y, guecs::Modifiers mods) {
|
|
||||||
return $ui.mouse(x, y, mods);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<sf::Sprite> get_sprite() {
|
|
||||||
auto viewer = $ui.entity("viewer");
|
|
||||||
return $ui.get<guecs::Sprite>(viewer).sprite;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class State {
|
|
||||||
START=__LINE__,
|
|
||||||
ANIMATE=__LINE__,
|
|
||||||
END=__LINE__,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FSM : public DeadSimpleFSM<State, game::Event> {
|
|
||||||
UI $ui;
|
|
||||||
gui::routing::Router $router;
|
|
||||||
sf::RenderWindow $window{sf::VideoMode({SCREEN_WIDTH, SCREEN_HEIGHT}), "Animation Crafting Tool"};
|
|
||||||
|
|
||||||
void init(const std::string &sprite_name) {
|
|
||||||
$ui.init(sprite_name);
|
|
||||||
|
|
||||||
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) {
|
|
||||||
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) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_keyboard_mouse() {
|
|
||||||
while(const auto ev = $window.pollEvent()) {
|
|
||||||
using enum game::Event;
|
|
||||||
auto gui_ev = $router.process_event(ev);
|
|
||||||
auto mouse_pos = $window.mapPixelToCoords($router.position);
|
|
||||||
|
|
||||||
switch(gui_ev) {
|
|
||||||
case MOUSE_CLICK:
|
|
||||||
$ui.mouse(mouse_pos.x, mouse_pos.y, guecs::NO_MODS);
|
|
||||||
break;
|
|
||||||
case MOUSE_MOVE:
|
|
||||||
$ui.mouse(mouse_pos.x, mouse_pos.y, {1 << guecs::ModBit::hover});
|
|
||||||
break;
|
|
||||||
case QUIT:
|
|
||||||
state(State::END);
|
|
||||||
default:
|
|
||||||
break; // ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void render() {
|
|
||||||
$window.clear();
|
|
||||||
$ui.render($window);
|
|
||||||
$window.display();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool active() {
|
|
||||||
return !in_state(State::END);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
animate2::Sheet sheet{
|
animate2::Sheet sheet{
|
||||||
.width{720*2},
|
.width{720*2},
|
||||||
.height{720},
|
.height{720},
|
||||||
|
|
@ -170,7 +35,7 @@ animate2::Transform scale_tr{
|
||||||
.ease_rate{4.0f},
|
.ease_rate{4.0f},
|
||||||
.scaled{true},
|
.scaled{true},
|
||||||
.toggled{false},
|
.toggled{false},
|
||||||
.looped{false},
|
.looped{true},
|
||||||
.easing = ease2::in_out_back,
|
.easing = ease2::in_out_back,
|
||||||
.motion = ease2::move_rush,
|
.motion = ease2::move_rush,
|
||||||
};
|
};
|
||||||
|
|
@ -190,6 +55,148 @@ animate2::Transform move_tr{
|
||||||
.motion = ease2::move_shake,
|
.motion = ease2::move_shake,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
animate2::Animate2 anim{sheet, sequence, scale_tr};
|
||||||
|
|
||||||
|
namespace animator {
|
||||||
|
|
||||||
|
void FSM::init(const std::string &sprite_name) {
|
||||||
|
$ui.init(sprite_name, *this);
|
||||||
|
|
||||||
|
if(YES_SYNC) {
|
||||||
|
$window.setVerticalSyncEnabled(VSYNC);
|
||||||
|
if(FRAME_LIMIT) $window.setFramerateLimit(FRAME_LIMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
$window.setPosition({0,0});
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSM::event(Event ev, std::any data) {
|
||||||
|
switch($state) {
|
||||||
|
FSM_STATE(State, START, ev);
|
||||||
|
FSM_STATE(State, ANIMATE, ev);
|
||||||
|
FSM_STATE(State, END, ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSM::START(Event ev) {
|
||||||
|
switch(ev) {
|
||||||
|
case Event::TICK:
|
||||||
|
state(State::ANIMATE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
state(State::START);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSM::ANIMATE(Event ev) {
|
||||||
|
switch(ev) {
|
||||||
|
case Event::TICK:
|
||||||
|
// stuff
|
||||||
|
break;
|
||||||
|
case Event::PLAY:
|
||||||
|
if(!anim.playing) anim.play();
|
||||||
|
break;
|
||||||
|
case Event::STOP:
|
||||||
|
if(anim.playing) anim.stop();
|
||||||
|
break;
|
||||||
|
case Event::LOOP:
|
||||||
|
anim.$transform.looped = !anim.$transform.looped;
|
||||||
|
break;
|
||||||
|
case Event::TOGGLE:
|
||||||
|
anim.$transform.toggled = !anim.$transform.toggled;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
state(State::START);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSM::END(Event ev) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSM::handle_keyboard_mouse() {
|
||||||
|
while(const auto ev = $window.pollEvent()) {
|
||||||
|
using enum game::Event;
|
||||||
|
auto gui_ev = $router.process_event(ev);
|
||||||
|
auto mouse_pos = $window.mapPixelToCoords($router.position);
|
||||||
|
|
||||||
|
switch(gui_ev) {
|
||||||
|
case MOUSE_CLICK:
|
||||||
|
$ui.mouse(mouse_pos.x, mouse_pos.y, guecs::NO_MODS);
|
||||||
|
break;
|
||||||
|
case MOUSE_MOVE:
|
||||||
|
$ui.mouse(mouse_pos.x, mouse_pos.y, {1 << guecs::ModBit::hover});
|
||||||
|
break;
|
||||||
|
case QUIT:
|
||||||
|
state(State::END);
|
||||||
|
default:
|
||||||
|
break; // ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSM::render() {
|
||||||
|
$window.clear();
|
||||||
|
$ui.render($window);
|
||||||
|
$window.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FSM::active() {
|
||||||
|
return !in_state(State::END);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI::button(const std::string& name, std::function<void(guecs::Modifiers mods)> cb) {
|
||||||
|
auto comp = $ui.entity(name);
|
||||||
|
$ui.set<guecs::Rectangle>(comp, {});
|
||||||
|
$ui.set<guecs::Text>(comp, {guecs::to_wstring(name)});
|
||||||
|
$ui.set<guecs::Effect>(comp, {});
|
||||||
|
$ui.set<guecs::Clickable>(comp, {cb});
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI::init(const std::string& sprite_name, FSM& fsm) {
|
||||||
|
$ui.position(0,0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
|
$ui.layout(
|
||||||
|
"[play|*%=(300,400)viewer|_|_]"
|
||||||
|
"[stop|_|_|_]"
|
||||||
|
"[loop|_|_|_]"
|
||||||
|
"[toggled|_|_|_]");
|
||||||
|
|
||||||
|
auto viewer = $ui.entity("viewer");
|
||||||
|
$ui.set<guecs::Sprite>(viewer, { sprite_name, 0, false});
|
||||||
|
|
||||||
|
button("stop", [&](auto){
|
||||||
|
fsm.event(Event::STOP, {});
|
||||||
|
});
|
||||||
|
|
||||||
|
button("play", [&](auto){
|
||||||
|
fsm.event(Event::PLAY, {});
|
||||||
|
});
|
||||||
|
|
||||||
|
button("loop", [&](auto){
|
||||||
|
fsm.event(Event::LOOP, {});
|
||||||
|
});
|
||||||
|
|
||||||
|
button("toggled", [&](auto){
|
||||||
|
fsm.event(Event::TOGGLE, {});
|
||||||
|
});
|
||||||
|
|
||||||
|
$ui.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI::render(sf::RenderWindow& window) {
|
||||||
|
$ui.render(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UI::mouse(float x, float y, guecs::Modifiers mods) {
|
||||||
|
return $ui.mouse(x, y, mods);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<sf::Sprite> UI::get_sprite() {
|
||||||
|
auto viewer = $ui.entity("viewer");
|
||||||
|
return $ui.get<guecs::Sprite>(viewer).sprite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
shaders::init();
|
shaders::init();
|
||||||
components::init();
|
components::init();
|
||||||
|
|
@ -207,7 +214,6 @@ int main(int argc, char* argv[]) {
|
||||||
animator::FSM main;
|
animator::FSM main;
|
||||||
main.init(argv[1]);
|
main.init(argv[1]);
|
||||||
|
|
||||||
animate2::Animate2 anim{sheet, sequence, scale_tr};
|
|
||||||
anim.play();
|
anim.play();
|
||||||
|
|
||||||
auto sprite = main.$ui.get_sprite();
|
auto sprite = main.$ui.get_sprite();
|
||||||
|
|
@ -220,7 +226,7 @@ int main(int argc, char* argv[]) {
|
||||||
auto [ticks, alpha] = anim.commit();
|
auto [ticks, alpha] = anim.commit();
|
||||||
|
|
||||||
for(int i = 0; i < ticks; i++) {
|
for(int i = 0; i < ticks; i++) {
|
||||||
main.event(game::Event::TICK, {});
|
main.event(animator::Event::TICK, {});
|
||||||
|
|
||||||
if(anim.playing) {
|
if(anim.playing) {
|
||||||
anim.update();
|
anim.update();
|
||||||
|
|
|
||||||
50
tools/animator.hpp
Normal file
50
tools/animator.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#pragma once
|
||||||
|
#include <guecs/ui.hpp>
|
||||||
|
#include "gui/event_router.hpp"
|
||||||
|
#include "gui/guecstra.hpp"
|
||||||
|
#include "events.hpp"
|
||||||
|
|
||||||
|
namespace animator {
|
||||||
|
|
||||||
|
enum class State {
|
||||||
|
START=__LINE__,
|
||||||
|
ANIMATE=__LINE__,
|
||||||
|
END=__LINE__,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Event {
|
||||||
|
TICK=__LINE__,
|
||||||
|
PLAY=__LINE__,
|
||||||
|
STOP=__LINE__,
|
||||||
|
LOOP=__LINE__,
|
||||||
|
TOGGLE=__LINE__,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FSM;
|
||||||
|
|
||||||
|
struct UI {
|
||||||
|
guecs::UI $ui;
|
||||||
|
|
||||||
|
void button(const std::string& name, std::function<void(guecs::Modifiers mods)> cb);
|
||||||
|
void init(const std::string& sprite_name, FSM& fsm);
|
||||||
|
void render(sf::RenderWindow& window);
|
||||||
|
bool mouse(float x, float y, guecs::Modifiers mods);
|
||||||
|
std::shared_ptr<sf::Sprite> get_sprite();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FSM : public DeadSimpleFSM<State, Event> {
|
||||||
|
UI $ui;
|
||||||
|
gui::routing::Router $router;
|
||||||
|
sf::RenderWindow $window{sf::VideoMode({SCREEN_WIDTH, SCREEN_HEIGHT}), "Animation Crafting Tool"};
|
||||||
|
|
||||||
|
void init(const std::string &sprite_name);
|
||||||
|
void event(Event ev, std::any data={});
|
||||||
|
void START(Event ev);
|
||||||
|
void ANIMATE(Event ev);
|
||||||
|
void END(Event ev);
|
||||||
|
void handle_keyboard_mouse();
|
||||||
|
void render();
|
||||||
|
bool active();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue