1 /*************************************************************************/
2 /* visibility_notifier_2d.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 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 #include "visibility_notifier_2d.h"
31
32 #include "particles_2d.h"
33 #include "scene/2d/animated_sprite.h"
34 #include "scene/2d/physics_body_2d.h"
35 #include "scene/animation/animation_player.h"
36 #include "scene/scene_string_names.h"
37
_enter_viewport(Viewport * p_viewport)38 void VisibilityNotifier2D::_enter_viewport(Viewport *p_viewport) {
39
40 ERR_FAIL_COND(viewports.has(p_viewport));
41 viewports.insert(p_viewport);
42
43 if (is_inside_tree() && get_tree()->is_editor_hint())
44 return;
45
46 if (viewports.size() == 1) {
47 emit_signal(SceneStringNames::get_singleton()->enter_screen);
48
49 _screen_enter();
50 }
51 emit_signal(SceneStringNames::get_singleton()->enter_viewport, p_viewport);
52 }
53
_exit_viewport(Viewport * p_viewport)54 void VisibilityNotifier2D::_exit_viewport(Viewport *p_viewport) {
55
56 ERR_FAIL_COND(!viewports.has(p_viewport));
57 viewports.erase(p_viewport);
58
59 if (is_inside_tree() && get_tree()->is_editor_hint())
60 return;
61
62 emit_signal(SceneStringNames::get_singleton()->exit_viewport, p_viewport);
63 if (viewports.size() == 0) {
64 emit_signal(SceneStringNames::get_singleton()->exit_screen);
65
66 _screen_exit();
67 }
68 }
69
set_rect(const Rect2 & p_rect)70 void VisibilityNotifier2D::set_rect(const Rect2 &p_rect) {
71
72 rect = p_rect;
73 if (is_inside_tree()) {
74 get_world_2d()->_update_notifier(this, get_global_transform().xform(rect));
75 if (get_tree()->is_editor_hint()) {
76 update();
77 item_rect_changed();
78 }
79 }
80
81 _change_notify("rect");
82 }
83
get_item_rect() const84 Rect2 VisibilityNotifier2D::get_item_rect() const {
85
86 return rect;
87 }
88
get_rect() const89 Rect2 VisibilityNotifier2D::get_rect() const {
90
91 return rect;
92 }
93
_notification(int p_what)94 void VisibilityNotifier2D::_notification(int p_what) {
95
96 switch (p_what) {
97 case NOTIFICATION_ENTER_TREE: {
98
99 //get_world_2d()->
100 get_world_2d()->_register_notifier(this, get_global_transform().xform(rect));
101 } break;
102 case NOTIFICATION_TRANSFORM_CHANGED: {
103
104 //get_world_2d()->
105 get_world_2d()->_update_notifier(this, get_global_transform().xform(rect));
106 } break;
107 case NOTIFICATION_DRAW: {
108
109 if (get_tree()->is_editor_hint()) {
110
111 draw_rect(rect, Color(1, 0.5, 1, 0.2));
112 }
113 } break;
114 case NOTIFICATION_EXIT_TREE: {
115
116 get_world_2d()->_remove_notifier(this);
117 } break;
118 }
119 }
120
is_on_screen() const121 bool VisibilityNotifier2D::is_on_screen() const {
122
123 return viewports.size() > 0;
124 }
125
_bind_methods()126 void VisibilityNotifier2D::_bind_methods() {
127
128 ObjectTypeDB::bind_method(_MD("set_rect", "rect"), &VisibilityNotifier2D::set_rect);
129 ObjectTypeDB::bind_method(_MD("get_rect"), &VisibilityNotifier2D::get_rect);
130 ObjectTypeDB::bind_method(_MD("is_on_screen"), &VisibilityNotifier2D::is_on_screen);
131
132 ADD_PROPERTY(PropertyInfo(Variant::RECT2, "rect"), _SCS("set_rect"), _SCS("get_rect"));
133
134 ADD_SIGNAL(MethodInfo("enter_viewport", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport")));
135 ADD_SIGNAL(MethodInfo("exit_viewport", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport")));
136 ADD_SIGNAL(MethodInfo("enter_screen"));
137 ADD_SIGNAL(MethodInfo("exit_screen"));
138 }
139
VisibilityNotifier2D()140 VisibilityNotifier2D::VisibilityNotifier2D() {
141
142 rect = Rect2(-10, -10, 20, 20);
143 }
144
145 //////////////////////////////////////
146
_screen_enter()147 void VisibilityEnabler2D::_screen_enter() {
148
149 for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
150
151 _change_node_state(E->key(), true);
152 }
153
154 if (enabler[ENABLER_PARENT_FIXED_PROCESS] && get_parent())
155 get_parent()->set_fixed_process(true);
156 if (enabler[ENABLER_PARENT_PROCESS] && get_parent())
157 get_parent()->set_process(true);
158
159 visible = true;
160 }
161
_screen_exit()162 void VisibilityEnabler2D::_screen_exit() {
163
164 for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
165
166 _change_node_state(E->key(), false);
167 }
168
169 if (enabler[ENABLER_PARENT_FIXED_PROCESS] && get_parent())
170 get_parent()->set_fixed_process(false);
171 if (enabler[ENABLER_PARENT_PROCESS] && get_parent())
172 get_parent()->set_process(false);
173
174 visible = false;
175 }
176
_find_nodes(Node * p_node)177 void VisibilityEnabler2D::_find_nodes(Node *p_node) {
178
179 bool add = false;
180 Variant meta;
181
182 if (enabler[ENABLER_FREEZE_BODIES]) {
183
184 RigidBody2D *rb2d = p_node->cast_to<RigidBody2D>();
185 if (rb2d && ((rb2d->get_mode() == RigidBody2D::MODE_CHARACTER || (rb2d->get_mode() == RigidBody2D::MODE_RIGID && !rb2d->is_able_to_sleep())))) {
186
187 add = true;
188 meta = rb2d->get_mode();
189 }
190 }
191
192 if (enabler[ENABLER_PAUSE_ANIMATIONS]) {
193
194 AnimationPlayer *ap = p_node->cast_to<AnimationPlayer>();
195 if (ap) {
196 add = true;
197 }
198 }
199
200 if (enabler[ENABLER_PAUSE_ANIMATED_SPRITES]) {
201
202 AnimatedSprite *as = p_node->cast_to<AnimatedSprite>();
203 if (as) {
204 add = true;
205 }
206 }
207
208 if (enabler[ENABLER_PAUSE_PARTICLES]) {
209
210 Particles2D *ps = p_node->cast_to<Particles2D>();
211 if (ps) {
212 add = true;
213 }
214 }
215
216 if (add) {
217
218 p_node->connect(SceneStringNames::get_singleton()->exit_tree, this, "_node_removed", varray(p_node), CONNECT_ONESHOT);
219 nodes[p_node] = meta;
220 _change_node_state(p_node, false);
221 }
222
223 for (int i = 0; i < p_node->get_child_count(); i++) {
224 Node *c = p_node->get_child(i);
225 if (c->get_filename() != String())
226 continue; //skip, instance
227
228 _find_nodes(c);
229 }
230 }
231
_notification(int p_what)232 void VisibilityEnabler2D::_notification(int p_what) {
233
234 if (p_what == NOTIFICATION_ENTER_TREE) {
235
236 if (get_tree()->is_editor_hint())
237 return;
238
239 Node *from = this;
240 //find where current scene starts
241 while (from->get_parent() && from->get_filename() == String())
242 from = from->get_parent();
243
244 _find_nodes(from);
245
246 if (enabler[ENABLER_PARENT_FIXED_PROCESS] && get_parent())
247 get_parent()->set_fixed_process(false);
248 if (enabler[ENABLER_PARENT_PROCESS] && get_parent())
249 get_parent()->set_process(false);
250 }
251
252 if (p_what == NOTIFICATION_EXIT_TREE) {
253
254 if (get_tree()->is_editor_hint())
255 return;
256
257 for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
258
259 if (!visible)
260 _change_node_state(E->key(), true);
261 E->key()->disconnect(SceneStringNames::get_singleton()->exit_tree, this, "_node_removed");
262 }
263
264 nodes.clear();
265 }
266 }
267
_change_node_state(Node * p_node,bool p_enabled)268 void VisibilityEnabler2D::_change_node_state(Node *p_node, bool p_enabled) {
269
270 ERR_FAIL_COND(!nodes.has(p_node));
271
272 {
273 RigidBody2D *rb = p_node->cast_to<RigidBody2D>();
274 if (rb) {
275
276 rb->set_sleeping(!p_enabled);
277 }
278 }
279
280 {
281 AnimationPlayer *ap = p_node->cast_to<AnimationPlayer>();
282
283 if (ap) {
284
285 ap->set_active(p_enabled);
286 }
287 }
288 {
289 AnimatedSprite *as = p_node->cast_to<AnimatedSprite>();
290
291 if (as) {
292
293 if (p_enabled)
294 as->play();
295 else
296 as->stop();
297 }
298 }
299
300 {
301 Particles2D *ps = p_node->cast_to<Particles2D>();
302
303 if (ps) {
304
305 ps->set_emitting(p_enabled);
306 }
307 }
308 }
309
_node_removed(Node * p_node)310 void VisibilityEnabler2D::_node_removed(Node *p_node) {
311
312 if (!visible)
313 _change_node_state(p_node, true);
314 //changed to one shot, not needed
315 //p_node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed");
316 nodes.erase(p_node);
317 }
318
get_configuration_warning() const319 String VisibilityEnabler2D::get_configuration_warning() const {
320 #ifdef TOOLS_ENABLED
321 if (is_inside_tree() && get_parent() && (get_parent()->get_filename() == String() && get_parent() != get_tree()->get_edited_scene_root())) {
322 return TTR("VisibilityEnable2D works best when used with the edited scene root directly as parent.");
323 }
324 #endif
325 return String();
326 }
327
_bind_methods()328 void VisibilityEnabler2D::_bind_methods() {
329
330 ObjectTypeDB::bind_method(_MD("set_enabler", "enabler", "enabled"), &VisibilityEnabler2D::set_enabler);
331 ObjectTypeDB::bind_method(_MD("is_enabler_enabled", "enabler"), &VisibilityEnabler2D::is_enabler_enabled);
332 ObjectTypeDB::bind_method(_MD("_node_removed"), &VisibilityEnabler2D::_node_removed);
333
334 ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "enabler/pause_animations"), _SCS("set_enabler"), _SCS("is_enabler_enabled"), ENABLER_PAUSE_ANIMATIONS);
335 ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "enabler/freeze_bodies"), _SCS("set_enabler"), _SCS("is_enabler_enabled"), ENABLER_FREEZE_BODIES);
336 ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "enabler/pause_particles"), _SCS("set_enabler"), _SCS("is_enabler_enabled"), ENABLER_PAUSE_PARTICLES);
337 ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "enabler/pause_animated_sprites"), _SCS("set_enabler"), _SCS("is_enabler_enabled"), ENABLER_PAUSE_ANIMATED_SPRITES);
338 ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "enabler/process_parent"), _SCS("set_enabler"), _SCS("is_enabler_enabled"), ENABLER_PARENT_PROCESS);
339 ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "enabler/fixed_process_parent"), _SCS("set_enabler"), _SCS("is_enabler_enabled"), ENABLER_PARENT_FIXED_PROCESS);
340
341 BIND_CONSTANT(ENABLER_FREEZE_BODIES);
342 BIND_CONSTANT(ENABLER_PAUSE_ANIMATIONS);
343 BIND_CONSTANT(ENABLER_PAUSE_PARTICLES);
344 BIND_CONSTANT(ENABLER_PAUSE_ANIMATED_SPRITES);
345 BIND_CONSTANT(ENABLER_PARENT_PROCESS);
346 BIND_CONSTANT(ENABLER_PARENT_FIXED_PROCESS);
347 BIND_CONSTANT(ENABLER_MAX);
348 }
349
set_enabler(Enabler p_enabler,bool p_enable)350 void VisibilityEnabler2D::set_enabler(Enabler p_enabler, bool p_enable) {
351
352 ERR_FAIL_INDEX(p_enabler, ENABLER_MAX);
353 enabler[p_enabler] = p_enable;
354 }
is_enabler_enabled(Enabler p_enabler) const355 bool VisibilityEnabler2D::is_enabler_enabled(Enabler p_enabler) const {
356
357 ERR_FAIL_INDEX_V(p_enabler, ENABLER_MAX, false);
358 return enabler[p_enabler];
359 }
360
VisibilityEnabler2D()361 VisibilityEnabler2D::VisibilityEnabler2D() {
362
363 for (int i = 0; i < ENABLER_MAX; i++)
364 enabler[i] = true;
365 enabler[ENABLER_PARENT_PROCESS] = false;
366 enabler[ENABLER_PARENT_FIXED_PROCESS] = false;
367
368 visible = false;
369 }
370