1 /*************************************************************************/
2 /* timer.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #include "timer.h"
32
33 #include "core/engine.h"
34
_notification(int p_what)35 void Timer::_notification(int p_what) {
36
37 switch (p_what) {
38
39 case NOTIFICATION_READY: {
40
41 if (autostart) {
42 #ifdef TOOLS_ENABLED
43 if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root() == this || get_tree()->get_edited_scene_root()->is_a_parent_of(this)))
44 break;
45 #endif
46 start();
47 autostart = false;
48 }
49 } break;
50 case NOTIFICATION_INTERNAL_PROCESS: {
51 if (timer_process_mode == TIMER_PROCESS_PHYSICS || !is_processing_internal())
52 return;
53 time_left -= get_process_delta_time();
54
55 if (time_left < 0) {
56 if (!one_shot)
57 time_left += wait_time;
58 else
59 stop();
60
61 emit_signal("timeout");
62 }
63
64 } break;
65 case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
66 if (timer_process_mode == TIMER_PROCESS_IDLE || !is_physics_processing_internal())
67 return;
68 time_left -= get_physics_process_delta_time();
69
70 if (time_left < 0) {
71 if (!one_shot)
72 time_left += wait_time;
73 else
74 stop();
75 emit_signal("timeout");
76 }
77
78 } break;
79 }
80 }
81
set_wait_time(float p_time)82 void Timer::set_wait_time(float p_time) {
83 ERR_FAIL_COND_MSG(p_time <= 0, "Time should be greater than zero.");
84 wait_time = p_time;
85 }
get_wait_time() const86 float Timer::get_wait_time() const {
87
88 return wait_time;
89 }
90
set_one_shot(bool p_one_shot)91 void Timer::set_one_shot(bool p_one_shot) {
92
93 one_shot = p_one_shot;
94 }
is_one_shot() const95 bool Timer::is_one_shot() const {
96
97 return one_shot;
98 }
99
set_autostart(bool p_start)100 void Timer::set_autostart(bool p_start) {
101
102 autostart = p_start;
103 }
has_autostart() const104 bool Timer::has_autostart() const {
105
106 return autostart;
107 }
108
start(float p_time)109 void Timer::start(float p_time) {
110
111 ERR_FAIL_COND_MSG(!is_inside_tree(), "Timer was not added to the SceneTree. Either add it or set autostart to true.");
112
113 if (p_time > 0) {
114 set_wait_time(p_time);
115 }
116 time_left = wait_time;
117 _set_process(true);
118 }
119
stop()120 void Timer::stop() {
121 time_left = -1;
122 _set_process(false);
123 autostart = false;
124 }
125
set_paused(bool p_paused)126 void Timer::set_paused(bool p_paused) {
127 if (paused == p_paused)
128 return;
129
130 paused = p_paused;
131 _set_process(processing);
132 }
133
is_paused() const134 bool Timer::is_paused() const {
135 return paused;
136 }
137
is_stopped() const138 bool Timer::is_stopped() const {
139 return get_time_left() <= 0;
140 }
141
get_time_left() const142 float Timer::get_time_left() const {
143
144 return time_left > 0 ? time_left : 0;
145 }
146
set_timer_process_mode(TimerProcessMode p_mode)147 void Timer::set_timer_process_mode(TimerProcessMode p_mode) {
148
149 if (timer_process_mode == p_mode)
150 return;
151
152 switch (timer_process_mode) {
153 case TIMER_PROCESS_PHYSICS:
154 if (is_physics_processing_internal()) {
155 set_physics_process_internal(false);
156 set_process_internal(true);
157 }
158 break;
159 case TIMER_PROCESS_IDLE:
160 if (is_processing_internal()) {
161 set_process_internal(false);
162 set_physics_process_internal(true);
163 }
164 break;
165 }
166 timer_process_mode = p_mode;
167 }
168
get_timer_process_mode() const169 Timer::TimerProcessMode Timer::get_timer_process_mode() const {
170
171 return timer_process_mode;
172 }
173
_set_process(bool p_process,bool p_force)174 void Timer::_set_process(bool p_process, bool p_force) {
175 switch (timer_process_mode) {
176 case TIMER_PROCESS_PHYSICS: set_physics_process_internal(p_process && !paused); break;
177 case TIMER_PROCESS_IDLE: set_process_internal(p_process && !paused); break;
178 }
179 processing = p_process;
180 }
181
_bind_methods()182 void Timer::_bind_methods() {
183
184 ClassDB::bind_method(D_METHOD("set_wait_time", "time_sec"), &Timer::set_wait_time);
185 ClassDB::bind_method(D_METHOD("get_wait_time"), &Timer::get_wait_time);
186
187 ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &Timer::set_one_shot);
188 ClassDB::bind_method(D_METHOD("is_one_shot"), &Timer::is_one_shot);
189
190 ClassDB::bind_method(D_METHOD("set_autostart", "enable"), &Timer::set_autostart);
191 ClassDB::bind_method(D_METHOD("has_autostart"), &Timer::has_autostart);
192
193 ClassDB::bind_method(D_METHOD("start", "time_sec"), &Timer::start, DEFVAL(-1));
194 ClassDB::bind_method(D_METHOD("stop"), &Timer::stop);
195
196 ClassDB::bind_method(D_METHOD("set_paused", "paused"), &Timer::set_paused);
197 ClassDB::bind_method(D_METHOD("is_paused"), &Timer::is_paused);
198
199 ClassDB::bind_method(D_METHOD("is_stopped"), &Timer::is_stopped);
200
201 ClassDB::bind_method(D_METHOD("get_time_left"), &Timer::get_time_left);
202
203 ClassDB::bind_method(D_METHOD("set_timer_process_mode", "mode"), &Timer::set_timer_process_mode);
204 ClassDB::bind_method(D_METHOD("get_timer_process_mode"), &Timer::get_timer_process_mode);
205
206 ADD_SIGNAL(MethodInfo("timeout"));
207
208 ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_timer_process_mode", "get_timer_process_mode");
209 ADD_PROPERTY(PropertyInfo(Variant::REAL, "wait_time", PROPERTY_HINT_EXP_RANGE, "0.001,4096,0.001,or_greater"), "set_wait_time", "get_wait_time");
210 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "is_one_shot");
211 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autostart"), "set_autostart", "has_autostart");
212 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused", PROPERTY_HINT_NONE, "", 0), "set_paused", "is_paused");
213 ADD_PROPERTY(PropertyInfo(Variant::REAL, "time_left", PROPERTY_HINT_NONE, "", 0), "", "get_time_left");
214
215 BIND_ENUM_CONSTANT(TIMER_PROCESS_PHYSICS);
216 BIND_ENUM_CONSTANT(TIMER_PROCESS_IDLE);
217 }
218
Timer()219 Timer::Timer() {
220 timer_process_mode = TIMER_PROCESS_IDLE;
221 autostart = false;
222 wait_time = 1;
223 one_shot = false;
224 time_left = -1;
225 processing = false;
226 paused = false;
227 }
228