Check in... animations are roughly half built

This commit is contained in:
John McCardle 2023-03-06 20:54:23 -05:00
parent 47e823d5b9
commit d74635ee4e
8 changed files with 167 additions and 52 deletions

View File

@ -1,81 +1,93 @@
#include "Animation.h" #include "Animation.h"
Animation::Animation(float _d, void* _t, std::function<void()> _cb, bool _l)
:duration(_d), target(_t), callback(_cb), loop(_l), elapsed(0.0f) {}
// linear interpolation constructor // linear interpolation constructor
template<typename T> template<typename T>
Animation<T>::Animation(float _d, T _ev, T* _t, std::function<void()> _cb, bool _l) LerpAnimation<T>::LerpAnimation(float _d, T _ev, T* _t, std::function<void()> _cb, bool _l)
:duration(_d), endvalue(_ev), target(_t), callback(_cb), loop(_l), :Animation(_d, _t, _cb, _l), //duration(_d), target(_t), callback(_cb), loop(_l),elapsed(0.0f),
index(-1), startvalue(*_t), elapsed(0.0f) {} startvalue(*_t), endvalue(_ev) {}
// discrete values constructor // discrete values constructor
template<typename T> template<typename T>
Animation<T>::Animation(float _d, std::vector<T> _v, T* _t, std::function<void()> _cb, bool _l) DiscreteAnimation<T>::DiscreteAnimation(float _d, std::vector<T> _v, T* _t, std::function<void()> _cb, bool _l)
:duration(_d), target(_t), callback(_cb), values(_v), loop(_l), :Animation(_d, _t, _cb, _l), //duration(_d), target(_t), callback(_cb), loop(_l), elapsed(0.0f),
index(0), startvalue(*_t), elapsed(0.0f), nonelapsed(0.0f) { index(0), nonelapsed(0.0f), values(_v) {
timestep = _v.size() / _d; timestep = _v.size() / _d;
} }
template<typename T> /* // don't call virtual functions (like cancel()) from base class destructor
Animation<T>::~Animation() { * // child classes destructors' are called first anyway
Animation::~Animation() {
// deconstructor sets target to desired end state (no partial values) // deconstructor sets target to desired end state (no partial values)
cancel(); cancel();
} }
*/
template<> template<>
void Animation<std::string>::lerp() { void LerpAnimation<std::string>::lerp() {
*target = endvalue.substr(0, endvalue.length() * (elapsed / duration)); *(std::string*)target = endvalue.substr(0, endvalue.length() * (elapsed / duration));
} }
template<> template<>
void Animation<int>::lerp() { void LerpAnimation<int>::lerp() {
int delta = endvalue - startvalue; int delta = endvalue - startvalue;
*target = startvalue + (elapsed / duration * delta); *(int*)target = startvalue + (elapsed / duration * delta);
} }
template<> template<>
void Animation<float>::lerp() { void LerpAnimation<float>::lerp() {
int delta = endvalue - startvalue; int delta = endvalue - startvalue;
*target = startvalue + (elapsed / duration * delta); *(float*)target = startvalue + (elapsed / duration * delta);
} }
template<> template<>
void Animation<sf::Vector2f>::lerp() { void LerpAnimation<sf::Vector2f>::lerp() {
int delta_x = endvalue.x - startvalue.x; int delta_x = endvalue.x - startvalue.x;
int delta_y = endvalue.y - startvalue.y; int delta_y = endvalue.y - startvalue.y;
target->x = startvalue.x + (elapsed / duration * delta_x); ((sf::Vector2f*)target)->x = startvalue.x + (elapsed / duration * delta_x);
target->y = startvalue.y + (elapsed / duration * delta_y); ((sf::Vector2f*)target)->y = startvalue.y + (elapsed / duration * delta_y);
} }
template<> template<>
void Animation<sf::Vector2i>::lerp() { void LerpAnimation<sf::Vector2i>::lerp() {
int delta_x = endvalue.x - startvalue.y; int delta_x = endvalue.x - startvalue.y;
int delta_y = endvalue.y - startvalue.y; int delta_y = endvalue.y - startvalue.y;
target->x = startvalue.x + (elapsed / duration * delta_x); ((sf::Vector2i*)target)->x = startvalue.x + (elapsed / duration * delta_x);
target->y = startvalue.y + (elapsed / duration * delta_y); ((sf::Vector2i*)target)->y = startvalue.y + (elapsed / duration * delta_y);
} }
template<typename T> template<typename T>
void Animation<T>::step(float delta) void LerpAnimation<T>::step(float delta) {
elapsed += delta;
lerp();
if (isDone()) cancel(); //use the exact value, not my math
}
template<typename T>
void DiscreteAnimation<T>::step(float delta)
{ {
if (index == -1) { nonelapsed += delta;
// lerp function if (nonelapsed < timestep) return;
elapsed += delta; if (index == values.size() - 1) return;
lerp(); elapsed += nonelapsed; // or should it be += timestep?
} nonelapsed = 0; // or should it -= timestep?
else { index++;
nonelapsed += delta; *target = values[index];
if (nonelapsed < timestep) return; if (isDone()) cancel(); //use the exact value, not my math
if (index == values.size() - 1) return;
elapsed += nonelapsed; // or should it be += timestep?
nonelapsed = 0; // or should it -= timestep?
index++;
*target = values[index];
}
} }
template<typename T> template<typename T>
void Animation<T>::cancel() { void LerpAnimation<T>::cancel() {
if (index == -1) *target = endvalue;
*target = endvalue; }
else
*target = values[values.size() - 1]; template<typename T>
void DiscreteAnimation<T>::cancel() {
*target = values[values.size() - 1];
}
bool Animation::isDone() {
return elapsed + Animation::EPSILON >= duration;
} }

View File

@ -1,23 +1,44 @@
#pragma once #pragma once
#include "Common.h" #include "Common.h"
template<typename T>
class Animation class Animation
{ {
protected:
static constexpr float EPSILON = 0.05; static constexpr float EPSILON = 0.05;
T startvalue, endvalue; float duration, elapsed;
int index; void* target;
float duration, elapsed, nonelapsed, timestep;
T* target;
std::vector<T> values;
std::function<void()> callback; std::function<void()> callback;
bool loop; bool loop;
public: public:
Animation(float, T, T*, std::function<void()>, bool); // lerp //Animation(float, T, T*, std::function<void()>, bool); // lerp
Animation(float, std::vector<T>, T*, std::function<void()>, bool); // discrete //Animation(float, std::vector<T>, T*, std::function<void()>, bool); // discrete
~Animation(); Animation(float, void*, std::function<void()>, bool);
void lerp(); virtual void step(float) = 0;
void step(float); virtual void cancel() = 0;
void cancel();
bool isDone(); bool isDone();
}; };
template<typename T>
class LerpAnimation: public Animation
{
T startvalue, endvalue;
void lerp();
public:
~LerpAnimation() { cancel(); }
LerpAnimation(float, T, T*, std::function<void()>, bool);
void step(float) override final;
void cancel() override final;
};
template<typename T>
class DiscreteAnimation: public Animation
{
std::vector<T> values;
float nonelapsed, timestep;
int index;
public:
DiscreteAnimation(float, std::vector<T>, T*, std::function<void()>, bool);
~DiscreteAnimation() { cancel(); }
void step(float) override final;
void cancel() override final;
};

View File

@ -27,6 +27,8 @@ GameEngine::GameEngine()
scenes["py"] = new PythonScene(this, "TestScene"); scenes["py"] = new PythonScene(this, "TestScene");
IndexSprite::game = this; IndexSprite::game = this;
clock.restart();
} }
Scene* GameEngine::currentScene() { return scenes[scene]; } Scene* GameEngine::currentScene() { return scenes[scene]; }
@ -38,6 +40,7 @@ sf::RenderWindow & GameEngine::getWindow() { return window; }
void GameEngine::run() void GameEngine::run()
{ {
clock.restart();
while (running) while (running)
{ {
currentScene()->update(); currentScene()->update();
@ -47,6 +50,7 @@ void GameEngine::run()
} }
currentScene()->sRender(); currentScene()->sRender();
currentFrame++; currentFrame++;
frameTime = clock.restart().asSeconds();
} }
} }

View File

@ -17,6 +17,8 @@ class GameEngine
bool paused = false; bool paused = false;
int currentFrame = 0; int currentFrame = 0;
sf::View visible; sf::View visible;
sf::Clock clock;
float frameTime;
public: public:
GameEngine(); GameEngine();
@ -29,6 +31,7 @@ public:
void run(); void run();
void sUserInput(); void sUserInput();
int getFrame() { return currentFrame; } int getFrame() { return currentFrame; }
float getFrameTime() { return frameTime; }
sf::View getView() { return visible; } sf::View getView() { return visible; }
// global textures for scripts to access // global textures for scripts to access

View File

@ -7,6 +7,8 @@
std::map<std::string, UIMenu*> McRFPy_API::menus; std::map<std::string, UIMenu*> McRFPy_API::menus;
std::map<std::string, Grid*> McRFPy_API::grids; std::map<std::string, Grid*> McRFPy_API::grids;
std::map<std::string, PyObject*> McRFPy_API::callbacks; std::map<std::string, PyObject*> McRFPy_API::callbacks;
std::list<Animation*> McRFPy_API::animations;
EntityManager McRFPy_API::entities; EntityManager McRFPy_API::entities;
static PyMethodDef mcrfpyMethods[] = { static PyMethodDef mcrfpyMethods[] = {
@ -46,6 +48,18 @@ static PyMethodDef mcrfpyMethods[] = {
{"modGrid", McRFPy_API::_modGrid, METH_VARARGS, {"modGrid", McRFPy_API::_modGrid, METH_VARARGS,
"call with a Grid object to update all fields"}, "call with a Grid object to update all fields"},
{"createAnimation", McRFPy_API::_createAnimation, METH_VARARGS,
"Create a new animation:\n"
"createAnimation(duration:float, parent:string, target_type:string, target_id:string or int, field:string, callback:function, loop:bool, frames:list)\n"
"duration: total animation time in seconds\n"
"parent: the name of a UI menu or grid\n"
"target_type: 'caption', 'button', 'sprite', or 'entity'\n"
"target_id: integer index of the caption or button, or string ID of entity\n"
"field: what to animate. 'position', 'size', 'bgcolor', 'textcolor' or 'sprite'\n"
"callback: called when the animation completes\n"
"loop: if True, animation repeats; if False, animation is deleted\n"
"frames: if animating a sprite, list the frames. For other data types, the value will change in discrete steps at a rate of duration/len(frames).\n"},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };

View File

@ -44,6 +44,7 @@ public:
static std::map<std::string, UIMenu*> menus; static std::map<std::string, UIMenu*> menus;
static EntityManager entities; // this is also kinda good, entities not on the current grid can still act (like monsters following you through doors??) static EntityManager entities; // this is also kinda good, entities not on the current grid can still act (like monsters following you through doors??)
static std::map<std::string, Grid*> grids; static std::map<std::string, Grid*> grids;
static std::list<Animation*> animations;
static std::map<std::string, PyObject*> callbacks; static std::map<std::string, PyObject*> callbacks;
@ -68,6 +69,8 @@ public:
static PyObject* _createGrid(PyObject*, PyObject*); static PyObject* _createGrid(PyObject*, PyObject*);
static PyObject* _listGrids(PyObject*, PyObject*); static PyObject* _listGrids(PyObject*, PyObject*);
static PyObject* _modGrid(PyObject*, PyObject*); static PyObject* _modGrid(PyObject*, PyObject*);
static PyObject* _createAnimation(PyObject*, PyObject*);
static PyObject* _registerPyAction(PyObject*, PyObject*); static PyObject* _registerPyAction(PyObject*, PyObject*);

View File

@ -1,6 +1,7 @@
#include "PythonScene.h" #include "PythonScene.h"
#include "ActionCode.h" #include "ActionCode.h"
#include "McRFPy_API.h" #include "McRFPy_API.h"
#include "Animation.h"
PythonScene::PythonScene(GameEngine* g, std::string pymodule) PythonScene::PythonScene(GameEngine* g, std::string pymodule)
: Scene(g) { : Scene(g) {
@ -42,6 +43,58 @@ PythonScene::PythonScene(GameEngine* g, std::string pymodule)
McRFPy_API::executePyString(pymodule + ".start()"); McRFPy_API::executePyString(pymodule + ".start()");
} }
void PythonScene::animate() {
auto frametime = game->getFrameTime();
auto it = McRFPy_API::animations.begin();
while (it != animations.end()) {
(*it)->step(frametime);
if ((*it)->isDone()) {
auto prev = it;
it++;
animations.erase(prev);
} else it++;
}
/* // workin on it
for (auto p : animations) {
if (p.first == "int") {
((Animation<int>)p.second).step(frametime);
} else if (p.first == "string") {
((Animation<std::string>)p.second).step(frametime);
} else if (p.first == "float") {
((Animation<float>)p.second).step(frametime);
} else if (p.first == "vector2f") {
((Animation<sf::Vector2f>)p.second).step(frametime);
} else if (p.first == "vector2i") {
((Animation<sf::Vector2i>)p.second).step(frametime);
} else if (p.first == "color") {
((Animation<int>)p.second).step(frametime); // TODO
} else {
std::cout << "Animation has label " << p.first << "; no type found" << std::endl;
}
}
auto it = animations.begin();
while (it != animations.end()) {
bool done = false;
if (p.first == "int") {
((Animation<int>)p.second).step(frametime);
} else if (p.first == "string") {
if ((Animation<std::string>)p.second).isDone()
delete (Animation<std::string>)p.second
} else if (p.first == "float") {
((Animation<float>)p.second).step(frametime);
} else if (p.first == "vector2f") {
((Animation<sf::Vector2f>)p.second).step(frametime);
} else if (p.first == "vector2i") {
((Animation<sf::Vector2i>)p.second).step(frametime);
} else if (p.first == "color") {
((Animation<int>)p.second).step(frametime); // TODO
if ((*it).second.isDone()) {
animations.erase(it++);
} else { it++; }
}
*/
}
void PythonScene::update() { void PythonScene::update() {
McRFPy_API::entities.update(); McRFPy_API::entities.update();
@ -57,6 +110,7 @@ void PythonScene::update() {
mouseprev = mousepos; mouseprev = mousepos;
} }
animate();
} }
void PythonScene::doLClick(sf::Vector2i mousepos) { void PythonScene::doLClick(sf::Vector2i mousepos) {

View File

@ -4,6 +4,8 @@
#include "Scene.h" #include "Scene.h"
#include "GameEngine.h" #include "GameEngine.h"
#include "Grid.h" #include "Grid.h"
//#include "Animation.h"
//#include <list>
class PythonScene: public Scene class PythonScene: public Scene
{ {
@ -13,6 +15,8 @@ class PythonScene: public Scene
void doLClick(sf::Vector2i); void doLClick(sf::Vector2i);
void doRClick(sf::Vector2i); void doRClick(sf::Vector2i);
void doZoom(sf::Vector2i, int); void doZoom(sf::Vector2i, int);
//std::list<Animation*> animations;
void animate();
public: public:
PythonScene(GameEngine*, std::string); PythonScene(GameEngine*, std::string);
void update() override final; void update() override final;