Fixed animations, jank-noted some issues & workarounds with the Animation python API
This commit is contained in:
parent
c9b97b9b35
commit
620def19f1
|
@ -14,7 +14,7 @@ template<typename T>
|
|||
DiscreteAnimation<T>::DiscreteAnimation(float _d, std::vector<T> _v, std::function<void()> _cb, std::function<void(T)> _w, bool _l)
|
||||
:Animation(_d, _cb, _l), //duration(_d), target(_t), callback(_cb), loop(_l), elapsed(0.0f),
|
||||
index(0), nonelapsed(0.0f), values(_v), write(_w) {
|
||||
timestep = _v.size() / _d;
|
||||
timestep = _d / _v.size();
|
||||
}
|
||||
|
||||
/* // don't call virtual functions (like cancel()) from base class destructor
|
||||
|
@ -47,11 +47,11 @@ void LerpAnimation<float>::lerp() {
|
|||
|
||||
template<>
|
||||
void LerpAnimation<sf::Vector2f>::lerp() {
|
||||
std::cout << "sf::Vector2f implementation of lerp." << std::endl;
|
||||
//std::cout << "sf::Vector2f implementation of lerp." << std::endl;
|
||||
int delta_x = endvalue.x - startvalue.x;
|
||||
int delta_y = endvalue.y - startvalue.y;
|
||||
std::cout << "Start: " << startvalue.x << ", " << startvalue.y << "; End: " << endvalue.x << ", " << endvalue.y << std::endl;
|
||||
std::cout << "Delta: " << delta_x << ", " << delta_y << std::endl;
|
||||
//std::cout << "Start: " << startvalue.x << ", " << startvalue.y << "; End: " << endvalue.x << ", " << endvalue.y << std::endl;
|
||||
//std::cout << "Delta: " << delta_x << ", " << delta_y << std::endl;
|
||||
//((sf::Vector2f*)target)->x = startvalue.x + (elapsed / duration * delta_x);
|
||||
//((sf::Vector2f*)target)->y = startvalue.y + (elapsed / duration * delta_y);
|
||||
write(sf::Vector2f(startvalue.x + (elapsed / duration * delta_x),
|
||||
|
@ -70,24 +70,28 @@ void LerpAnimation<sf::Vector2i>::lerp() {
|
|||
|
||||
template<typename T>
|
||||
void LerpAnimation<T>::step(float delta) {
|
||||
if (complete) return;
|
||||
elapsed += delta;
|
||||
std::cout << "LerpAnimation step function. Elapsed: " << elapsed <<std::endl;
|
||||
//std::cout << "LerpAnimation step function. Elapsed: " << elapsed <<std::endl;
|
||||
lerp();
|
||||
if (isDone()) cancel(); //use the exact value, not my math
|
||||
if (isDone()) { callback(); complete = true; cancel(); }; //use the exact value, not my math
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void DiscreteAnimation<T>::step(float delta)
|
||||
{
|
||||
if (complete) return;
|
||||
nonelapsed += delta;
|
||||
//std::cout << "Nonelapsed: " << nonelapsed << " elapsed (pre-add): " << elapsed << " timestep: " << timestep << " duration: " << duration << " index: " << index << std::endl;
|
||||
if (nonelapsed < timestep) return;
|
||||
if (index == values.size() - 1) return;
|
||||
//std::cout << "values size: " << values.size() << " isDone(): " << isDone() << std::endl;
|
||||
if (elapsed > duration && !complete) {callback(); complete = true; return; }
|
||||
elapsed += nonelapsed; // or should it be += timestep?
|
||||
if (index == values.size() - 1) return;
|
||||
nonelapsed = 0; // or should it -= timestep?
|
||||
index++;
|
||||
//*(T*)target = values[index];
|
||||
write(values[index]);
|
||||
if (isDone()) cancel(); //use the exact value, not my math
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -111,6 +115,7 @@ namespace animation_template_implementations {
|
|||
//LerpAnimation<sf::Vector2f> implement_vector2f;
|
||||
|
||||
auto implement_v2f_const = LerpAnimation<sf::Vector2<float>>(4.0, sf::Vector2<float>(), sf::Vector2f(1,1), [](){}, [](sf::Vector2f v){}, false);
|
||||
auto implement_disc_i = DiscreteAnimation<int>(3.0, std::vector<int>{0},[](){},[](int){},false);
|
||||
//LerpAnimation<sf::Vector2i> implement_vector2i;
|
||||
//LerpAnimation<int> implment_int;
|
||||
//LerpAnimation<std::string> implment_string;
|
||||
|
|
|
@ -9,6 +9,7 @@ protected:
|
|||
float duration, elapsed;
|
||||
std::function<void()> callback;
|
||||
bool loop;
|
||||
bool complete=false;
|
||||
public:
|
||||
//Animation(float, T, T*, std::function<void()>, bool); // lerp
|
||||
//Animation(float, std::vector<T>, T*, std::function<void()>, bool); // discrete
|
||||
|
|
|
@ -630,7 +630,7 @@ PyObject* McRFPy_API::_modGrid(PyObject* self, PyObject* args) {
|
|||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject* McRFPy_API::_createAnimation(PyObject *self, PyObject *args) {
|
||||
PyObject* _test_createAnimation(PyObject *self, PyObject *args) {
|
||||
//LerpAnimation<T>::LerpAnimation(float _d, T _ev, T* _t, std::function<void()> _cb, std::function<void(T)> _w, bool _l)
|
||||
std::string menu_key = "demobox1";
|
||||
McRFPy_API::animations.push_back(
|
||||
|
@ -651,3 +651,122 @@ PyObject* McRFPy_API::_createAnimation(PyObject *self, PyObject *args) {
|
|||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
#define CEQ(A, B) (std::string(A).compare(B) == 0)
|
||||
|
||||
PyObject* McRFPy_API::_createAnimation(PyObject *self, PyObject *args) {
|
||||
std::cout << "Creating animation called..." << std::endl;
|
||||
float duration;
|
||||
const char* parent;
|
||||
const char* target_type;
|
||||
PyObject* target_id_obj;
|
||||
const char* field;
|
||||
PyObject* callback;
|
||||
PyObject* loop_obj;
|
||||
PyObject* values_obj;
|
||||
PyObject* evdata; // for decoding values_obj
|
||||
//std::cout << PyUnicode_AsUTF8(PyObject_Repr(args)) << std::endl;
|
||||
if (!PyArg_ParseTuple(args, "fssOsOOO", &duration, &parent, &target_type, &target_id_obj, &field, &callback, &loop_obj, &values_obj)) { return NULL; }
|
||||
bool loop = PyObject_IsTrue(loop_obj);
|
||||
int target_id = PyLong_AsLong(target_id_obj);
|
||||
Py_INCREF(callback);
|
||||
std::cout << "Animation fields received:" <<
|
||||
"\nduration: " << duration <<
|
||||
"\nparent: " << parent <<
|
||||
"\ntarget type: " << target_type <<
|
||||
"\ntarget id: " << PyUnicode_AsUTF8(PyObject_Repr(target_id_obj)) <<
|
||||
"\nfield: " << field <<
|
||||
"\ncallback: " << PyUnicode_AsUTF8(PyObject_Repr(callback)) <<
|
||||
"\nloop: " << loop <<
|
||||
"\nvalues: " << PyUnicode_AsUTF8(PyObject_Repr(values_obj)) << std::endl;
|
||||
/* Jank alert:
|
||||
* The following block is meant to raise an exception when index is missing from object animations that require one,
|
||||
* but accept the target_id_obj error (and accept None as an index) for menus/grids.
|
||||
* Instead, I get a "latent" exception, not properly raised, when the index is None.
|
||||
* That not-really-raised exception causes other scripts to silently fail to execute
|
||||
* until I go into the REPL and run any code, and get a bizarre, botched traceback.
|
||||
* So, Grid/Menu can just take an index of 0 in the scripts until this is dejankified
|
||||
*/
|
||||
if (!CEQ(target_type, "menu") && !CEQ(target_type, "grid") && target_id == -1) {
|
||||
PyErr_SetObject(PyExc_TypeError, target_id_obj);
|
||||
PyErr_SetString(PyExc_TypeError, "target_id (integer, index value) is required for targets other than 'menu' or 'grid'");
|
||||
return NULL;
|
||||
}
|
||||
// at this point, `values` needs to be decoded based on the `field` provided
|
||||
|
||||
// 3.0, # duration, seconds
|
||||
// "demobox1", # parent: a UIMenu or Grid key
|
||||
// "menu", # target type: 'menu', 'grid', 'caption', 'button', 'sprite', or 'entity'
|
||||
// None, # target id: integer index for menu or grid objs; None for grid/menu
|
||||
// "position", # field: 'position', 'size', 'bgcolor', 'textcolor', or 'sprite'
|
||||
// lambda: self.animation_done("demobox1"), #callback: callable once animation is complete
|
||||
// False, #loop: repeat indefinitely
|
||||
// [100, 100] # values: iterable of frames for 'sprite', lerp target for others
|
||||
|
||||
//LerpAnimation<T>::LerpAnimation(float _d, T _ev, T _sv, std::function<void()> _cb, std::function<void(T)> _w, bool _l)
|
||||
if (CEQ(target_type, "menu")) {
|
||||
auto obj = menus[std::string(parent)];
|
||||
if (CEQ(field, "position")) {
|
||||
if (PyList_Check(values_obj)) evdata = PyList_AsTuple(values_obj); else evdata = values_obj;
|
||||
auto end_value = sf::Vector2f(PyFloat_AsDouble(PyTuple_GetItem(evdata, 0)),
|
||||
PyFloat_AsDouble(PyTuple_GetItem(evdata, 1)));
|
||||
McRFPy_API::animations.push_back(new LerpAnimation<sf::Vector2f>(
|
||||
duration, end_value,
|
||||
obj->box.getPosition(),
|
||||
[=](){PyObject_Call(callback, PyTuple_New(0), NULL);},
|
||||
[=](sf::Vector2f v){obj->box.setPosition(v);},
|
||||
loop)
|
||||
);
|
||||
}
|
||||
else if (CEQ(field, "size")) {
|
||||
if (PyList_Check(values_obj)) evdata = PyList_AsTuple(values_obj); else evdata = values_obj;
|
||||
auto end_value = sf::Vector2f(PyFloat_AsDouble(PyTuple_GetItem(evdata, 0)),
|
||||
PyFloat_AsDouble(PyTuple_GetItem(evdata, 1)));
|
||||
McRFPy_API::animations.push_back(new LerpAnimation<sf::Vector2f>(
|
||||
duration, end_value,
|
||||
obj->box.getSize(),
|
||||
[=](){PyObject_Call(callback, PyTuple_New(0), NULL);},
|
||||
[=](sf::Vector2f v){obj->box.setSize(v);},
|
||||
loop)
|
||||
);
|
||||
}
|
||||
// else if (CEQ(field, "bgcolor")) { )
|
||||
}
|
||||
else if (CEQ(target_type, "sprite")) {
|
||||
auto obj = menus[std::string(parent)]->sprites[target_id];
|
||||
if (CEQ(field, "position")) {
|
||||
PyObject* evdata;
|
||||
if (PyList_Check(values_obj)) evdata = PyList_AsTuple(values_obj); else evdata = values_obj;
|
||||
auto end_value = sf::Vector2f(PyFloat_AsDouble(PyTuple_GetItem(evdata, 0)),
|
||||
PyFloat_AsDouble(PyTuple_GetItem(evdata, 1)));
|
||||
McRFPy_API::animations.push_back(new LerpAnimation<sf::Vector2f>(duration, end_value,
|
||||
sf::Vector2f(obj.x, obj.y),
|
||||
[=](){PyObject_Call(callback, PyTuple_New(0), NULL);},
|
||||
[&](sf::Vector2f v){obj.x = v.x; obj.y = v.y;},
|
||||
loop)
|
||||
);
|
||||
}
|
||||
else if (CEQ(field, "sprite")) {
|
||||
auto obj = menus[std::string(parent)];
|
||||
PyObject* evdata;
|
||||
if (PyList_Check(values_obj)) evdata = PyList_AsTuple(values_obj); else evdata = values_obj;
|
||||
std::vector<int> frames;
|
||||
for (int i = 0; i < PyTuple_Size(evdata); i++) {
|
||||
frames.push_back(PyLong_AsLong(PyTuple_GetItem(evdata, i)));
|
||||
}
|
||||
//DiscreteAnimation(float _d, std::vector<T> _v, std::function<void()> _cb, std::function<void(T)> _w, bool _l)
|
||||
McRFPy_API::animations.push_back(new DiscreteAnimation<int>(
|
||||
duration,
|
||||
frames,
|
||||
[=](){PyObject_Call(callback, PyTuple_New(0), NULL);},
|
||||
[=](int s){obj->sprites[target_id].sprite_index = s;},
|
||||
loop)
|
||||
);
|
||||
std::cout << "Frame animation constructed, there are now " <<McRFPy_API::animations.size() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
|
|
@ -48,11 +48,11 @@ void PythonScene::animate() {
|
|||
auto frametime = game->getFrameTime();
|
||||
auto it = McRFPy_API::animations.begin();
|
||||
while (it != McRFPy_API::animations.end()) {
|
||||
std::cout << "Iterating" << std::endl;
|
||||
//std::cout << "Iterating" << std::endl;
|
||||
(*it)->step(frametime);
|
||||
std::cout << "Step complete" << std::endl;
|
||||
//std::cout << "Step complete" << std::endl;
|
||||
if ((*it)->isDone()) {
|
||||
std::cout << "Cleaning up" << std::endl;
|
||||
std::cout << "Cleaning up Animation" << std::endl;
|
||||
auto prev = it;
|
||||
it++;
|
||||
McRFPy_API::animations.erase(prev);
|
||||
|
|
|
@ -19,10 +19,12 @@ class TestScene:
|
|||
mcrfpy.createMenu(ui_name, 20, 520, 500, 200)
|
||||
mcrfpy.createCaption(ui_name, "Hello There", 18, BLACK)
|
||||
mcrfpy.createCaption(ui_name, "", 18, BLACK)
|
||||
mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKBLUE, (0, 0, 0), "clicky", "testaction")
|
||||
#mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKBLUE, (0, 0, 0), "clicky", "testaction")
|
||||
mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKRED, (0, 0, 0), "REPL", "startrepl")
|
||||
mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKGREEN, (0, 0, 0), "map gen", "gridgen")
|
||||
mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKBLUE, (192, 0, 0), "anim", "animtest")
|
||||
mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKGREEN, (0, 0, 0), "mapL", "gridgen2")
|
||||
mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKBLUE, (192, 0, 0), "a_menu", "animtest")
|
||||
mcrfpy.createButton(ui_name, 250, 20, 100, 50, DARKRED, GREEN, "a_spr", "animtest2")
|
||||
mcrfpy.createSprite(ui_name, 0, randint(0, 3), 300, 20, 5.0)
|
||||
self.menus = mcrfpy.listMenus()
|
||||
self.menus[0].visible = True
|
||||
|
@ -30,9 +32,11 @@ class TestScene:
|
|||
|
||||
# Button behavior
|
||||
self.clicks = 0
|
||||
mcrfpy.registerPyAction("testaction", self.click)
|
||||
#mcrfpy.registerPyAction("testaction", self.click)
|
||||
mcrfpy.registerPyAction("gridgen", self.gridgen)
|
||||
mcrfpy.registerPyAction("animtest", lambda: mcrfpy.createAnimation())
|
||||
mcrfpy.registerPyAction("gridgen2", lambda: self.gridgen())
|
||||
mcrfpy.registerPyAction("animtest", lambda: self.createAnimation())
|
||||
mcrfpy.registerPyAction("animtest2", lambda: self.createAnimation2())
|
||||
|
||||
# create grid (title, gx, gy, gs, x, y, w, h)
|
||||
mcrfpy.createGrid(grid_name, 20, 20, 16, 20, 20, 800, 500)
|
||||
|
@ -51,6 +55,43 @@ class TestScene:
|
|||
print("[Python] Modifying:")
|
||||
self.grids[0].visible = True
|
||||
mcrfpy.modGrid(self.grids[0])
|
||||
|
||||
def animation_done(self, s):
|
||||
print(f"The `{s}` animation completed.")
|
||||
#self.menus = mcrfpy.listMenus()
|
||||
|
||||
# if (!PyArg_ParseTuple(args, "fsssiOOO", &duration, &parent, &target_type, &target_id, &field, &callback, &loop_obj, &values_obj)) return NULL;
|
||||
def createAnimation(self):
|
||||
print(self.menus)
|
||||
self.menus = mcrfpy.listMenus()
|
||||
self.menus[0].w = 500
|
||||
self.menus[0].h = 200
|
||||
print(self.menus)
|
||||
mcrfpy.modMenu(self.menus[0])
|
||||
print(self.menus)
|
||||
mcrfpy.createAnimation(
|
||||
3.0, # duration, seconds
|
||||
"demobox1", # parent: a UIMenu or Grid key
|
||||
"menu", # target type: 'menu', 'grid', 'caption', 'button', 'sprite', or 'entity'
|
||||
0, # target id: integer index for menu or grid objs; None for grid/menu
|
||||
"size", # field: 'position', 'size', 'bgcolor', 'textcolor', or 'sprite'
|
||||
lambda: self.animation_done("demobox1"), #callback: callable once animation is complete
|
||||
False, #loop: repeat indefinitely
|
||||
[150, 100] # values: iterable of frames for 'sprite', lerp target for others
|
||||
)
|
||||
|
||||
def createAnimation2(self):
|
||||
mcrfpy.createAnimation(
|
||||
5,
|
||||
"demobox1",
|
||||
"sprite",
|
||||
0,
|
||||
"sprite",
|
||||
lambda: self.animation_done("sprite change"),
|
||||
False,
|
||||
[0, 1, 2, 1, 2, 0]
|
||||
)
|
||||
|
||||
scene = None
|
||||
def start():
|
||||
global scene
|
||||
|
|
Loading…
Reference in New Issue