[CLASS] AnimBlendTask - Animation blending with task

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");
2 Likes