Add BTPlayAnimation action

This commit is contained in:
Serhii Snitsaruk 2023-08-13 17:34:34 +02:00
parent 10e601fcd5
commit 45cf74dca9
4 changed files with 207 additions and 0 deletions

View File

@ -0,0 +1,138 @@
/**
* bt_play_animation.cpp
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
#include "bt_play_animation.h"
#include "core/math/math_funcs.h"
//**** Setters / Getters
void BTPlayAnimation::set_animation_player(Ref<BBNode> p_animation_player) {
animation_player_param = p_animation_player;
emit_changed();
if (Engine::get_singleton()->is_editor_hint() && animation_player_param.is_valid()) {
animation_player_param->connect(SNAME("changed"), Callable(this, SNAME("emit_changed")));
}
}
void BTPlayAnimation::set_animation_name(StringName p_animation_name) {
animation_name = p_animation_name;
emit_changed();
}
void BTPlayAnimation::set_await_completion(double p_await_completion) {
await_completion = p_await_completion;
emit_changed();
}
void BTPlayAnimation::set_blend(double p_blend) {
blend = p_blend;
emit_changed();
}
void BTPlayAnimation::set_speed(double p_speed) {
speed = p_speed;
emit_changed();
}
void BTPlayAnimation::set_from_end(bool p_from_end) {
from_end = p_from_end;
emit_changed();
}
//**** Task Implementation
String BTPlayAnimation::get_configuration_warning() const {
String warning = BTAction::get_configuration_warning();
if (!warning.is_empty()) {
warning += "\n";
}
if (animation_player_param.is_null()) {
warning += "Animation Player parameter is not set.\n";
} else {
if (animation_player_param->get_value_source() == BBParam::SAVED_VALUE && animation_player_param->get_saved_value().is_zero()) {
warning += "Path to AnimationPlayer node is not set.\n";
} else if (animation_player_param->get_value_source() == BBParam::BLACKBOARD_VAR && animation_player_param->get_variable().is_empty()) {
warning += "AnimationPlayer blackboard variable is not set.\n";
}
}
if (animation_name == StringName()) {
warning += "Animation Name is not set.\n";
}
return warning;
}
String BTPlayAnimation::_generate_name() const {
if (animation_name == StringName() || animation_player_param.is_null()) {
return "PlayAnimation ???";
}
return vformat("PlayAnimation \"%s\"", animation_name) +
(blend >= 0.0 ? vformat(" blend: %ss", Math::snapped(blend, 0.001)) : "") +
(speed != 1.0 ? vformat(" speed: %s", Math::snapped(speed, 0.001)) : "") +
(from_end != false ? vformat(" from_end: %s", from_end) : "") +
(await_completion > 0.0 ? vformat(" await_completion: %ss", Math::snapped(await_completion, 0.001)) : "");
}
void BTPlayAnimation::_setup() {
setup_failed = true;
ERR_FAIL_COND_MSG(animation_player_param.is_null(), "BTPlayAnimation: AnimationPlayer parameter is not set.");
animation_player = Object::cast_to<AnimationPlayer>(animation_player_param->get_value(get_agent(), get_blackboard()));
ERR_FAIL_COND_MSG(animation_player == nullptr, "BTPlayAnimation: Failed to get AnimationPlayer.");
ERR_FAIL_COND_MSG(animation_name == StringName(), "BTPlayAnimation: Animation name is not set.");
ERR_FAIL_COND_MSG(!animation_player->has_animation(animation_name), vformat("BTPlayAnimation: Animation not found: %s", animation_name));
setup_failed = false;
}
void BTPlayAnimation::_enter() {
if (!setup_failed) {
animation_player->play(animation_name, blend, speed, from_end);
}
}
int BTPlayAnimation::_tick(double p_delta) {
ERR_FAIL_COND_V_MSG(setup_failed == true, FAILURE, "BTPlayAnimation: _setup() failed - returning FAILURE.");
// ! Doing this check instead of using signal due to a bug in Godot: https://github.com/godotengine/godot/issues/76127
if (animation_player->is_playing() && animation_player->get_assigned_animation() == animation_name) {
if (get_elapsed_time() < await_completion) {
return RUNNING;
} else if (await_completion > 0.0) {
WARN_PRINT(vformat("BTPlayAnimation: Waiting time for the \"%s\" animation exceeded the allocated %s sec.", animation_name, await_completion));
}
}
return SUCCESS;
}
//**** Godot
void BTPlayAnimation::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_animation_player", "p_anim_player"), &BTPlayAnimation::set_animation_player);
ClassDB::bind_method(D_METHOD("get_animation_player"), &BTPlayAnimation::get_animation_player);
ClassDB::bind_method(D_METHOD("set_animation_name", "p_anim_name"), &BTPlayAnimation::set_animation_name);
ClassDB::bind_method(D_METHOD("get_animation_name"), &BTPlayAnimation::get_animation_name);
ClassDB::bind_method(D_METHOD("set_await_completion", "p_time_sec"), &BTPlayAnimation::set_await_completion);
ClassDB::bind_method(D_METHOD("get_await_completion"), &BTPlayAnimation::get_await_completion);
ClassDB::bind_method(D_METHOD("set_blend", "p_blend"), &BTPlayAnimation::set_blend);
ClassDB::bind_method(D_METHOD("get_blend"), &BTPlayAnimation::get_blend);
ClassDB::bind_method(D_METHOD("set_speed", "p_speed"), &BTPlayAnimation::set_speed);
ClassDB::bind_method(D_METHOD("get_speed"), &BTPlayAnimation::get_speed);
ClassDB::bind_method(D_METHOD("set_from_end", "p_from_end"), &BTPlayAnimation::set_from_end);
ClassDB::bind_method(D_METHOD("get_from_end"), &BTPlayAnimation::get_from_end);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "await_completion", PROPERTY_HINT_RANGE, "0.0,100.0"), "set_await_completion", "get_await_completion");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "animation_player", PROPERTY_HINT_RESOURCE_TYPE, "BBNode"), "set_animation_player", "get_animation_player");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation_name"), "set_animation_name", "get_animation_name");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "blend"), "set_blend", "get_blend");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed"), "set_speed", "get_speed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "from_end"), "set_from_end", "get_from_end");
}

View File

@ -0,0 +1,66 @@
/**
* bt_play_animation.h
* =============================================================================
* Copyright 2021-2023 Serhii Snitsaruk
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
#ifndef BT_PLAY_ANIMATION_H
#define BT_PLAY_ANIMATION_H
#include "bt_action.h"
#include "modules/limboai/blackboard/bb_param/bb_node.h"
#include "core/object/object.h"
#include "scene/animation/animation_player.h"
class BTPlayAnimation : public BTAction {
GDCLASS(BTPlayAnimation, BTAction);
private:
Ref<BBNode> animation_player_param;
StringName animation_name;
double await_completion = 0.0;
double blend = -1.0;
double speed = 1.0;
bool from_end = false;
AnimationPlayer *animation_player = nullptr;
bool setup_failed = false;
protected:
static void _bind_methods();
virtual String _generate_name() const override;
virtual void _setup() override;
virtual void _enter() override;
virtual int _tick(double p_delta) override;
public:
void set_animation_player(Ref<BBNode> p_animation_player);
Ref<BBNode> get_animation_player() const { return animation_player_param; }
void set_animation_name(StringName p_animation_name);
StringName get_animation_name() const { return animation_name; }
void set_await_completion(double p_await_completion);
double get_await_completion() const { return await_completion; }
void set_blend(double p_blend);
double get_blend() const { return blend; }
void set_speed(double p_speed);
double get_speed() const { return speed; }
void set_from_end(bool p_from_end);
bool get_from_end() const { return from_end; }
virtual String get_configuration_warning() const override;
};
#endif // BT_PLAY_ANIMATION

View File

@ -76,6 +76,7 @@ def get_doc_classes():
"BTInvert",
"BTNewScope",
"BTParallel",
"BTPlayAnimation",
"BTPlayer",
"BTProbability",
"BTRandomSelector",

View File

@ -47,6 +47,7 @@
#include "bt/actions/bt_action.h"
#include "bt/actions/bt_console_print.h"
#include "bt/actions/bt_fail.h"
#include "bt/actions/bt_play_animation.h"
#include "bt/actions/bt_random_wait.h"
#include "bt/actions/bt_set_agent_property.h"
#include "bt/actions/bt_set_var.h"
@ -142,6 +143,7 @@ void initialize_limboai_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(BTConsolePrint);
GDREGISTER_CLASS(BTFail);
GDREGISTER_CLASS(BTNewScope);
GDREGISTER_CLASS(BTPlayAnimation);
GDREGISTER_CLASS(BTRandomWait);
GDREGISTER_CLASS(BTSetAgentProperty);
GDREGISTER_CLASS(BTSetVar);