Skip to content

Commit ad582ac

Browse files
committed
Initial + Implements frame Timer
1 parent 3302f80 commit ad582ac

File tree

3 files changed

+92
-13
lines changed

3 files changed

+92
-13
lines changed

doc/classes/Timer.xml

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
Without requiring much code, a timer node can be added and configured in the editor. The [signal timeout] signal it emits can also be connected through the Node dock in the editor:
1010
[codeblock]
1111
func _on_timer_timeout():
12-
print("Time to attack!")
12+
print("Time to attack!")
1313
[/codeblock]
1414
[b]Note:[/b] To create a one-shot timer without instantiating a node, use [method SceneTree.create_timer].
15-
[b]Note:[/b] Timers are affected by [member Engine.time_scale]. The higher the time scale, the sooner timers will end. How often a timer processes may depend on the framerate or [member Engine.physics_ticks_per_second].
15+
[b]Note:[/b] Timers in Time mode are affected by [member Engine.time_scale]. The higher the time scale, the sooner timers will end. How often a timer processes may depend on the framerate or [member Engine.physics_ticks_per_second].
1616
</description>
1717
<tutorials>
1818
<link title="2D Dodge The Creeps Demo">https://godotengine.org/asset-library/asset/2712</link>
@@ -53,13 +53,17 @@
5353
<member name="process_callback" type="int" setter="set_timer_process_callback" getter="get_timer_process_callback" enum="Timer.TimerProcessCallback" default="1">
5454
Specifies when the timer is updated during the main loop (see [enum TimerProcessCallback]).
5555
</member>
56+
<member name="process_type" type="int" setter="set_timer_process_type" getter="get_timer_process_type" enum="Timer.TimerProcessType" default="0">
57+
Specifies which units the timer uses to count. (see [enum TimerProcessType]).
58+
</member>
5659
<member name="time_left" type="float" setter="" getter="get_time_left">
5760
The timer's remaining time in seconds. This is always [code]0[/code] if the timer is stopped.
5861
[b]Note:[/b] This property is read-only and cannot be modified. It is based on [member wait_time].
5962
</member>
6063
<member name="wait_time" type="float" setter="set_wait_time" getter="get_wait_time" default="1.0">
61-
The time required for the timer to end, in seconds. This property can also be set every time [method start] is called.
62-
[b]Note:[/b] Timers can only process once per physics or process frame (depending on the [member process_callback]). An unstable framerate may cause the timer to end inconsistently, which is especially noticeable if the wait time is lower than roughly [code]0.05[/code] seconds. For very short timers, it is recommended to write your own code instead of using a [Timer] node. Timers are also affected by [member Engine.time_scale].
64+
The time required for the timer to end, in seconds or frames. This property can also be set every time [method start] is called.
65+
Time mode uses floats while Frame mode only accepts and returns non-fractional numbers.
66+
[b]Note:[/b] Timers can only process once per physics or process frame (depending on the [member process_callback]). In Time mode, an unstable framerate may cause the timer to end inconsistently, which is especially noticeable if the wait time is lower than roughly [code]0.05[/code] seconds. For very short timers, it is recommended to write your own code instead of using a [Timer] node. Timers are also affected by [member Engine.time_scale].
6367
</member>
6468
</members>
6569
<signals>
@@ -76,5 +80,11 @@
7680
<constant name="TIMER_PROCESS_IDLE" value="1" enum="TimerProcessCallback">
7781
Update the timer every process (rendered) frame (see [constant Node.NOTIFICATION_INTERNAL_PROCESS]).
7882
</constant>
83+
<constant name="TIMER_PROCESS_TYPE_TIME" value="0" enum="TimerProcessType">
84+
Timer works with seconds. In this mode the timer is affected by [member Engine.time_scale].
85+
</constant>
86+
<constant name="TIMER_PROCESS_TYPE_FRAMES" value="1" enum="TimerProcessType">
87+
Timer works with frames. Speed depends on the framerate. Accepts non-fractional values only.
88+
</constant>
7989
</constants>
80-
</class>
90+
</class>

scene/main/timer.cpp

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,15 @@ void Timer::_notification(int p_what) {
5050
if (!processing || timer_process_callback == TIMER_PROCESS_PHYSICS || !is_processing_internal()) {
5151
return;
5252
}
53-
time_left -= get_process_delta_time();
53+
54+
switch (timer_process_type) {
55+
case TIMER_PROCESS_TYPE_TIME: {
56+
time_left -= get_process_delta_time();
57+
}; break;
58+
case TIMER_PROCESS_TYPE_FRAMES: {
59+
time_left -= 1;
60+
}; break;
61+
}
5462

5563
if (time_left < 0) {
5664
if (!one_shot) {
@@ -62,12 +70,19 @@ void Timer::_notification(int p_what) {
6270
emit_signal(SNAME("timeout"));
6371
}
6472
} break;
65-
6673
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
6774
if (!processing || timer_process_callback == TIMER_PROCESS_IDLE || !is_physics_processing_internal()) {
6875
return;
6976
}
70-
time_left -= get_physics_process_delta_time();
77+
78+
switch (timer_process_type) {
79+
case TIMER_PROCESS_TYPE_TIME: {
80+
time_left -= get_physics_process_delta_time();
81+
}; break;
82+
case TIMER_PROCESS_TYPE_FRAMES: {
83+
time_left -= 1;
84+
}; break;
85+
}
7186

7287
if (time_left < 0) {
7388
if (!one_shot) {
@@ -83,7 +98,12 @@ void Timer::_notification(int p_what) {
8398

8499
void Timer::set_wait_time(double p_time) {
85100
ERR_FAIL_COND_MSG(p_time <= 0, "Time should be greater than zero.");
86-
wait_time = p_time;
101+
if (timer_process_type == TIMER_PROCESS_TYPE_FRAMES) {
102+
ERR_FAIL_COND_MSG(p_time != (int)p_time, "Frame mode only accepts non-fractional values. (Frames will be rounded.)");
103+
wait_time = (int)p_time;
104+
} else {
105+
wait_time = p_time;
106+
}
87107
update_configuration_warnings();
88108
}
89109

@@ -154,13 +174,13 @@ void Timer::set_timer_process_callback(TimerProcessCallback p_callback) {
154174
if (is_physics_processing_internal()) {
155175
set_physics_process_internal(false);
156176
set_process_internal(true);
157-
}
177+
};
158178
break;
159179
case TIMER_PROCESS_IDLE:
160180
if (is_processing_internal()) {
161181
set_process_internal(false);
162182
set_physics_process_internal(true);
163-
}
183+
};
164184
break;
165185
}
166186
timer_process_callback = p_callback;
@@ -170,6 +190,26 @@ Timer::TimerProcessCallback Timer::get_timer_process_callback() const {
170190
return timer_process_callback;
171191
}
172192

193+
void Timer::set_timer_process_type(TimerProcessType p_type) {
194+
if (timer_process_type == p_type) {
195+
return;
196+
}
197+
switch (timer_process_type) {
198+
case TIMER_PROCESS_TYPE_FRAMES: {
199+
wait_time = (int)wait_time;
200+
time_left = (int)time_left;
201+
}; break;
202+
case TIMER_PROCESS_TYPE_TIME:
203+
break;
204+
}
205+
timer_process_type = p_type;
206+
notify_property_list_changed();
207+
}
208+
209+
Timer::TimerProcessType Timer::get_timer_process_type() const {
210+
return timer_process_type;
211+
}
212+
173213
void Timer::_set_process(bool p_process, bool p_force) {
174214
switch (timer_process_callback) {
175215
case TIMER_PROCESS_PHYSICS:
@@ -192,6 +232,14 @@ PackedStringArray Timer::get_configuration_warnings() const {
192232
return warnings;
193233
}
194234

235+
void Timer::_validate_property(PropertyInfo &p_property) const {
236+
if (timer_process_type == TIMER_PROCESS_TYPE_FRAMES && p_property.name == "wait_time") {
237+
p_property.type = Variant::INT;
238+
p_property.hint = PROPERTY_HINT_NONE;
239+
p_property.hint_string = "suffix:f";
240+
}
241+
}
242+
195243
void Timer::_bind_methods() {
196244
ClassDB::bind_method(D_METHOD("set_wait_time", "time_sec"), &Timer::set_wait_time);
197245
ClassDB::bind_method(D_METHOD("get_wait_time"), &Timer::get_wait_time);
@@ -215,9 +263,13 @@ void Timer::_bind_methods() {
215263
ClassDB::bind_method(D_METHOD("set_timer_process_callback", "callback"), &Timer::set_timer_process_callback);
216264
ClassDB::bind_method(D_METHOD("get_timer_process_callback"), &Timer::get_timer_process_callback);
217265

266+
ClassDB::bind_method(D_METHOD("set_timer_process_type", "type"), &Timer::set_timer_process_type);
267+
ClassDB::bind_method(D_METHOD("get_timer_process_type"), &Timer::get_timer_process_type);
268+
218269
ADD_SIGNAL(MethodInfo("timeout"));
219270

220271
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_timer_process_callback", "get_timer_process_callback");
272+
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_type", PROPERTY_HINT_ENUM, "Time,Frames"), "set_timer_process_type", "get_timer_process_type");
221273
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wait_time", PROPERTY_HINT_RANGE, "0.001,4096,0.001,or_greater,exp,suffix:s"), "set_wait_time", "get_wait_time");
222274
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "is_one_shot");
223275
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autostart"), "set_autostart", "has_autostart");
@@ -226,6 +278,9 @@ void Timer::_bind_methods() {
226278

227279
BIND_ENUM_CONSTANT(TIMER_PROCESS_PHYSICS);
228280
BIND_ENUM_CONSTANT(TIMER_PROCESS_IDLE);
281+
282+
BIND_ENUM_CONSTANT(TIMER_PROCESS_TYPE_TIME);
283+
BIND_ENUM_CONSTANT(TIMER_PROCESS_TYPE_FRAMES);
229284
}
230285

231-
Timer::Timer() {}
286+
Timer::Timer() {}

scene/main/timer.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,21 @@ class Timer : public Node {
4949
protected:
5050
void _notification(int p_what);
5151
static void _bind_methods();
52+
void _validate_property(PropertyInfo &p_property) const;
5253

5354
public:
5455
enum TimerProcessCallback {
5556
TIMER_PROCESS_PHYSICS,
5657
TIMER_PROCESS_IDLE,
5758
};
5859

60+
// Type instead of Mode to prevent name collisions when upgrading from 3 to 4
61+
// Godot 3 used TimerProcessMode which is now TimerProcessCallback
62+
enum TimerProcessType {
63+
TIMER_PROCESS_TYPE_TIME,
64+
TIMER_PROCESS_TYPE_FRAMES,
65+
};
66+
5967
void set_wait_time(double p_time);
6068
double get_wait_time() const;
6169

@@ -79,13 +87,19 @@ class Timer : public Node {
7987

8088
void set_timer_process_callback(TimerProcessCallback p_callback);
8189
TimerProcessCallback get_timer_process_callback() const;
90+
91+
void set_timer_process_type(TimerProcessType p_type);
92+
TimerProcessType get_timer_process_type() const;
93+
8294
Timer();
8395

8496
private:
8597
TimerProcessCallback timer_process_callback = TIMER_PROCESS_IDLE;
98+
TimerProcessType timer_process_type = TIMER_PROCESS_TYPE_TIME;
8699
void _set_process(bool p_process, bool p_force = false);
87100
};
88101

89102
VARIANT_ENUM_CAST(Timer::TimerProcessCallback);
103+
VARIANT_ENUM_CAST(Timer::TimerProcessType);
90104

91-
#endif // TIMER_H
105+
#endif // TIMER_H

0 commit comments

Comments
 (0)