Hello everyone,
I just wanted to share with you the code I wrote. I’m still working on it to see what’s missing or wrong. I am open to any kind of improvement/correction from you. I hope it will also help people who use C++.
AnimBlendTask;
typedef struct {
NodePath _node;
AnimControlCollection* _col;
std::string _animFrom;
std::string _animTo;
PN_stdfloat _blend_speed;
int _cycle_count;
int _cycle_limit;
} AnimBlendArgs;
class AnimBlendTask {
public:
AnimBlendTask() {};
void run(AnimBlendArgs* _blend_args) {
_the_task = new GenericAsyncTask("New AnimBlendTask", &do_the_task, _blend_args);
AsyncTaskManager::get_global_ptr()->add(_the_task);
}
protected:
static AsyncTask::DoneStatus do_the_task(GenericAsyncTask* task, void* data) {
if (task->get_elapsed_time() < 0.01) {
return AsyncTask::DS_cont;
}
AnimBlendArgs* _self = static_cast<AnimBlendArgs*>(data);
if(_self->_cycle_count>_self->_cycle_limit){ return AsyncTask::DS_done; }
PartBundle* bundle = DCAST(Character, _self->_node.find("**/+Character").node())->get_bundle(0);
PN_stdfloat _animFrom_CEF = bundle->get_control_effect(_self->_col->find_anim(_self->_animFrom));
PN_stdfloat _animTo_CEF = bundle->get_control_effect(_self->_col->find_anim(_self->_animTo));
std::cout << "Blending [ " << _self->_animFrom << " -> " << _self->_animTo << " ] " << _animFrom_CEF << " -> " << _animTo_CEF << std::endl;
if ((_animTo_CEF>=1.0 && _animFrom_CEF<=0.0) || _self->_animFrom == _self->_animTo) {
bundle->set_control_effect(_self->_col->find_anim(_self->_animFrom), 0.0);
bundle->set_control_effect(_self->_col->find_anim(_self->_animTo), 1.0);
std::cout << "Looping -> " << _self->_animTo << std::endl;
return AsyncTask::DS_done;
}
if (_animFrom_CEF > 0.0) {
bundle->set_control_effect(_self->_col->find_anim(_self->_animFrom), _animFrom_CEF - _self->_blend_speed);
}
if (_animTo_CEF < 1.0) {
bundle->set_control_effect(_self->_col->find_anim(_self->_animTo), _animTo_CEF + _self->_blend_speed);
}
_self->_cycle_count++;
return AsyncTask::DS_again;
}
private:
PT(GenericAsyncTask) _the_task;
};
And here some codes about usage;
playerNP = NodeBase::loadPlayerModel("orc", { 5,5,5 }, { 135,182,0 });
NodeBase::loadAnimToInstance(playerNP, &anim_control_collection, "run");
NodeBase::loadAnimToInstance(playerNP, &anim_control_collection, "idle");
void NodeBase::loadAnimToInstance(NodePath _node, AnimControlCollection* col, const std::string _anim)
{
const string _actual_anim_name = _node.get_name() + "-" + _anim;
const string _anim_path = "bin/neuera/characters/anims/" + _actual_anim_name + ".bam";
NodePath animNP = Engine::loadModelToModel(_node, _anim_path);
animNP.set_name(_actual_anim_name);
AnimControlCollection tmpCol;
auto_bind(_node.node(), tmpCol);
PT(AnimControl) animPtr = tmpCol.get_anim(0);
animPtr->set_name(_actual_anim_name);
animPtr->loop(true);
PartBundle* bundle = DCAST(Character, _node.find("**/+Character").node())->get_bundle(0);
bundle->set_frame_blend_flag(true);
bundle->set_anim_blend_flag(true);
bundle->set_control_effect(animPtr, 0.0);
col->store_anim(animPtr, _actual_anim_name);
string animName = tmpCol.get_anim_name(0);
std::cout << animName << std::endl;
tmpCol.unbind_anim(animName);
animNP.detach_node();
}
void NodeBase::setLoopMotion(NodePath _node, AnimControlCollection* col, const std::string _anim)
{
string _animFrom;
const string _animTo = _node.get_name() + "-" + _anim;
bool not_playing = true;
for (int i = 0; i < col->get_num_anims(); i++)
{
if (col->get_anim(i)->is_playing() && col->get_anim(i)->get_name()!= _animTo) {
not_playing = false;
_animFrom=col->get_anim(i)->get_name();
break;
}
}
if (not_playing) {
PartBundle* bundle = DCAST(Character, _node.find("**/+Character").node())->get_bundle(0);
bundle->set_control_effect(col->find_anim(_animTo), 1.0);
col->loop(_animTo, true);
return;
}
AnimBlendArgs* _blend_args = new AnimBlendArgs;
AnimBlendTask ab;
_blend_args->_node = _node;
_blend_args->_col = col;
_blend_args->_animFrom = _animFrom;
_blend_args->_animTo = _animTo;
_blend_args->_blend_speed = 0.075;
_blend_args->_cycle_count = 0;
_blend_args->_cycle_limit = 15;
ab.run(_blend_args);
}
NodeBase::setLoopMotion(playerNP, &anim_control_collection, "idle");
NodeBase::setLoopMotion(playerNP, &anim_control_collection, "run");