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"
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
template<typename T>
Animation<T>::Animation(float _d, T _ev, T* _t, std::function<void()> _cb, bool _l)
:duration(_d), endvalue(_ev), target(_t), callback(_cb), loop(_l),
index(-1), startvalue(*_t), elapsed(0.0f) {}
LerpAnimation<T>::LerpAnimation(float _d, T _ev, T* _t, std::function<void()> _cb, bool _l)
:Animation(_d, _t, _cb, _l), //duration(_d), target(_t), callback(_cb), loop(_l),elapsed(0.0f),
startvalue(*_t), endvalue(_ev) {}
// discrete values constructor
template<typename T>
Animation<T>::Animation(float _d, std::vector<T> _v, T* _t, std::function<void()> _cb, bool _l)
:duration(_d), target(_t), callback(_cb), values(_v), loop(_l),
index(0), startvalue(*_t), elapsed(0.0f), nonelapsed(0.0f) {
DiscreteAnimation<T>::DiscreteAnimation(float _d, std::vector<T> _v, T* _t, std::function<void()> _cb, bool _l)
:Animation(_d, _t, _cb, _l), //duration(_d), target(_t), callback(_cb), loop(_l), elapsed(0.0f),
index(0), nonelapsed(0.0f), values(_v) {
timestep = _v.size() / _d;
}
template<typename T>
Animation<T>::~Animation() {
/* // don't call virtual functions (like cancel()) from base class destructor
* // child classes destructors' are called first anyway
Animation::~Animation() {
// deconstructor sets target to desired end state (no partial values)
cancel();
}
*/
template<>
void Animation<std::string>::lerp() {
*target = endvalue.substr(0, endvalue.length() * (elapsed / duration));
void LerpAnimation<std::string>::lerp() {
*(std::string*)target = endvalue.substr(0, endvalue.length() * (elapsed / duration));
}
template<>
void Animation<int>::lerp() {
void LerpAnimation<int>::lerp() {
int delta = endvalue - startvalue;
*target = startvalue + (elapsed / duration * delta);
*(int*)target = startvalue + (elapsed / duration * delta);
}
template<>
void Animation<float>::lerp() {
void LerpAnimation<float>::lerp() {
int delta = endvalue - startvalue;
*target = startvalue + (elapsed / duration * delta);
*(float*)target = startvalue + (elapsed / duration * delta);
}
template<>
void Animation<sf::Vector2f>::lerp() {
void LerpAnimation<sf::Vector2f>::lerp() {
int delta_x = endvalue.x - startvalue.x;
int delta_y = endvalue.y - startvalue.y;
target->x = startvalue.x + (elapsed / duration * delta_x);
target->y = startvalue.y + (elapsed / duration * delta_y);
((sf::Vector2f*)target)->x = startvalue.x + (elapsed / duration * delta_x);
((sf::Vector2f*)target)->y = startvalue.y + (elapsed / duration * delta_y);
}
template<>
void Animation<sf::Vector2i>::lerp() {
void LerpAnimation<sf::Vector2i>::lerp() {
int delta_x = endvalue.x - startvalue.y;
int delta_y = endvalue.y - startvalue.y;
target->x = startvalue.x + (elapsed / duration * delta_x);
target->y = startvalue.y + (elapsed / duration * delta_y);
((sf::Vector2i*)target)->x = startvalue.x + (elapsed / duration * delta_x);
((sf::Vector2i*)target)->y = startvalue.y + (elapsed / duration * delta_y);
}
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) {
// lerp function
elapsed += delta;
lerp();
}
else {
nonelapsed += delta;
if (nonelapsed < timestep) return;
if (index == values.size() - 1) return;
elapsed += nonelapsed; // or should it be += timestep?
nonelapsed = 0; // or should it -= timestep?
index++;
*target = values[index];
}
nonelapsed += delta;
if (nonelapsed < timestep) return;
if (index == values.size() - 1) return;
elapsed += nonelapsed; // or should it be += timestep?
nonelapsed = 0; // or should it -= timestep?
index++;
*target = values[index];
if (isDone()) cancel(); //use the exact value, not my math
}
template<typename T>
void Animation<T>::cancel() {
if (index == -1)
*target = endvalue;
else
*target = values[values.size() - 1];
void LerpAnimation<T>::cancel() {
*target = endvalue;
}
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
#include "Common.h"
template<typename T>
class Animation
{
protected:
static constexpr float EPSILON = 0.05;
T startvalue, endvalue;
int index;
float duration, elapsed, nonelapsed, timestep;
T* target;
std::vector<T> values;
float duration, elapsed;
void* target;
std::function<void()> callback;
bool loop;
public:
Animation(float, T, T*, std::function<void()>, bool); // lerp
Animation(float, std::vector<T>, T*, std::function<void()>, bool); // discrete
~Animation();
void lerp();
void step(float);
void cancel();
//Animation(float, T, T*, std::function<void()>, bool); // lerp
//Animation(float, std::vector<T>, T*, std::function<void()>, bool); // discrete
Animation(float, void*, std::function<void()>, bool);
virtual void step(float) = 0;
virtual void cancel() = 0;
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");
IndexSprite::game = this;
clock.restart();
}
Scene* GameEngine::currentScene() { return scenes[scene]; }
@ -38,6 +40,7 @@ sf::RenderWindow & GameEngine::getWindow() { return window; }
void GameEngine::run()
{
clock.restart();
while (running)
{
currentScene()->update();
@ -47,6 +50,7 @@ void GameEngine::run()
}
currentScene()->sRender();
currentFrame++;
frameTime = clock.restart().asSeconds();
}
}

View File

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

View File

@ -7,6 +7,8 @@
std::map<std::string, UIMenu*> McRFPy_API::menus;
std::map<std::string, Grid*> McRFPy_API::grids;
std::map<std::string, PyObject*> McRFPy_API::callbacks;
std::list<Animation*> McRFPy_API::animations;
EntityManager McRFPy_API::entities;
static PyMethodDef mcrfpyMethods[] = {
@ -46,6 +48,18 @@ static PyMethodDef mcrfpyMethods[] = {
{"modGrid", McRFPy_API::_modGrid, METH_VARARGS,
"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}
};

View File

@ -44,6 +44,7 @@ public:
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 std::map<std::string, Grid*> grids;
static std::list<Animation*> animations;
static std::map<std::string, PyObject*> callbacks;
@ -68,6 +69,8 @@ public:
static PyObject* _createGrid(PyObject*, PyObject*);
static PyObject* _listGrids(PyObject*, PyObject*);
static PyObject* _modGrid(PyObject*, PyObject*);
static PyObject* _createAnimation(PyObject*, PyObject*);
static PyObject* _registerPyAction(PyObject*, PyObject*);

View File

@ -1,6 +1,7 @@
#include "PythonScene.h"
#include "ActionCode.h"
#include "McRFPy_API.h"
#include "Animation.h"
PythonScene::PythonScene(GameEngine* g, std::string pymodule)
: Scene(g) {
@ -42,6 +43,58 @@ PythonScene::PythonScene(GameEngine* g, std::string pymodule)
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() {
McRFPy_API::entities.update();
@ -57,6 +110,7 @@ void PythonScene::update() {
mouseprev = mousepos;
}
animate();
}
void PythonScene::doLClick(sf::Vector2i mousepos) {

View File

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