Merge pull request #63026 from Xwdit/improve_scene_tree_timer

Some improvements to the SceneTreeTimer
This commit is contained in:
Rémi Verschelde 2022-09-03 18:23:28 +02:00 committed by GitHub
commit 5d628e4108
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 35 deletions

View file

@ -58,8 +58,13 @@
<return type="SceneTreeTimer" />
<param index="0" name="time_sec" type="float" />
<param index="1" name="process_always" type="bool" default="true" />
<param index="2" name="process_in_physics" type="bool" default="false" />
<param index="3" name="ignore_time_scale" type="bool" default="false" />
<description>
Returns a [SceneTreeTimer] which will [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this [SceneTree]. If [param process_always] is set to [code]false[/code], pausing the [SceneTree] will also pause the timer.
Returns a [SceneTreeTimer] which will [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this [SceneTree].
If [code]process_always[/code] is set to [code]false[/code], pausing the [SceneTree] will also pause the timer.
If [code]process_in_physics[/code] is set to [code]true[/code], will update the [SceneTreeTimer] during the physics frame instead of the process frame (fixed framerate processing).
If [code]ignore_time_scale[/code] is set to [code]true[/code], will ignore [member Engine.time_scale] and update the [SceneTreeTimer] with the actual frame delta.
Commonly used to create a one-shot delay timer as in the following example:
[codeblocks]
[gdscript]

View file

@ -88,6 +88,14 @@ bool SceneTreeTimer::is_process_always() {
return process_always;
}
void SceneTreeTimer::set_process_in_physics(bool p_process_in_physics) {
process_in_physics = p_process_in_physics;
}
bool SceneTreeTimer::is_process_in_physics() {
return process_in_physics;
}
void SceneTreeTimer::set_ignore_time_scale(bool p_ignore) {
ignore_time_scale = p_ignore;
}
@ -420,6 +428,8 @@ bool SceneTree::physics_process(double p_time) {
_flush_ugc();
MessageQueue::get_singleton()->flush(); //small little hack
process_timers(p_time, true); //go through timers
process_tweens(p_time, true);
flush_transform_notifications();
@ -462,37 +472,7 @@ bool SceneTree::process(double p_time) {
_flush_delete_queue();
//go through timers
List<Ref<SceneTreeTimer>>::Element *L = timers.back(); //last element
for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) {
List<Ref<SceneTreeTimer>>::Element *N = E->next();
if (paused && !E->get()->is_process_always()) {
if (E == L) {
break; //break on last, so if new timers were added during list traversal, ignore them.
}
E = N;
continue;
}
double time_left = E->get()->get_time_left();
if (E->get()->is_ignore_time_scale()) {
time_left -= Engine::get_singleton()->get_process_step();
} else {
time_left -= p_time;
}
E->get()->set_time_left(time_left);
if (time_left <= 0) {
E->get()->emit_signal(SNAME("timeout"));
timers.erase(E);
}
if (E == L) {
break; //break on last, so if new timers were added during list traversal, ignore them.
}
E = N;
}
process_timers(p_time, false); //go through timers
process_tweens(p_time, false);
@ -530,6 +510,38 @@ bool SceneTree::process(double p_time) {
return _quit;
}
void SceneTree::process_timers(float p_delta, bool p_physics_frame) {
List<Ref<SceneTreeTimer>>::Element *L = timers.back(); //last element
for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) {
List<Ref<SceneTreeTimer>>::Element *N = E->next();
if ((paused && !E->get()->is_process_always()) || (E->get()->is_process_in_physics() != p_physics_frame)) {
if (E == L) {
break; //break on last, so if new timers were added during list traversal, ignore them.
}
E = N;
continue;
}
double time_left = E->get()->get_time_left();
if (E->get()->is_ignore_time_scale()) {
time_left -= Engine::get_singleton()->get_process_step();
} else {
time_left -= p_delta;
}
E->get()->set_time_left(time_left);
if (time_left <= 0) {
E->get()->emit_signal(SNAME("timeout"));
timers.erase(E);
}
if (E == L) {
break; //break on last, so if new timers were added during list traversal, ignore them.
}
E = N;
}
}
void SceneTree::process_tweens(float p_delta, bool p_physics) {
// This methods works similarly to how SceneTreeTimers are handled.
List<Ref<Tween>>::Element *L = tweens.back();
@ -1157,11 +1169,13 @@ void SceneTree::add_current_scene(Node *p_current) {
root->add_child(p_current);
}
Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always) {
Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always, bool p_process_in_physics, bool p_ignore_time_scale) {
Ref<SceneTreeTimer> stt;
stt.instantiate();
stt->set_process_always(p_process_always);
stt->set_time_left(p_delay_sec);
stt->set_process_in_physics(p_process_in_physics);
stt->set_ignore_time_scale(p_ignore_time_scale);
timers.push_back(stt);
return stt;
}
@ -1259,7 +1273,7 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause);
ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused);
ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "process_always"), &SceneTree::create_timer, DEFVAL(true));
ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "process_always", "process_in_physics", "ignore_time_scale"), &SceneTree::create_timer, DEFVAL(true), DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("create_tween"), &SceneTree::create_tween);
ClassDB::bind_method(D_METHOD("get_processed_tweens"), &SceneTree::get_processed_tweens);

View file

@ -53,6 +53,7 @@ class SceneTreeTimer : public RefCounted {
double time_left = 0.0;
bool process_always = true;
bool process_in_physics = false;
bool ignore_time_scale = false;
protected:
@ -65,6 +66,9 @@ public:
void set_process_always(bool p_process_always);
bool is_process_always();
void set_process_in_physics(bool p_process_in_physics);
bool is_process_in_physics();
void set_ignore_time_scale(bool p_ignore);
bool is_ignore_time_scale();
@ -176,6 +180,7 @@ private:
void node_added(Node *p_node);
void node_removed(Node *p_node);
void node_renamed(Node *p_node);
void process_timers(float p_delta, bool p_physics_frame);
void process_tweens(float p_delta, bool p_physics_frame);
Group *add_to_group(const StringName &p_group, Node *p_node);
@ -365,7 +370,7 @@ public:
Error change_scene_to(const Ref<PackedScene> &p_scene);
Error reload_current_scene();
Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true);
Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true, bool p_process_in_physics = false, bool p_ignore_time_scale = false);
Ref<Tween> create_tween();
TypedArray<Tween> get_processed_tweens();