Allow AnimationNodes to restart when transitioning to the same state
This commit is contained in:
parent
8bfaf098c7
commit
e480262c53
|
@ -49,6 +49,13 @@
|
||||||
When inheriting from [AnimationRootNode], implement this virtual method to return whether the blend tree editor should display filter editing on this node.
|
When inheriting from [AnimationRootNode], implement this virtual method to return whether the blend tree editor should display filter editing on this node.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="_is_parameter_read_only" qualifiers="virtual const">
|
||||||
|
<return type="bool" />
|
||||||
|
<param index="0" name="parameter" type="StringName" />
|
||||||
|
<description>
|
||||||
|
When inheriting from [AnimationRootNode], implement this virtual method to return whether the [param parameter] is read-only. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="_process" qualifiers="virtual const">
|
<method name="_process" qualifiers="virtual const">
|
||||||
<return type="float" />
|
<return type="float" />
|
||||||
<param index="0" name="time" type="float" />
|
<param index="0" name="time" type="float" />
|
||||||
|
|
|
@ -28,6 +28,12 @@
|
||||||
</member>
|
</member>
|
||||||
</members>
|
</members>
|
||||||
<constants>
|
<constants>
|
||||||
|
<constant name="ONE_SHOT_REQUEST_NONE" value="0" enum="OneShotRequest">
|
||||||
|
</constant>
|
||||||
|
<constant name="ONE_SHOT_REQUEST_FIRE" value="1" enum="OneShotRequest">
|
||||||
|
</constant>
|
||||||
|
<constant name="ONE_SHOT_REQUEST_ABORT" value="2" enum="OneShotRequest">
|
||||||
|
</constant>
|
||||||
<constant name="MIX_MODE_BLEND" value="0" enum="MixMode">
|
<constant name="MIX_MODE_BLEND" value="0" enum="MixMode">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="MIX_MODE_ADD" value="1" enum="MixMode">
|
<constant name="MIX_MODE_ADD" value="1" enum="MixMode">
|
||||||
|
|
|
@ -12,6 +12,12 @@
|
||||||
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
|
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
<methods>
|
<methods>
|
||||||
|
<method name="find_input_caption" qualifiers="const">
|
||||||
|
<return type="int" />
|
||||||
|
<param index="0" name="caption" type="String" />
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="get_input_caption" qualifiers="const">
|
<method name="get_input_caption" qualifiers="const">
|
||||||
<return type="String" />
|
<return type="String" />
|
||||||
<param index="0" name="input" type="int" />
|
<param index="0" name="input" type="int" />
|
||||||
|
|
|
@ -342,12 +342,17 @@ void EditorPropertyTextEnum::_notification(int p_what) {
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorPropertyTextEnum::EditorPropertyTextEnum() {
|
EditorPropertyTextEnum::EditorPropertyTextEnum() {
|
||||||
|
HBoxContainer *hb = memnew(HBoxContainer);
|
||||||
|
add_child(hb);
|
||||||
|
|
||||||
default_layout = memnew(HBoxContainer);
|
default_layout = memnew(HBoxContainer);
|
||||||
add_child(default_layout);
|
default_layout->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||||
|
hb->add_child(default_layout);
|
||||||
|
|
||||||
edit_custom_layout = memnew(HBoxContainer);
|
edit_custom_layout = memnew(HBoxContainer);
|
||||||
|
edit_custom_layout->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||||
edit_custom_layout->hide();
|
edit_custom_layout->hide();
|
||||||
add_child(edit_custom_layout);
|
hb->add_child(edit_custom_layout);
|
||||||
|
|
||||||
option_button = memnew(OptionButton);
|
option_button = memnew(OptionButton);
|
||||||
option_button->set_h_size_flags(SIZE_EXPAND_FILL);
|
option_button->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||||
|
|
|
@ -187,7 +187,7 @@ void AnimationNodeBlendTreeEditor::update_graph() {
|
||||||
String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E) + "/" + F.name;
|
String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E) + "/" + F.name;
|
||||||
EditorProperty *prop = EditorInspector::instantiate_property_editor(tree, F.type, base_path, F.hint, F.hint_string, F.usage);
|
EditorProperty *prop = EditorInspector::instantiate_property_editor(tree, F.type, base_path, F.hint, F.hint_string, F.usage);
|
||||||
if (prop) {
|
if (prop) {
|
||||||
prop->set_read_only(read_only);
|
prop->set_read_only(read_only || (F.usage & PROPERTY_USAGE_READ_ONLY));
|
||||||
prop->set_object_and_property(tree, base_path);
|
prop->set_object_and_property(tree, base_path);
|
||||||
prop->update_property();
|
prop->update_property();
|
||||||
prop->set_name_split_ratio(0);
|
prop->set_name_split_ratio(0);
|
||||||
|
|
|
@ -229,15 +229,17 @@ AnimationNodeSync::AnimationNodeSync() {
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
|
void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
|
||||||
r_list->push_back(PropertyInfo(Variant::BOOL, active));
|
r_list->push_back(PropertyInfo(Variant::BOOL, active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY));
|
||||||
r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
r_list->push_back(PropertyInfo(Variant::INT, request, PROPERTY_HINT_ENUM, ",Fire,Abort"));
|
||||||
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||||
r_list->push_back(PropertyInfo(Variant::FLOAT, remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
r_list->push_back(PropertyInfo(Variant::FLOAT, remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||||
r_list->push_back(PropertyInfo(Variant::FLOAT, time_to_restart, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
r_list->push_back(PropertyInfo(Variant::FLOAT, time_to_restart, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||||
}
|
}
|
||||||
|
|
||||||
Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const {
|
Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const {
|
||||||
if (p_parameter == active || p_parameter == prev_active) {
|
if (p_parameter == request) {
|
||||||
|
return ONE_SHOT_REQUEST_NONE;
|
||||||
|
} else if (p_parameter == active) {
|
||||||
return false;
|
return false;
|
||||||
} else if (p_parameter == time_to_restart) {
|
} else if (p_parameter == time_to_restart) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -246,6 +248,13 @@ Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_pa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AnimationNodeOneShot::is_parameter_read_only(const StringName &p_parameter) const {
|
||||||
|
if (p_parameter == active) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void AnimationNodeOneShot::set_fadein_time(double p_time) {
|
void AnimationNodeOneShot::set_fadein_time(double p_time) {
|
||||||
fade_in = p_time;
|
fade_in = p_time;
|
||||||
}
|
}
|
||||||
|
@ -303,41 +312,42 @@ bool AnimationNodeOneShot::has_filter() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
||||||
|
OneShotRequest cur_request = static_cast<OneShotRequest>((int)get_parameter(request));
|
||||||
bool cur_active = get_parameter(active);
|
bool cur_active = get_parameter(active);
|
||||||
bool cur_prev_active = get_parameter(prev_active);
|
|
||||||
double cur_time = get_parameter(time);
|
double cur_time = get_parameter(time);
|
||||||
double cur_remaining = get_parameter(remaining);
|
double cur_remaining = get_parameter(remaining);
|
||||||
double cur_time_to_restart = get_parameter(time_to_restart);
|
double cur_time_to_restart = get_parameter(time_to_restart);
|
||||||
|
|
||||||
if (!cur_active) {
|
set_parameter(request, ONE_SHOT_REQUEST_NONE);
|
||||||
//make it as if this node doesn't exist, pass input 0 by.
|
|
||||||
if (cur_prev_active) {
|
bool do_start = cur_request == ONE_SHOT_REQUEST_FIRE;
|
||||||
set_parameter(prev_active, false);
|
if (cur_request == ONE_SHOT_REQUEST_ABORT) {
|
||||||
}
|
set_parameter(active, false);
|
||||||
|
set_parameter(time_to_restart, -1);
|
||||||
|
return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
|
||||||
|
} else if (!do_start && !cur_active) {
|
||||||
if (cur_time_to_restart >= 0.0 && !p_seek) {
|
if (cur_time_to_restart >= 0.0 && !p_seek) {
|
||||||
cur_time_to_restart -= p_time;
|
cur_time_to_restart -= p_time;
|
||||||
if (cur_time_to_restart < 0) {
|
if (cur_time_to_restart < 0) {
|
||||||
//restart
|
do_start = true; // Restart.
|
||||||
set_parameter(active, true);
|
|
||||||
cur_active = true;
|
|
||||||
}
|
}
|
||||||
set_parameter(time_to_restart, cur_time_to_restart);
|
set_parameter(time_to_restart, cur_time_to_restart);
|
||||||
}
|
}
|
||||||
|
if (!do_start) {
|
||||||
return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
|
return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool os_seek = p_seek;
|
bool os_seek = p_seek;
|
||||||
|
|
||||||
if (p_seek) {
|
if (p_seek) {
|
||||||
cur_time = p_time;
|
cur_time = p_time;
|
||||||
}
|
}
|
||||||
bool do_start = !cur_prev_active;
|
|
||||||
|
|
||||||
if (do_start) {
|
if (do_start) {
|
||||||
cur_time = 0;
|
cur_time = 0;
|
||||||
os_seek = true;
|
os_seek = true;
|
||||||
set_parameter(prev_active, true);
|
set_parameter(request, ONE_SHOT_REQUEST_NONE);
|
||||||
|
set_parameter(active, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
real_t blend;
|
real_t blend;
|
||||||
|
@ -375,7 +385,6 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_exter
|
||||||
cur_remaining = os_rem;
|
cur_remaining = os_rem;
|
||||||
if (cur_remaining <= 0) {
|
if (cur_remaining <= 0) {
|
||||||
set_parameter(active, false);
|
set_parameter(active, false);
|
||||||
set_parameter(prev_active, false);
|
|
||||||
if (autorestart) {
|
if (autorestart) {
|
||||||
double restart_sec = autorestart_delay + Math::randd() * autorestart_random_delay;
|
double restart_sec = autorestart_delay + Math::randd() * autorestart_random_delay;
|
||||||
set_parameter(time_to_restart, restart_sec);
|
set_parameter(time_to_restart, restart_sec);
|
||||||
|
@ -419,6 +428,10 @@ void AnimationNodeOneShot::_bind_methods() {
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_delay", "get_autorestart_delay");
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_delay", "get_autorestart_delay");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_random_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_random_delay", "get_autorestart_random_delay");
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_random_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_random_delay", "get_autorestart_random_delay");
|
||||||
|
|
||||||
|
BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_NONE);
|
||||||
|
BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_FIRE);
|
||||||
|
BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_ABORT);
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(MIX_MODE_BLEND);
|
BIND_ENUM_CONSTANT(MIX_MODE_BLEND);
|
||||||
BIND_ENUM_CONSTANT(MIX_MODE_ADD);
|
BIND_ENUM_CONSTANT(MIX_MODE_ADD);
|
||||||
}
|
}
|
||||||
|
@ -640,9 +653,10 @@ void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) con
|
||||||
anims += inputs[i].name;
|
anims += inputs[i].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
r_list->push_back(PropertyInfo(Variant::INT, current, PROPERTY_HINT_ENUM, anims));
|
r_list->push_back(PropertyInfo(Variant::STRING, current_state, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY)); // For interface.
|
||||||
r_list->push_back(PropertyInfo(Variant::INT, prev_current, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
r_list->push_back(PropertyInfo(Variant::STRING, transition_request, PROPERTY_HINT_ENUM, anims)); // For transition request. It will be cleared after setting the value immediately.
|
||||||
r_list->push_back(PropertyInfo(Variant::INT, prev, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
r_list->push_back(PropertyInfo(Variant::INT, current_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY)); // To avoid finding the index every frame, use this internally.
|
||||||
|
r_list->push_back(PropertyInfo(Variant::INT, prev_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||||
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||||
r_list->push_back(PropertyInfo(Variant::FLOAT, prev_xfading, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
r_list->push_back(PropertyInfo(Variant::FLOAT, prev_xfading, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||||
}
|
}
|
||||||
|
@ -650,13 +664,22 @@ void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) con
|
||||||
Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const {
|
Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const {
|
||||||
if (p_parameter == time || p_parameter == prev_xfading) {
|
if (p_parameter == time || p_parameter == prev_xfading) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
} else if (p_parameter == prev || p_parameter == prev_current) {
|
} else if (p_parameter == prev_index) {
|
||||||
return -1;
|
return -1;
|
||||||
|
} else if (p_parameter == transition_request || p_parameter == current_state) {
|
||||||
|
return String();
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AnimationNodeTransition::is_parameter_read_only(const StringName &p_parameter) const {
|
||||||
|
if (p_parameter == current_state || p_parameter == current_index) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
String AnimationNodeTransition::get_caption() const {
|
String AnimationNodeTransition::get_caption() const {
|
||||||
return "Transition";
|
return "Transition";
|
||||||
}
|
}
|
||||||
|
@ -702,6 +725,17 @@ String AnimationNodeTransition::get_input_caption(int p_input) const {
|
||||||
return inputs[p_input].name;
|
return inputs[p_input].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int AnimationNodeTransition::find_input_caption(const String &p_name) const {
|
||||||
|
int idx = -1;
|
||||||
|
for (int i = 0; i < MAX_INPUTS; i++) {
|
||||||
|
if (inputs[i].name == p_name) {
|
||||||
|
idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
void AnimationNodeTransition::set_xfade_time(double p_fade) {
|
void AnimationNodeTransition::set_xfade_time(double p_fade) {
|
||||||
xfade_time = p_fade;
|
xfade_time = p_fade;
|
||||||
}
|
}
|
||||||
|
@ -727,26 +761,53 @@ bool AnimationNodeTransition::is_reset() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
||||||
int cur_current = get_parameter(current);
|
String cur_transition_request = get_parameter(transition_request);
|
||||||
int cur_prev = get_parameter(prev);
|
int cur_current_index = get_parameter(current_index);
|
||||||
int cur_prev_current = get_parameter(prev_current);
|
int cur_prev_index = get_parameter(prev_index);
|
||||||
|
|
||||||
double cur_time = get_parameter(time);
|
double cur_time = get_parameter(time);
|
||||||
double cur_prev_xfading = get_parameter(prev_xfading);
|
double cur_prev_xfading = get_parameter(prev_xfading);
|
||||||
|
|
||||||
bool switched = cur_current != cur_prev_current;
|
bool switched = false;
|
||||||
|
bool restart = false;
|
||||||
|
|
||||||
if (switched) {
|
if (!cur_transition_request.is_empty()) {
|
||||||
set_parameter(prev_current, cur_current);
|
int new_idx = find_input_caption(cur_transition_request);
|
||||||
set_parameter(prev, cur_prev_current);
|
if (new_idx >= 0) {
|
||||||
|
if (cur_current_index == new_idx) {
|
||||||
cur_prev = cur_prev_current;
|
// Transition to same state.
|
||||||
cur_prev_xfading = xfade_time;
|
restart = reset;
|
||||||
cur_time = 0;
|
cur_prev_xfading = 0;
|
||||||
|
set_parameter(prev_xfading, 0);
|
||||||
|
cur_prev_index = -1;
|
||||||
|
set_parameter(prev_index, -1);
|
||||||
|
} else {
|
||||||
switched = true;
|
switched = true;
|
||||||
|
cur_prev_index = cur_current_index;
|
||||||
|
set_parameter(prev_index, cur_current_index);
|
||||||
|
}
|
||||||
|
cur_current_index = new_idx;
|
||||||
|
set_parameter(current_index, cur_current_index);
|
||||||
|
set_parameter(current_state, cur_transition_request);
|
||||||
|
} else {
|
||||||
|
ERR_PRINT("No such input: '" + cur_transition_request + "'");
|
||||||
|
}
|
||||||
|
cur_transition_request = String();
|
||||||
|
set_parameter(transition_request, cur_transition_request);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cur_current < 0 || cur_current >= enabled_inputs || cur_prev >= enabled_inputs) {
|
// Special case for restart.
|
||||||
|
if (restart) {
|
||||||
|
set_parameter(time, 0);
|
||||||
|
return blend_input(cur_current_index, 0, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switched) {
|
||||||
|
cur_prev_xfading = xfade_time;
|
||||||
|
cur_time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur_current_index < 0 || cur_current_index >= enabled_inputs || cur_prev_index >= enabled_inputs) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -754,15 +815,15 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
|
||||||
|
|
||||||
if (sync) {
|
if (sync) {
|
||||||
for (int i = 0; i < enabled_inputs; i++) {
|
for (int i = 0; i < enabled_inputs; i++) {
|
||||||
if (i != cur_current && i != cur_prev) {
|
if (i != cur_current_index && i != cur_prev_index) {
|
||||||
blend_input(i, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
|
blend_input(i, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cur_prev < 0) { // process current animation, check for transition
|
if (cur_prev_index < 0) { // process current animation, check for transition
|
||||||
|
|
||||||
rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
||||||
|
|
||||||
if (p_seek) {
|
if (p_seek) {
|
||||||
cur_time = p_time;
|
cur_time = p_time;
|
||||||
|
@ -770,8 +831,8 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
|
||||||
cur_time += p_time;
|
cur_time += p_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputs[cur_current].auto_advance && rem <= xfade_time) {
|
if (inputs[cur_current_index].auto_advance && rem <= xfade_time) {
|
||||||
set_parameter(current, (cur_current + 1) % enabled_inputs);
|
set_parameter(transition_request, get_input_caption((cur_current_index + 1) % enabled_inputs));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else { // cross-fading from prev to current
|
} else { // cross-fading from prev to current
|
||||||
|
@ -784,20 +845,20 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
|
||||||
// Blend values must be more than CMP_EPSILON to process discrete keys in edge.
|
// Blend values must be more than CMP_EPSILON to process discrete keys in edge.
|
||||||
real_t blend_inv = 1.0 - blend;
|
real_t blend_inv = 1.0 - blend;
|
||||||
if (reset && !p_seek && switched) { //just switched, seek to start of current
|
if (reset && !p_seek && switched) { //just switched, seek to start of current
|
||||||
rem = blend_input(cur_current, 0, true, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
|
rem = blend_input(cur_current_index, 0, true, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
|
||||||
} else {
|
} else {
|
||||||
rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
|
rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_seek) {
|
if (p_seek) {
|
||||||
blend_input(cur_prev, p_time, true, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true);
|
blend_input(cur_prev_index, p_time, true, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true);
|
||||||
cur_time = p_time;
|
cur_time = p_time;
|
||||||
} else {
|
} else {
|
||||||
blend_input(cur_prev, p_time, false, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true);
|
blend_input(cur_prev_index, p_time, false, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true);
|
||||||
cur_time += p_time;
|
cur_time += p_time;
|
||||||
cur_prev_xfading -= p_time;
|
cur_prev_xfading -= p_time;
|
||||||
if (cur_prev_xfading < 0) {
|
if (cur_prev_xfading < 0) {
|
||||||
set_parameter(prev, -1);
|
set_parameter(prev_index, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -829,6 +890,7 @@ void AnimationNodeTransition::_bind_methods() {
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption);
|
ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption);
|
||||||
ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption);
|
ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption);
|
||||||
|
ClassDB::bind_method(D_METHOD("find_input_caption", "caption"), &AnimationNodeTransition::find_input_caption);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_xfade_time", "time"), &AnimationNodeTransition::set_xfade_time);
|
ClassDB::bind_method(D_METHOD("set_xfade_time", "time"), &AnimationNodeTransition::set_xfade_time);
|
||||||
ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeTransition::get_xfade_time);
|
ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeTransition::get_xfade_time);
|
||||||
|
|
|
@ -96,6 +96,12 @@ class AnimationNodeOneShot : public AnimationNodeSync {
|
||||||
GDCLASS(AnimationNodeOneShot, AnimationNodeSync);
|
GDCLASS(AnimationNodeOneShot, AnimationNodeSync);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum OneShotRequest {
|
||||||
|
ONE_SHOT_REQUEST_NONE,
|
||||||
|
ONE_SHOT_REQUEST_FIRE,
|
||||||
|
ONE_SHOT_REQUEST_ABORT,
|
||||||
|
};
|
||||||
|
|
||||||
enum MixMode {
|
enum MixMode {
|
||||||
MIX_MODE_BLEND,
|
MIX_MODE_BLEND,
|
||||||
MIX_MODE_ADD
|
MIX_MODE_ADD
|
||||||
|
@ -110,13 +116,8 @@ private:
|
||||||
double autorestart_random_delay = 0.0;
|
double autorestart_random_delay = 0.0;
|
||||||
MixMode mix = MIX_MODE_BLEND;
|
MixMode mix = MIX_MODE_BLEND;
|
||||||
|
|
||||||
/* bool active;
|
StringName request = PNAME("request");
|
||||||
bool do_start;
|
|
||||||
double time;
|
|
||||||
double remaining;*/
|
|
||||||
|
|
||||||
StringName active = PNAME("active");
|
StringName active = PNAME("active");
|
||||||
StringName prev_active = "prev_active";
|
|
||||||
StringName time = "time";
|
StringName time = "time";
|
||||||
StringName remaining = "remaining";
|
StringName remaining = "remaining";
|
||||||
StringName time_to_restart = "time_to_restart";
|
StringName time_to_restart = "time_to_restart";
|
||||||
|
@ -127,6 +128,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
|
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
|
||||||
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
|
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
|
||||||
|
virtual bool is_parameter_read_only(const StringName &p_parameter) const override;
|
||||||
|
|
||||||
virtual String get_caption() const override;
|
virtual String get_caption() const override;
|
||||||
|
|
||||||
|
@ -153,6 +155,7 @@ public:
|
||||||
AnimationNodeOneShot();
|
AnimationNodeOneShot();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
VARIANT_ENUM_CAST(AnimationNodeOneShot::OneShotRequest)
|
||||||
VARIANT_ENUM_CAST(AnimationNodeOneShot::MixMode)
|
VARIANT_ENUM_CAST(AnimationNodeOneShot::MixMode)
|
||||||
|
|
||||||
class AnimationNodeAdd2 : public AnimationNodeSync {
|
class AnimationNodeAdd2 : public AnimationNodeSync {
|
||||||
|
@ -284,18 +287,15 @@ class AnimationNodeTransition : public AnimationNodeSync {
|
||||||
InputData inputs[MAX_INPUTS];
|
InputData inputs[MAX_INPUTS];
|
||||||
int enabled_inputs = 0;
|
int enabled_inputs = 0;
|
||||||
|
|
||||||
/*
|
|
||||||
double prev_xfading;
|
|
||||||
int prev;
|
|
||||||
double time;
|
|
||||||
int current;
|
|
||||||
int prev_current; */
|
|
||||||
|
|
||||||
StringName prev_xfading = "prev_xfading";
|
|
||||||
StringName prev = "prev";
|
|
||||||
StringName time = "time";
|
StringName time = "time";
|
||||||
StringName current = PNAME("current");
|
StringName prev_xfading = "prev_xfading";
|
||||||
StringName prev_current = "prev_current";
|
StringName prev_index = "prev_index";
|
||||||
|
StringName current_index = PNAME("current_index");
|
||||||
|
StringName current_state = PNAME("current_state");
|
||||||
|
StringName transition_request = PNAME("transition_request");
|
||||||
|
|
||||||
|
StringName prev_frame_current = "pf_current";
|
||||||
|
StringName prev_frame_current_idx = "pf_current_idx";
|
||||||
|
|
||||||
double xfade_time = 0.0;
|
double xfade_time = 0.0;
|
||||||
Ref<Curve> xfade_curve;
|
Ref<Curve> xfade_curve;
|
||||||
|
@ -310,6 +310,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
|
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
|
||||||
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
|
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
|
||||||
|
virtual bool is_parameter_read_only(const StringName &p_parameter) const override;
|
||||||
|
|
||||||
virtual String get_caption() const override;
|
virtual String get_caption() const override;
|
||||||
|
|
||||||
|
@ -321,6 +322,7 @@ public:
|
||||||
|
|
||||||
void set_input_caption(int p_input, const String &p_name);
|
void set_input_caption(int p_input, const String &p_name);
|
||||||
String get_input_caption(int p_input) const;
|
String get_input_caption(int p_input) const;
|
||||||
|
int find_input_caption(const String &p_name) const;
|
||||||
|
|
||||||
void set_xfade_time(double p_fade);
|
void set_xfade_time(double p_fade);
|
||||||
double get_xfade_time() const;
|
double get_xfade_time() const;
|
||||||
|
|
|
@ -236,7 +236,7 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta
|
||||||
path.clear(); //a new one will be needed
|
path.clear(); //a new one will be needed
|
||||||
|
|
||||||
if (current == p_travel) {
|
if (current == p_travel) {
|
||||||
return true; //nothing to do
|
return false; // Will teleport oneself (restart).
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 current_pos = p_state_machine->states[current].position;
|
Vector2 current_pos = p_state_machine->states[current].position;
|
||||||
|
|
|
@ -54,13 +54,19 @@ Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AnimationNode::is_parameter_read_only(const StringName &p_parameter) const {
|
||||||
|
bool ret = false;
|
||||||
|
GDVIRTUAL_CALL(_is_parameter_read_only, p_parameter, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_value) {
|
void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_value) {
|
||||||
ERR_FAIL_COND(!state);
|
ERR_FAIL_COND(!state);
|
||||||
ERR_FAIL_COND(!state->tree->property_parent_map.has(base_path));
|
ERR_FAIL_COND(!state->tree->property_parent_map.has(base_path));
|
||||||
ERR_FAIL_COND(!state->tree->property_parent_map[base_path].has(p_name));
|
ERR_FAIL_COND(!state->tree->property_parent_map[base_path].has(p_name));
|
||||||
StringName path = state->tree->property_parent_map[base_path][p_name];
|
StringName path = state->tree->property_parent_map[base_path][p_name];
|
||||||
|
|
||||||
state->tree->property_map[path] = p_value;
|
state->tree->property_map[path].first = p_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Variant AnimationNode::get_parameter(const StringName &p_name) const {
|
Variant AnimationNode::get_parameter(const StringName &p_name) const {
|
||||||
|
@ -69,7 +75,7 @@ Variant AnimationNode::get_parameter(const StringName &p_name) const {
|
||||||
ERR_FAIL_COND_V(!state->tree->property_parent_map[base_path].has(p_name), 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];
|
StringName path = state->tree->property_parent_map[base_path][p_name];
|
||||||
return state->tree->property_map[path];
|
return state->tree->property_map[path].first;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
|
void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
|
||||||
|
@ -427,6 +433,7 @@ void AnimationNode::_bind_methods() {
|
||||||
GDVIRTUAL_BIND(_get_parameter_list);
|
GDVIRTUAL_BIND(_get_parameter_list);
|
||||||
GDVIRTUAL_BIND(_get_child_by_name, "name");
|
GDVIRTUAL_BIND(_get_child_by_name, "name");
|
||||||
GDVIRTUAL_BIND(_get_parameter_default_value, "parameter");
|
GDVIRTUAL_BIND(_get_parameter_default_value, "parameter");
|
||||||
|
GDVIRTUAL_BIND(_is_parameter_read_only, "parameter");
|
||||||
GDVIRTUAL_BIND(_process, "time", "seek", "is_external_seeking");
|
GDVIRTUAL_BIND(_process, "time", "seek", "is_external_seeking");
|
||||||
GDVIRTUAL_BIND(_get_caption);
|
GDVIRTUAL_BIND(_get_caption);
|
||||||
GDVIRTUAL_BIND(_has_filter);
|
GDVIRTUAL_BIND(_has_filter);
|
||||||
|
@ -1889,7 +1896,10 @@ void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<A
|
||||||
StringName key = pinfo.name;
|
StringName key = pinfo.name;
|
||||||
|
|
||||||
if (!property_map.has(p_base_path + key)) {
|
if (!property_map.has(p_base_path + key)) {
|
||||||
property_map[p_base_path + key] = node->get_parameter_default_value(key);
|
Pair<Variant, bool> param;
|
||||||
|
param.first = node->get_parameter_default_value(key);
|
||||||
|
param.second = node->is_parameter_read_only(key);
|
||||||
|
property_map[p_base_path + key] = param;
|
||||||
}
|
}
|
||||||
|
|
||||||
property_parent_map[p_base_path][key] = p_base_path + key;
|
property_parent_map[p_base_path][key] = p_base_path + key;
|
||||||
|
@ -1931,7 +1941,10 @@ bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property_map.has(p_name)) {
|
if (property_map.has(p_name)) {
|
||||||
property_map[p_name] = p_value;
|
if (is_inside_tree() && property_map[p_name].second) {
|
||||||
|
return false; // Prevent to set property by user.
|
||||||
|
}
|
||||||
|
property_map[p_name].first = p_value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1944,7 +1957,7 @@ bool AnimationTree::_get(const StringName &p_name, Variant &r_ret) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property_map.has(p_name)) {
|
if (property_map.has(p_name)) {
|
||||||
r_ret = property_map[p_name];
|
r_ret = property_map[p_name].first;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,7 @@ protected:
|
||||||
GDVIRTUAL0RC(Array, _get_parameter_list)
|
GDVIRTUAL0RC(Array, _get_parameter_list)
|
||||||
GDVIRTUAL1RC(Ref<AnimationNode>, _get_child_by_name, StringName)
|
GDVIRTUAL1RC(Ref<AnimationNode>, _get_child_by_name, StringName)
|
||||||
GDVIRTUAL1RC(Variant, _get_parameter_default_value, StringName)
|
GDVIRTUAL1RC(Variant, _get_parameter_default_value, StringName)
|
||||||
|
GDVIRTUAL1RC(bool, _is_parameter_read_only, StringName)
|
||||||
GDVIRTUAL3RC(double, _process, double, bool, bool)
|
GDVIRTUAL3RC(double, _process, double, bool, bool)
|
||||||
GDVIRTUAL0RC(String, _get_caption)
|
GDVIRTUAL0RC(String, _get_caption)
|
||||||
GDVIRTUAL0RC(bool, _has_filter)
|
GDVIRTUAL0RC(bool, _has_filter)
|
||||||
|
@ -124,6 +125,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
|
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
|
||||||
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
|
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
|
||||||
|
virtual bool is_parameter_read_only(const StringName &p_parameter) const;
|
||||||
|
|
||||||
void set_parameter(const StringName &p_name, const Variant &p_value);
|
void set_parameter(const StringName &p_name, const Variant &p_value);
|
||||||
Variant get_parameter(const StringName &p_name) const;
|
Variant get_parameter(const StringName &p_name) const;
|
||||||
|
@ -304,7 +306,7 @@ private:
|
||||||
void _update_properties();
|
void _update_properties();
|
||||||
List<PropertyInfo> properties;
|
List<PropertyInfo> properties;
|
||||||
HashMap<StringName, HashMap<StringName, StringName>> property_parent_map;
|
HashMap<StringName, HashMap<StringName, StringName>> property_parent_map;
|
||||||
HashMap<StringName, Variant> property_map;
|
HashMap<StringName, Pair<Variant, bool>> property_map; // Property value and read-only flag.
|
||||||
|
|
||||||
struct Activity {
|
struct Activity {
|
||||||
uint64_t last_pass = 0;
|
uint64_t last_pass = 0;
|
||||||
|
|
Loading…
Reference in New Issue