You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-07 12:30:27 +00:00
Massive rewrite to AnimationTree. Many APIs changed in order to:
-Reuse resources -Expose properties in AnimationTree
This commit is contained in:
@@ -5,6 +5,38 @@
|
||||
#include "scene/scene_string_names.h"
|
||||
#include "servers/audio/audio_stream.h"
|
||||
|
||||
|
||||
|
||||
void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const {
|
||||
|
||||
}
|
||||
|
||||
Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const {
|
||||
return Variant();
|
||||
}
|
||||
|
||||
void AnimationNode::set_parameter(const StringName& p_name, const Variant& p_value) {
|
||||
ERR_FAIL_COND(!state);
|
||||
ERR_FAIL_COND(!state->tree->property_parent_map.has(base_path));
|
||||
ERR_FAIL_COND(!state->tree->property_parent_map[base_path].has(p_name));
|
||||
StringName path = state->tree->property_parent_map[base_path][p_name];
|
||||
|
||||
state->tree->property_map[path]=p_value;
|
||||
}
|
||||
|
||||
Variant AnimationNode::get_parameter(const StringName& p_name) const {
|
||||
ERR_FAIL_COND_V(!state,Variant());
|
||||
ERR_FAIL_COND_V(!state->tree->property_parent_map.has(base_path),Variant());
|
||||
ERR_FAIL_COND_V(!state->tree->property_parent_map[base_path].has(p_name),Variant());
|
||||
|
||||
StringName path = state->tree->property_parent_map[base_path][p_name];
|
||||
return state->tree->property_map[path];
|
||||
}
|
||||
|
||||
void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
|
||||
|
||||
}
|
||||
|
||||
void AnimationNode::blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend) {
|
||||
|
||||
ERR_FAIL_COND(!state);
|
||||
@@ -14,8 +46,8 @@ void AnimationNode::blend_animation(const StringName &p_animation, float p_time,
|
||||
|
||||
if (animation.is_null()) {
|
||||
|
||||
Ref<AnimationNodeBlendTree> btree = get_parent();
|
||||
if (btree.is_valid()) {
|
||||
AnimationNodeBlendTree* btree = Object::cast_to<AnimationNodeBlendTree>(parent);
|
||||
if (btree) {
|
||||
String name = btree->get_node_name(Ref<AnimationNodeAnimation>(this));
|
||||
make_invalid(vformat(RTR("In node '%s', invalid animation: '%s'."), name, p_animation));
|
||||
} else {
|
||||
@@ -37,10 +69,20 @@ void AnimationNode::blend_animation(const StringName &p_animation, float p_time,
|
||||
state->animation_states.push_back(anim_state);
|
||||
}
|
||||
|
||||
float AnimationNode::_pre_process(State *p_state, float p_time, bool p_seek) {
|
||||
float AnimationNode::_pre_process(const StringName& p_base_path, AnimationNode *p_parent, State *p_state, float p_time, bool p_seek, const Vector<StringName>& p_connections) {
|
||||
|
||||
base_path = p_base_path;
|
||||
parent = p_parent;
|
||||
connections=p_connections;
|
||||
state = p_state;
|
||||
|
||||
float t = process(p_time, p_seek);
|
||||
|
||||
state = NULL;
|
||||
parent = NULL;
|
||||
base_path = StringName();
|
||||
connections.clear();
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -56,39 +98,31 @@ void AnimationNode::make_invalid(const String &p_reason) {
|
||||
float AnimationNode::blend_input(int p_input, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) {
|
||||
ERR_FAIL_INDEX_V(p_input, inputs.size(), 0);
|
||||
ERR_FAIL_COND_V(!state, 0);
|
||||
ERR_FAIL_COND_V(!get_tree(), 0); //should not happen, but used to catch bugs
|
||||
|
||||
Ref<AnimationNodeBlendTree> tree = get_parent();
|
||||
AnimationNodeBlendTree* blend_tree = Object::cast_to<AnimationNodeBlendTree>(parent);
|
||||
ERR_FAIL_COND_V(!blend_tree,0);
|
||||
|
||||
if (!tree.is_valid() && get_tree()->get_tree_root().ptr() != this) {
|
||||
make_invalid(RTR("Can't blend input because node is not in a tree"));
|
||||
return 0;
|
||||
}
|
||||
StringName node_name = connections[p_input];
|
||||
|
||||
ERR_FAIL_COND_V(!tree.is_valid(), 0); //should not happen
|
||||
|
||||
StringName anim_name = inputs[p_input].connected_to;
|
||||
|
||||
Ref<AnimationNode> node = tree->get_node(anim_name);
|
||||
|
||||
if (node.is_null()) {
|
||||
|
||||
String name = tree->get_node_name(Ref<AnimationNodeAnimation>(this));
|
||||
if (!blend_tree->has_node(node_name)) {
|
||||
String name = blend_tree->get_node_name(Ref<AnimationNode>(this));
|
||||
make_invalid(vformat(RTR("Nothing connected to input '%s' of node '%s'."), get_input_name(p_input), name));
|
||||
return 0;
|
||||
}
|
||||
|
||||
inputs.write[p_input].last_pass = state->last_pass;
|
||||
Ref<AnimationNode> node = blend_tree->get_node(node_name);
|
||||
|
||||
return _blend_node(node, p_time, p_seek, p_blend, p_filter, p_optimize, &inputs.write[p_input].activity);
|
||||
//inputs.write[p_input].last_pass = state->last_pass;
|
||||
float activity;
|
||||
return _blend_node(node_name,blend_tree->get_node_connection_array(node_name),NULL,node, p_time, p_seek, p_blend, p_filter, p_optimize, &activity);
|
||||
}
|
||||
|
||||
float AnimationNode::blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) {
|
||||
float AnimationNode::blend_node(const StringName& p_sub_path,Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) {
|
||||
|
||||
return _blend_node(p_node, p_time, p_seek, p_blend, p_filter, p_optimize);
|
||||
return _blend_node(p_sub_path,Vector<StringName>(),this,p_node, p_time, p_seek, p_blend, p_filter, p_optimize);
|
||||
}
|
||||
|
||||
float AnimationNode::_blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize, float *r_max) {
|
||||
float AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName>& p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize, float *r_max) {
|
||||
|
||||
ERR_FAIL_COND_V(!p_node.is_valid(), 0);
|
||||
ERR_FAIL_COND_V(!state, 0);
|
||||
@@ -189,7 +223,19 @@ float AnimationNode::_blend_node(Ref<AnimationNode> p_node, float p_time, bool p
|
||||
if (!p_seek && p_optimize && !any_valid) //pointless to go on, all are zero
|
||||
return 0;
|
||||
|
||||
return p_node->_pre_process(state, p_time, p_seek);
|
||||
String new_path;
|
||||
AnimationNode *new_parent;
|
||||
|
||||
//this is the slowest part of processing, but as strings process in powers of 2, and the paths always exist, it will not result in that many allocations
|
||||
if (p_new_parent) {
|
||||
new_parent = p_new_parent;
|
||||
new_path = String(base_path)+String(p_subpath)+"/";
|
||||
} else {
|
||||
ERR_FAIL_COND_V(!parent,0);
|
||||
new_parent = parent;
|
||||
new_path = String(parent->base_path) + String(p_subpath)+"/";
|
||||
}
|
||||
return p_node->_pre_process(new_path,new_parent,state, p_time, p_seek, p_connections);
|
||||
}
|
||||
|
||||
int AnimationNode::get_input_count() const {
|
||||
@@ -201,28 +247,6 @@ String AnimationNode::get_input_name(int p_input) {
|
||||
return inputs[p_input].name;
|
||||
}
|
||||
|
||||
float AnimationNode::get_input_activity(int p_input) const {
|
||||
|
||||
ERR_FAIL_INDEX_V(p_input, inputs.size(), 0);
|
||||
if (!get_tree())
|
||||
return 0;
|
||||
|
||||
if (get_tree()->get_last_process_pass() != inputs[p_input].last_pass) {
|
||||
return 0;
|
||||
}
|
||||
return inputs[p_input].activity;
|
||||
}
|
||||
StringName AnimationNode::get_input_connection(int p_input) {
|
||||
|
||||
ERR_FAIL_INDEX_V(p_input, inputs.size(), StringName());
|
||||
return inputs[p_input].connected_to;
|
||||
}
|
||||
|
||||
void AnimationNode::set_input_connection(int p_input, const StringName &p_connection) {
|
||||
|
||||
ERR_FAIL_INDEX(p_input, inputs.size());
|
||||
inputs.write[p_input].connected_to = p_connection;
|
||||
}
|
||||
|
||||
String AnimationNode::get_caption() const {
|
||||
|
||||
@@ -239,8 +263,6 @@ void AnimationNode::add_input(const String &p_name) {
|
||||
Input input;
|
||||
ERR_FAIL_COND(p_name.find(".") != -1 || p_name.find("/") != -1);
|
||||
input.name = p_name;
|
||||
input.activity = 0;
|
||||
input.last_pass = 0;
|
||||
inputs.push_back(input);
|
||||
emit_changed();
|
||||
}
|
||||
@@ -258,35 +280,6 @@ void AnimationNode::remove_input(int p_index) {
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void AnimationNode::_set_parent(Object *p_parent) {
|
||||
set_parent(Object::cast_to<AnimationNode>(p_parent));
|
||||
}
|
||||
|
||||
void AnimationNode::set_parent(AnimationNode *p_parent) {
|
||||
parent = p_parent; //do not use ref because parent contains children
|
||||
if (get_script_instance()) {
|
||||
get_script_instance()->call("_parent_set", p_parent);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<AnimationNode> AnimationNode::get_parent() const {
|
||||
if (parent) {
|
||||
return Ref<AnimationNode>(parent);
|
||||
}
|
||||
|
||||
return Ref<AnimationNode>();
|
||||
}
|
||||
|
||||
AnimationTree *AnimationNode::get_tree() const {
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
AnimationPlayer *AnimationNode::get_player() const {
|
||||
ERR_FAIL_COND_V(!state, NULL);
|
||||
return state->player;
|
||||
}
|
||||
|
||||
float AnimationNode::process(float p_time, bool p_seek) {
|
||||
|
||||
if (get_script_instance()) {
|
||||
@@ -320,21 +313,7 @@ bool AnimationNode::has_filter() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void AnimationNode::set_position(const Vector2 &p_position) {
|
||||
position = p_position;
|
||||
}
|
||||
|
||||
Vector2 AnimationNode::get_position() const {
|
||||
return position;
|
||||
}
|
||||
|
||||
void AnimationNode::set_tree(AnimationTree *p_player) {
|
||||
|
||||
if (player != NULL && p_player == NULL) {
|
||||
emit_signal("removed_from_graph");
|
||||
}
|
||||
player = p_player;
|
||||
}
|
||||
|
||||
Array AnimationNode::_get_filters() const {
|
||||
|
||||
@@ -361,12 +340,14 @@ void AnimationNode::_validate_property(PropertyInfo &property) const {
|
||||
}
|
||||
}
|
||||
|
||||
Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) {
|
||||
return Ref<AnimationNode>();
|
||||
}
|
||||
|
||||
void AnimationNode::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_input_count"), &AnimationNode::get_input_count);
|
||||
ClassDB::bind_method(D_METHOD("get_input_name", "input"), &AnimationNode::get_input_name);
|
||||
ClassDB::bind_method(D_METHOD("get_input_connection", "input"), &AnimationNode::get_input_connection);
|
||||
ClassDB::bind_method(D_METHOD("get_input_activity", "input"), &AnimationNode::get_input_activity);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("add_input", "name"), &AnimationNode::add_input);
|
||||
ClassDB::bind_method(D_METHOD("remove_input", "index"), &AnimationNode::remove_input);
|
||||
@@ -377,19 +358,16 @@ void AnimationNode::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_filter_enabled", "enable"), &AnimationNode::set_filter_enabled);
|
||||
ClassDB::bind_method(D_METHOD("is_filter_enabled"), &AnimationNode::is_filter_enabled);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_position", "position"), &AnimationNode::set_position);
|
||||
ClassDB::bind_method(D_METHOD("get_position"), &AnimationNode::get_position);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_set_filters", "filters"), &AnimationNode::_set_filters);
|
||||
ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "blend"), &AnimationNode::blend_animation);
|
||||
ClassDB::bind_method(D_METHOD("blend_node", "node", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
|
||||
ClassDB::bind_method(D_METHOD("blend_node", "name","node", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
|
||||
ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_parent", "parent"), &AnimationNode::_set_parent);
|
||||
ClassDB::bind_method(D_METHOD("get_parent"), &AnimationNode::get_parent);
|
||||
ClassDB::bind_method(D_METHOD("get_tree"), &AnimationNode::get_tree);
|
||||
ClassDB::bind_method(D_METHOD("set_parameter","name","value"), &AnimationNode::set_parameter);
|
||||
ClassDB::bind_method(D_METHOD("get_parameter","name"), &AnimationNode::get_parameter);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_filter_enabled", "is_filter_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "filters", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_filters", "_get_filters");
|
||||
@@ -397,9 +375,11 @@ void AnimationNode::_bind_methods() {
|
||||
BIND_VMETHOD(MethodInfo("process", PropertyInfo(Variant::REAL, "time"), PropertyInfo(Variant::BOOL, "seek")));
|
||||
BIND_VMETHOD(MethodInfo(Variant::STRING, "get_caption"));
|
||||
BIND_VMETHOD(MethodInfo(Variant::STRING, "has_filter"));
|
||||
BIND_VMETHOD(MethodInfo("_parent_set", PropertyInfo(Variant::OBJECT, "parent")));
|
||||
|
||||
ADD_SIGNAL(MethodInfo("removed_from_graph"));
|
||||
|
||||
ADD_SIGNAL(MethodInfo("tree_changed"));
|
||||
|
||||
BIND_ENUM_CONSTANT(FILTER_IGNORE);
|
||||
BIND_ENUM_CONSTANT(FILTER_PASS);
|
||||
BIND_ENUM_CONSTANT(FILTER_STOP);
|
||||
@@ -410,8 +390,6 @@ AnimationNode::AnimationNode() {
|
||||
|
||||
state = NULL;
|
||||
parent = NULL;
|
||||
player = NULL;
|
||||
set_local_to_scene(true);
|
||||
filter_enabled = false;
|
||||
}
|
||||
|
||||
@@ -420,18 +398,17 @@ AnimationNode::AnimationNode() {
|
||||
void AnimationTree::set_tree_root(const Ref<AnimationNode> &p_root) {
|
||||
|
||||
if (root.is_valid()) {
|
||||
root->set_tree(NULL);
|
||||
}
|
||||
if (p_root.is_valid()) {
|
||||
ERR_EXPLAIN("root node already set to another player");
|
||||
ERR_FAIL_COND(p_root->player);
|
||||
root->disconnect("tree_changed",this,"_tree_changed");
|
||||
}
|
||||
|
||||
root = p_root;
|
||||
|
||||
if (root.is_valid()) {
|
||||
root->set_tree(this);
|
||||
root->connect("tree_changed",this,"_tree_changed");
|
||||
}
|
||||
|
||||
properties_dirty=true;
|
||||
|
||||
update_configuration_warning();
|
||||
}
|
||||
|
||||
@@ -699,7 +676,10 @@ void AnimationTree::_clear_caches() {
|
||||
|
||||
void AnimationTree::_process_graph(float p_delta) {
|
||||
|
||||
_update_properties(); //if properties need updating, update them
|
||||
|
||||
//check all tracks, see if they need modification
|
||||
|
||||
root_motion_transform = Transform();
|
||||
|
||||
if (!root.is_valid()) {
|
||||
@@ -741,6 +721,7 @@ void AnimationTree::_process_graph(float p_delta) {
|
||||
state.valid = true;
|
||||
state.player = player;
|
||||
state.last_pass = process_pass;
|
||||
state.tree = this;
|
||||
|
||||
// root source blends
|
||||
|
||||
@@ -757,11 +738,11 @@ void AnimationTree::_process_graph(float p_delta) {
|
||||
|
||||
if (started) {
|
||||
//if started, seek
|
||||
root->_pre_process(&state, 0, true);
|
||||
root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path,NULL,&state, 0, true,Vector<StringName>());
|
||||
started = false;
|
||||
}
|
||||
|
||||
root->_pre_process(&state, p_delta, false);
|
||||
root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path,NULL,&state, p_delta, false,Vector<StringName>());
|
||||
}
|
||||
|
||||
if (!state.valid) {
|
||||
@@ -1297,6 +1278,117 @@ Transform AnimationTree::get_root_motion_transform() const {
|
||||
return root_motion_transform;
|
||||
}
|
||||
|
||||
void AnimationTree::_tree_changed() {
|
||||
if (properties_dirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
call_deferred("_update_properties");
|
||||
properties_dirty=true;
|
||||
}
|
||||
|
||||
void AnimationTree::_update_properties_for_node(const String& p_base_path,Ref<AnimationNode> node) {
|
||||
|
||||
if (!property_parent_map.has(p_base_path)) {
|
||||
property_parent_map[p_base_path]=HashMap<StringName, StringName>();
|
||||
}
|
||||
|
||||
List<PropertyInfo> plist;
|
||||
node->get_parameter_list(&plist);
|
||||
for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
|
||||
PropertyInfo pinfo = E->get();
|
||||
|
||||
StringName key = pinfo.name;
|
||||
|
||||
if (!property_map.has(p_base_path +key)) {
|
||||
property_map[p_base_path + key] = node->get_parameter_default_value(key);
|
||||
}
|
||||
|
||||
property_parent_map[p_base_path][key]=p_base_path+key;
|
||||
|
||||
pinfo.name = p_base_path + key;
|
||||
properties.push_back(pinfo);
|
||||
}
|
||||
|
||||
List<AnimationNode::ChildNode> children;
|
||||
node->get_child_nodes(&children);
|
||||
|
||||
for (List<AnimationNode::ChildNode>::Element *E=children.front();E;E=E->next()) {
|
||||
_update_properties_for_node(p_base_path+E->get().name+"/",E->get().node);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationTree::_update_properties() {
|
||||
if (!properties_dirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
properties.clear();
|
||||
property_parent_map.clear();
|
||||
|
||||
if (root.is_valid()) {
|
||||
_update_properties_for_node(SceneStringNames::get_singleton()->parameters_base_path,root);
|
||||
}
|
||||
|
||||
properties_dirty = false;
|
||||
|
||||
_change_notify();
|
||||
}
|
||||
|
||||
bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) {
|
||||
if (properties_dirty) {
|
||||
_update_properties();
|
||||
}
|
||||
|
||||
if (property_map.has(p_name)) {
|
||||
property_map[p_name]=p_value;
|
||||
#ifdef TOOLS_ENABLED
|
||||
_change_notify(p_name.operator String().utf8().get_data());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AnimationTree::_get(const StringName &p_name, Variant &r_ret) const {
|
||||
if (properties_dirty) {
|
||||
const_cast<AnimationTree*>(this)->_update_properties();
|
||||
}
|
||||
|
||||
if (property_map.has(p_name)) {
|
||||
r_ret=property_map[p_name];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
void AnimationTree::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
if (properties_dirty) {
|
||||
const_cast<AnimationTree*>(this)->_update_properties();
|
||||
}
|
||||
|
||||
for (const List<PropertyInfo>::Element *E=properties.front();E;E=E->next()) {
|
||||
p_list->push_back(E->get());
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationTree::rename_parameter(const String& p_base,const String& p_new_base) {
|
||||
|
||||
//rename values first
|
||||
for (const List<PropertyInfo>::Element *E=properties.front();E;E=E->next()) {
|
||||
if (E->get().name.begins_with(p_base)) {
|
||||
String new_name = E->get().name.replace_first(p_base,p_new_base);
|
||||
property_map[new_name]=property_map[E->get().name];
|
||||
}
|
||||
}
|
||||
|
||||
//update tree second
|
||||
properties_dirty=true;
|
||||
_update_properties();
|
||||
}
|
||||
|
||||
void AnimationTree::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_active", "active"), &AnimationTree::set_active);
|
||||
ClassDB::bind_method(D_METHOD("is_active"), &AnimationTree::is_active);
|
||||
@@ -1315,11 +1407,17 @@ void AnimationTree::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_root_motion_transform"), &AnimationTree::get_root_motion_transform);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationTree::_tree_changed);
|
||||
ClassDB::bind_method(D_METHOD("_update_properties"), &AnimationTree::_update_properties);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("rename_parameter","old_name","new_name"), &AnimationTree::rename_parameter);
|
||||
|
||||
|
||||
ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationTree::advance);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationTree::_node_removed);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_tree_root", "get_tree_root");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode"), "set_tree_root", "get_tree_root");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_mode", "get_process_mode");
|
||||
@@ -1338,10 +1436,9 @@ AnimationTree::AnimationTree() {
|
||||
cache_valid = false;
|
||||
setup_pass = 1;
|
||||
started = true;
|
||||
properties_dirty = true;
|
||||
}
|
||||
|
||||
AnimationTree::~AnimationTree() {
|
||||
if (root.is_valid()) {
|
||||
root->player = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user