1 | /**************************************************************************/ |
2 | /* area_3d.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
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 "area_3d.h" |
32 | |
33 | #include "scene/scene_string_names.h" |
34 | #include "servers/audio_server.h" |
35 | |
36 | void Area3D::set_gravity_space_override_mode(SpaceOverride p_mode) { |
37 | gravity_space_override = p_mode; |
38 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE, p_mode); |
39 | } |
40 | |
41 | Area3D::SpaceOverride Area3D::get_gravity_space_override_mode() const { |
42 | return gravity_space_override; |
43 | } |
44 | |
45 | void Area3D::set_gravity_is_point(bool p_enabled) { |
46 | gravity_is_point = p_enabled; |
47 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT, p_enabled); |
48 | } |
49 | |
50 | bool Area3D::is_gravity_a_point() const { |
51 | return gravity_is_point; |
52 | } |
53 | |
54 | void Area3D::set_gravity_point_unit_distance(real_t p_scale) { |
55 | gravity_point_unit_distance = p_scale; |
56 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE, p_scale); |
57 | } |
58 | |
59 | real_t Area3D::get_gravity_point_unit_distance() const { |
60 | return gravity_point_unit_distance; |
61 | } |
62 | |
63 | void Area3D::set_gravity_point_center(const Vector3 &p_center) { |
64 | gravity_vec = p_center; |
65 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, p_center); |
66 | } |
67 | |
68 | const Vector3 &Area3D::get_gravity_point_center() const { |
69 | return gravity_vec; |
70 | } |
71 | |
72 | void Area3D::set_gravity_direction(const Vector3 &p_direction) { |
73 | gravity_vec = p_direction; |
74 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, p_direction); |
75 | } |
76 | |
77 | const Vector3 &Area3D::get_gravity_direction() const { |
78 | return gravity_vec; |
79 | } |
80 | |
81 | void Area3D::set_gravity(real_t p_gravity) { |
82 | gravity = p_gravity; |
83 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY, p_gravity); |
84 | } |
85 | |
86 | real_t Area3D::get_gravity() const { |
87 | return gravity; |
88 | } |
89 | |
90 | void Area3D::set_linear_damp_space_override_mode(SpaceOverride p_mode) { |
91 | linear_damp_space_override = p_mode; |
92 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE, p_mode); |
93 | } |
94 | |
95 | Area3D::SpaceOverride Area3D::get_linear_damp_space_override_mode() const { |
96 | return linear_damp_space_override; |
97 | } |
98 | |
99 | void Area3D::set_angular_damp_space_override_mode(SpaceOverride p_mode) { |
100 | angular_damp_space_override = p_mode; |
101 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE, p_mode); |
102 | } |
103 | |
104 | Area3D::SpaceOverride Area3D::get_angular_damp_space_override_mode() const { |
105 | return angular_damp_space_override; |
106 | } |
107 | |
108 | void Area3D::set_linear_damp(real_t p_linear_damp) { |
109 | linear_damp = p_linear_damp; |
110 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_LINEAR_DAMP, p_linear_damp); |
111 | } |
112 | |
113 | real_t Area3D::get_linear_damp() const { |
114 | return linear_damp; |
115 | } |
116 | |
117 | void Area3D::set_angular_damp(real_t p_angular_damp) { |
118 | angular_damp = p_angular_damp; |
119 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP, p_angular_damp); |
120 | } |
121 | |
122 | real_t Area3D::get_angular_damp() const { |
123 | return angular_damp; |
124 | } |
125 | |
126 | void Area3D::set_priority(int p_priority) { |
127 | priority = p_priority; |
128 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_PRIORITY, p_priority); |
129 | } |
130 | |
131 | int Area3D::get_priority() const { |
132 | return priority; |
133 | } |
134 | |
135 | void Area3D::set_wind_force_magnitude(real_t p_wind_force_magnitude) { |
136 | wind_force_magnitude = p_wind_force_magnitude; |
137 | if (is_inside_tree()) { |
138 | _initialize_wind(); |
139 | } |
140 | } |
141 | |
142 | real_t Area3D::get_wind_force_magnitude() const { |
143 | return wind_force_magnitude; |
144 | } |
145 | |
146 | void Area3D::set_wind_attenuation_factor(real_t p_wind_force_attenuation_factor) { |
147 | wind_attenuation_factor = p_wind_force_attenuation_factor; |
148 | if (is_inside_tree()) { |
149 | _initialize_wind(); |
150 | } |
151 | } |
152 | |
153 | real_t Area3D::get_wind_attenuation_factor() const { |
154 | return wind_attenuation_factor; |
155 | } |
156 | |
157 | void Area3D::set_wind_source_path(const NodePath &p_wind_source_path) { |
158 | wind_source_path = p_wind_source_path; |
159 | if (is_inside_tree()) { |
160 | _initialize_wind(); |
161 | } |
162 | } |
163 | |
164 | const NodePath &Area3D::get_wind_source_path() const { |
165 | return wind_source_path; |
166 | } |
167 | |
168 | void Area3D::_initialize_wind() { |
169 | real_t temp_magnitude = 0.0; |
170 | Vector3 wind_direction(0., 0., 0.); |
171 | Vector3 wind_source(0., 0., 0.); |
172 | |
173 | // Overwrite with area-specified info if available |
174 | if (!wind_source_path.is_empty()) { |
175 | Node *wind_source_node = get_node_or_null(wind_source_path); |
176 | ERR_FAIL_NULL_MSG(wind_source_node, "Path to wind source is invalid: '" + wind_source_path + "'." ); |
177 | Node3D *wind_source_node3d = Object::cast_to<Node3D>(wind_source_node); |
178 | ERR_FAIL_NULL_MSG(wind_source_node3d, "Path to wind source does not point to a Node3D: '" + wind_source_path + "'." ); |
179 | Transform3D global_transform = wind_source_node3d->get_transform(); |
180 | wind_direction = -global_transform.basis.get_column(Vector3::AXIS_Z).normalized(); |
181 | wind_source = global_transform.origin; |
182 | temp_magnitude = wind_force_magnitude; |
183 | } |
184 | |
185 | // Set force, source and direction in the physics server. |
186 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_ATTENUATION_FACTOR, wind_attenuation_factor); |
187 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_SOURCE, wind_source); |
188 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_DIRECTION, wind_direction); |
189 | PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_FORCE_MAGNITUDE, temp_magnitude); |
190 | } |
191 | |
192 | void Area3D::_body_enter_tree(ObjectID p_id) { |
193 | Object *obj = ObjectDB::get_instance(p_id); |
194 | Node *node = Object::cast_to<Node>(obj); |
195 | ERR_FAIL_NULL(node); |
196 | |
197 | HashMap<ObjectID, BodyState>::Iterator E = body_map.find(p_id); |
198 | ERR_FAIL_COND(!E); |
199 | ERR_FAIL_COND(E->value.in_tree); |
200 | |
201 | E->value.in_tree = true; |
202 | emit_signal(SceneStringNames::get_singleton()->body_entered, node); |
203 | for (int i = 0; i < E->value.shapes.size(); i++) { |
204 | emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].area_shape); |
205 | } |
206 | } |
207 | |
208 | void Area3D::_body_exit_tree(ObjectID p_id) { |
209 | Object *obj = ObjectDB::get_instance(p_id); |
210 | Node *node = Object::cast_to<Node>(obj); |
211 | ERR_FAIL_NULL(node); |
212 | HashMap<ObjectID, BodyState>::Iterator E = body_map.find(p_id); |
213 | ERR_FAIL_COND(!E); |
214 | ERR_FAIL_COND(!E->value.in_tree); |
215 | E->value.in_tree = false; |
216 | emit_signal(SceneStringNames::get_singleton()->body_exited, node); |
217 | for (int i = 0; i < E->value.shapes.size(); i++) { |
218 | emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].area_shape); |
219 | } |
220 | } |
221 | |
222 | void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape) { |
223 | bool body_in = p_status == PhysicsServer3D::AREA_BODY_ADDED; |
224 | ObjectID objid = p_instance; |
225 | |
226 | Object *obj = ObjectDB::get_instance(objid); |
227 | Node *node = Object::cast_to<Node>(obj); |
228 | |
229 | HashMap<ObjectID, BodyState>::Iterator E = body_map.find(objid); |
230 | |
231 | if (!body_in && !E) { |
232 | return; //likely removed from the tree |
233 | } |
234 | |
235 | lock_callback(); |
236 | locked = true; |
237 | |
238 | if (body_in) { |
239 | if (!E) { |
240 | E = body_map.insert(objid, BodyState()); |
241 | E->value.rid = p_body; |
242 | E->value.rc = 0; |
243 | E->value.in_tree = node && node->is_inside_tree(); |
244 | if (node) { |
245 | node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree).bind(objid)); |
246 | node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree).bind(objid)); |
247 | if (E->value.in_tree) { |
248 | emit_signal(SceneStringNames::get_singleton()->body_entered, node); |
249 | } |
250 | } |
251 | } |
252 | E->value.rc++; |
253 | if (node) { |
254 | E->value.shapes.insert(ShapePair(p_body_shape, p_area_shape)); |
255 | } |
256 | |
257 | if (E->value.in_tree) { |
258 | emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_area_shape); |
259 | } |
260 | |
261 | } else { |
262 | E->value.rc--; |
263 | |
264 | if (node) { |
265 | E->value.shapes.erase(ShapePair(p_body_shape, p_area_shape)); |
266 | } |
267 | |
268 | bool in_tree = E->value.in_tree; |
269 | if (E->value.rc == 0) { |
270 | body_map.remove(E); |
271 | if (node) { |
272 | node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree)); |
273 | node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree)); |
274 | if (in_tree) { |
275 | emit_signal(SceneStringNames::get_singleton()->body_exited, obj); |
276 | } |
277 | } |
278 | } |
279 | if (node && in_tree) { |
280 | emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_area_shape); |
281 | } |
282 | } |
283 | |
284 | locked = false; |
285 | unlock_callback(); |
286 | } |
287 | |
288 | void Area3D::_clear_monitoring() { |
289 | ERR_FAIL_COND_MSG(locked, "This function can't be used during the in/out signal." ); |
290 | |
291 | { |
292 | HashMap<ObjectID, BodyState> bmcopy = body_map; |
293 | body_map.clear(); |
294 | //disconnect all monitored stuff |
295 | |
296 | for (const KeyValue<ObjectID, BodyState> &E : bmcopy) { |
297 | Object *obj = ObjectDB::get_instance(E.key); |
298 | Node *node = Object::cast_to<Node>(obj); |
299 | |
300 | if (!node) { //node may have been deleted in previous frame or at other legitimate point |
301 | continue; |
302 | } |
303 | //ERR_CONTINUE(!node); |
304 | |
305 | node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree)); |
306 | node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree)); |
307 | |
308 | if (!E.value.in_tree) { |
309 | continue; |
310 | } |
311 | |
312 | for (int i = 0; i < E.value.shapes.size(); i++) { |
313 | emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E.value.rid, node, E.value.shapes[i].body_shape, E.value.shapes[i].area_shape); |
314 | } |
315 | |
316 | emit_signal(SceneStringNames::get_singleton()->body_exited, node); |
317 | } |
318 | } |
319 | |
320 | { |
321 | HashMap<ObjectID, AreaState> bmcopy = area_map; |
322 | area_map.clear(); |
323 | //disconnect all monitored stuff |
324 | |
325 | for (const KeyValue<ObjectID, AreaState> &E : bmcopy) { |
326 | Object *obj = ObjectDB::get_instance(E.key); |
327 | Node *node = Object::cast_to<Node>(obj); |
328 | |
329 | if (!node) { //node may have been deleted in previous frame or at other legitimate point |
330 | continue; |
331 | } |
332 | //ERR_CONTINUE(!node); |
333 | |
334 | node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree)); |
335 | node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree)); |
336 | |
337 | if (!E.value.in_tree) { |
338 | continue; |
339 | } |
340 | |
341 | for (int i = 0; i < E.value.shapes.size(); i++) { |
342 | emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E.value.rid, node, E.value.shapes[i].area_shape, E.value.shapes[i].self_shape); |
343 | } |
344 | |
345 | emit_signal(SceneStringNames::get_singleton()->area_exited, obj); |
346 | } |
347 | } |
348 | } |
349 | |
350 | void Area3D::_notification(int p_what) { |
351 | switch (p_what) { |
352 | case NOTIFICATION_EXIT_TREE: { |
353 | _clear_monitoring(); |
354 | } break; |
355 | |
356 | case NOTIFICATION_ENTER_TREE: { |
357 | _initialize_wind(); |
358 | } break; |
359 | } |
360 | } |
361 | |
362 | void Area3D::set_monitoring(bool p_enable) { |
363 | ERR_FAIL_COND_MSG(locked, "Function blocked during in/out signal. Use set_deferred(\"monitoring\", true/false)." ); |
364 | |
365 | if (p_enable == monitoring) { |
366 | return; |
367 | } |
368 | |
369 | monitoring = p_enable; |
370 | |
371 | if (monitoring) { |
372 | PhysicsServer3D::get_singleton()->area_set_monitor_callback(get_rid(), callable_mp(this, &Area3D::_body_inout)); |
373 | PhysicsServer3D::get_singleton()->area_set_area_monitor_callback(get_rid(), callable_mp(this, &Area3D::_area_inout)); |
374 | } else { |
375 | PhysicsServer3D::get_singleton()->area_set_monitor_callback(get_rid(), Callable()); |
376 | PhysicsServer3D::get_singleton()->area_set_area_monitor_callback(get_rid(), Callable()); |
377 | _clear_monitoring(); |
378 | } |
379 | } |
380 | |
381 | void Area3D::_area_enter_tree(ObjectID p_id) { |
382 | Object *obj = ObjectDB::get_instance(p_id); |
383 | Node *node = Object::cast_to<Node>(obj); |
384 | ERR_FAIL_NULL(node); |
385 | |
386 | HashMap<ObjectID, AreaState>::Iterator E = area_map.find(p_id); |
387 | ERR_FAIL_COND(!E); |
388 | ERR_FAIL_COND(E->value.in_tree); |
389 | |
390 | E->value.in_tree = true; |
391 | emit_signal(SceneStringNames::get_singleton()->area_entered, node); |
392 | for (int i = 0; i < E->value.shapes.size(); i++) { |
393 | emit_signal(SceneStringNames::get_singleton()->area_shape_entered, E->value.rid, node, E->value.shapes[i].area_shape, E->value.shapes[i].self_shape); |
394 | } |
395 | } |
396 | |
397 | void Area3D::_area_exit_tree(ObjectID p_id) { |
398 | Object *obj = ObjectDB::get_instance(p_id); |
399 | Node *node = Object::cast_to<Node>(obj); |
400 | ERR_FAIL_NULL(node); |
401 | HashMap<ObjectID, AreaState>::Iterator E = area_map.find(p_id); |
402 | ERR_FAIL_COND(!E); |
403 | ERR_FAIL_COND(!E->value.in_tree); |
404 | E->value.in_tree = false; |
405 | emit_signal(SceneStringNames::get_singleton()->area_exited, node); |
406 | for (int i = 0; i < E->value.shapes.size(); i++) { |
407 | emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E->value.rid, node, E->value.shapes[i].area_shape, E->value.shapes[i].self_shape); |
408 | } |
409 | } |
410 | |
411 | void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, int p_area_shape, int p_self_shape) { |
412 | bool area_in = p_status == PhysicsServer3D::AREA_BODY_ADDED; |
413 | ObjectID objid = p_instance; |
414 | |
415 | Object *obj = ObjectDB::get_instance(objid); |
416 | Node *node = Object::cast_to<Node>(obj); |
417 | |
418 | HashMap<ObjectID, AreaState>::Iterator E = area_map.find(objid); |
419 | |
420 | if (!area_in && !E) { |
421 | return; //likely removed from the tree |
422 | } |
423 | |
424 | lock_callback(); |
425 | locked = true; |
426 | |
427 | if (area_in) { |
428 | if (!E) { |
429 | E = area_map.insert(objid, AreaState()); |
430 | E->value.rid = p_area; |
431 | E->value.rc = 0; |
432 | E->value.in_tree = node && node->is_inside_tree(); |
433 | if (node) { |
434 | node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree).bind(objid)); |
435 | node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree).bind(objid)); |
436 | if (E->value.in_tree) { |
437 | emit_signal(SceneStringNames::get_singleton()->area_entered, node); |
438 | } |
439 | } |
440 | } |
441 | E->value.rc++; |
442 | if (node) { |
443 | E->value.shapes.insert(AreaShapePair(p_area_shape, p_self_shape)); |
444 | } |
445 | |
446 | if (!node || E->value.in_tree) { |
447 | emit_signal(SceneStringNames::get_singleton()->area_shape_entered, p_area, node, p_area_shape, p_self_shape); |
448 | } |
449 | |
450 | } else { |
451 | E->value.rc--; |
452 | |
453 | if (node) { |
454 | E->value.shapes.erase(AreaShapePair(p_area_shape, p_self_shape)); |
455 | } |
456 | |
457 | bool in_tree = E->value.in_tree; |
458 | if (E->value.rc == 0) { |
459 | area_map.remove(E); |
460 | if (node) { |
461 | node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree)); |
462 | node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree)); |
463 | if (in_tree) { |
464 | emit_signal(SceneStringNames::get_singleton()->area_exited, obj); |
465 | } |
466 | } |
467 | } |
468 | if (!node || in_tree) { |
469 | emit_signal(SceneStringNames::get_singleton()->area_shape_exited, p_area, obj, p_area_shape, p_self_shape); |
470 | } |
471 | } |
472 | |
473 | locked = false; |
474 | unlock_callback(); |
475 | } |
476 | |
477 | bool Area3D::is_monitoring() const { |
478 | return monitoring; |
479 | } |
480 | |
481 | TypedArray<Node3D> Area3D::get_overlapping_bodies() const { |
482 | TypedArray<Node3D> ret; |
483 | ERR_FAIL_COND_V_MSG(!monitoring, ret, "Can't find overlapping bodies when monitoring is off." ); |
484 | ret.resize(body_map.size()); |
485 | int idx = 0; |
486 | for (const KeyValue<ObjectID, BodyState> &E : body_map) { |
487 | Object *obj = ObjectDB::get_instance(E.key); |
488 | if (obj) { |
489 | ret[idx] = obj; |
490 | idx++; |
491 | } |
492 | } |
493 | |
494 | ret.resize(idx); |
495 | return ret; |
496 | } |
497 | |
498 | bool Area3D::has_overlapping_bodies() const { |
499 | ERR_FAIL_COND_V_MSG(!monitoring, false, "Can't find overlapping bodies when monitoring is off." ); |
500 | return !body_map.is_empty(); |
501 | } |
502 | |
503 | void Area3D::set_monitorable(bool p_enable) { |
504 | ERR_FAIL_COND_MSG(locked || (is_inside_tree() && PhysicsServer3D::get_singleton()->is_flushing_queries()), "Function blocked during in/out signal. Use set_deferred(\"monitorable\", true/false)." ); |
505 | |
506 | if (p_enable == monitorable) { |
507 | return; |
508 | } |
509 | |
510 | monitorable = p_enable; |
511 | |
512 | PhysicsServer3D::get_singleton()->area_set_monitorable(get_rid(), monitorable); |
513 | } |
514 | |
515 | bool Area3D::is_monitorable() const { |
516 | return monitorable; |
517 | } |
518 | |
519 | TypedArray<Area3D> Area3D::get_overlapping_areas() const { |
520 | TypedArray<Area3D> ret; |
521 | ERR_FAIL_COND_V_MSG(!monitoring, ret, "Can't find overlapping areas when monitoring is off." ); |
522 | ret.resize(area_map.size()); |
523 | int idx = 0; |
524 | for (const KeyValue<ObjectID, AreaState> &E : area_map) { |
525 | Object *obj = ObjectDB::get_instance(E.key); |
526 | if (obj) { |
527 | ret[idx] = obj; |
528 | idx++; |
529 | } |
530 | } |
531 | ret.resize(idx); |
532 | return ret; |
533 | } |
534 | |
535 | bool Area3D::has_overlapping_areas() const { |
536 | ERR_FAIL_COND_V_MSG(!monitoring, false, "Can't find overlapping areas when monitoring is off." ); |
537 | return !area_map.is_empty(); |
538 | } |
539 | |
540 | bool Area3D::overlaps_area(Node *p_area) const { |
541 | ERR_FAIL_NULL_V(p_area, false); |
542 | HashMap<ObjectID, AreaState>::ConstIterator E = area_map.find(p_area->get_instance_id()); |
543 | if (!E) { |
544 | return false; |
545 | } |
546 | return E->value.in_tree; |
547 | } |
548 | |
549 | bool Area3D::overlaps_body(Node *p_body) const { |
550 | ERR_FAIL_NULL_V(p_body, false); |
551 | HashMap<ObjectID, BodyState>::ConstIterator E = body_map.find(p_body->get_instance_id()); |
552 | if (!E) { |
553 | return false; |
554 | } |
555 | return E->value.in_tree; |
556 | } |
557 | |
558 | void Area3D::set_audio_bus_override(bool p_override) { |
559 | audio_bus_override = p_override; |
560 | } |
561 | |
562 | bool Area3D::is_overriding_audio_bus() const { |
563 | return audio_bus_override; |
564 | } |
565 | |
566 | void Area3D::set_audio_bus_name(const StringName &p_audio_bus) { |
567 | audio_bus = p_audio_bus; |
568 | } |
569 | |
570 | StringName Area3D::get_audio_bus_name() const { |
571 | for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { |
572 | if (AudioServer::get_singleton()->get_bus_name(i) == audio_bus) { |
573 | return audio_bus; |
574 | } |
575 | } |
576 | return SceneStringNames::get_singleton()->Master; |
577 | } |
578 | |
579 | void Area3D::set_use_reverb_bus(bool p_enable) { |
580 | use_reverb_bus = p_enable; |
581 | } |
582 | |
583 | bool Area3D::is_using_reverb_bus() const { |
584 | return use_reverb_bus; |
585 | } |
586 | |
587 | void Area3D::set_reverb_bus_name(const StringName &p_audio_bus) { |
588 | reverb_bus = p_audio_bus; |
589 | } |
590 | |
591 | StringName Area3D::get_reverb_bus_name() const { |
592 | for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { |
593 | if (AudioServer::get_singleton()->get_bus_name(i) == reverb_bus) { |
594 | return reverb_bus; |
595 | } |
596 | } |
597 | return SceneStringNames::get_singleton()->Master; |
598 | } |
599 | |
600 | void Area3D::set_reverb_amount(float p_amount) { |
601 | reverb_amount = p_amount; |
602 | } |
603 | |
604 | float Area3D::get_reverb_amount() const { |
605 | return reverb_amount; |
606 | } |
607 | |
608 | void Area3D::set_reverb_uniformity(float p_uniformity) { |
609 | reverb_uniformity = p_uniformity; |
610 | } |
611 | |
612 | float Area3D::get_reverb_uniformity() const { |
613 | return reverb_uniformity; |
614 | } |
615 | |
616 | void Area3D::_validate_property(PropertyInfo &p_property) const { |
617 | if (p_property.name == "audio_bus_name" || p_property.name == "reverb_bus_name" ) { |
618 | String options; |
619 | for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { |
620 | if (i > 0) { |
621 | options += "," ; |
622 | } |
623 | String name = AudioServer::get_singleton()->get_bus_name(i); |
624 | options += name; |
625 | } |
626 | |
627 | p_property.hint_string = options; |
628 | } else if (p_property.name.begins_with("gravity" ) && p_property.name != "gravity_space_override" ) { |
629 | if (gravity_space_override == SPACE_OVERRIDE_DISABLED) { |
630 | p_property.usage = PROPERTY_USAGE_NO_EDITOR; |
631 | } else { |
632 | if (gravity_is_point) { |
633 | if (p_property.name == "gravity_direction" ) { |
634 | p_property.usage = PROPERTY_USAGE_NO_EDITOR; |
635 | } |
636 | } else { |
637 | if (p_property.name.begins_with("gravity_point_" )) { |
638 | p_property.usage = PROPERTY_USAGE_NO_EDITOR; |
639 | } |
640 | } |
641 | } |
642 | } else if (p_property.name.begins_with("linear_damp" ) && p_property.name != "linear_damp_space_override" ) { |
643 | if (linear_damp_space_override == SPACE_OVERRIDE_DISABLED) { |
644 | p_property.usage = PROPERTY_USAGE_NO_EDITOR; |
645 | } |
646 | } else if (p_property.name.begins_with("angular_damp" ) && p_property.name != "angular_damp_space_override" ) { |
647 | if (angular_damp_space_override == SPACE_OVERRIDE_DISABLED) { |
648 | p_property.usage = PROPERTY_USAGE_NO_EDITOR; |
649 | } |
650 | } |
651 | } |
652 | |
653 | void Area3D::_bind_methods() { |
654 | ClassDB::bind_method(D_METHOD("set_gravity_space_override_mode" , "space_override_mode" ), &Area3D::set_gravity_space_override_mode); |
655 | ClassDB::bind_method(D_METHOD("get_gravity_space_override_mode" ), &Area3D::get_gravity_space_override_mode); |
656 | |
657 | ClassDB::bind_method(D_METHOD("set_gravity_is_point" , "enable" ), &Area3D::set_gravity_is_point); |
658 | ClassDB::bind_method(D_METHOD("is_gravity_a_point" ), &Area3D::is_gravity_a_point); |
659 | |
660 | ClassDB::bind_method(D_METHOD("set_gravity_point_unit_distance" , "distance_scale" ), &Area3D::set_gravity_point_unit_distance); |
661 | ClassDB::bind_method(D_METHOD("get_gravity_point_unit_distance" ), &Area3D::get_gravity_point_unit_distance); |
662 | |
663 | ClassDB::bind_method(D_METHOD("set_gravity_point_center" , "center" ), &Area3D::set_gravity_point_center); |
664 | ClassDB::bind_method(D_METHOD("get_gravity_point_center" ), &Area3D::get_gravity_point_center); |
665 | |
666 | ClassDB::bind_method(D_METHOD("set_gravity_direction" , "direction" ), &Area3D::set_gravity_direction); |
667 | ClassDB::bind_method(D_METHOD("get_gravity_direction" ), &Area3D::get_gravity_direction); |
668 | |
669 | ClassDB::bind_method(D_METHOD("set_gravity" , "gravity" ), &Area3D::set_gravity); |
670 | ClassDB::bind_method(D_METHOD("get_gravity" ), &Area3D::get_gravity); |
671 | |
672 | ClassDB::bind_method(D_METHOD("set_linear_damp_space_override_mode" , "space_override_mode" ), &Area3D::set_linear_damp_space_override_mode); |
673 | ClassDB::bind_method(D_METHOD("get_linear_damp_space_override_mode" ), &Area3D::get_linear_damp_space_override_mode); |
674 | |
675 | ClassDB::bind_method(D_METHOD("set_angular_damp_space_override_mode" , "space_override_mode" ), &Area3D::set_angular_damp_space_override_mode); |
676 | ClassDB::bind_method(D_METHOD("get_angular_damp_space_override_mode" ), &Area3D::get_angular_damp_space_override_mode); |
677 | |
678 | ClassDB::bind_method(D_METHOD("set_angular_damp" , "angular_damp" ), &Area3D::set_angular_damp); |
679 | ClassDB::bind_method(D_METHOD("get_angular_damp" ), &Area3D::get_angular_damp); |
680 | |
681 | ClassDB::bind_method(D_METHOD("set_linear_damp" , "linear_damp" ), &Area3D::set_linear_damp); |
682 | ClassDB::bind_method(D_METHOD("get_linear_damp" ), &Area3D::get_linear_damp); |
683 | |
684 | ClassDB::bind_method(D_METHOD("set_priority" , "priority" ), &Area3D::set_priority); |
685 | ClassDB::bind_method(D_METHOD("get_priority" ), &Area3D::get_priority); |
686 | |
687 | ClassDB::bind_method(D_METHOD("set_wind_force_magnitude" , "wind_force_magnitude" ), &Area3D::set_wind_force_magnitude); |
688 | ClassDB::bind_method(D_METHOD("get_wind_force_magnitude" ), &Area3D::get_wind_force_magnitude); |
689 | |
690 | ClassDB::bind_method(D_METHOD("set_wind_attenuation_factor" , "wind_attenuation_factor" ), &Area3D::set_wind_attenuation_factor); |
691 | ClassDB::bind_method(D_METHOD("get_wind_attenuation_factor" ), &Area3D::get_wind_attenuation_factor); |
692 | |
693 | ClassDB::bind_method(D_METHOD("set_wind_source_path" , "wind_source_path" ), &Area3D::set_wind_source_path); |
694 | ClassDB::bind_method(D_METHOD("get_wind_source_path" ), &Area3D::get_wind_source_path); |
695 | |
696 | ClassDB::bind_method(D_METHOD("set_monitorable" , "enable" ), &Area3D::set_monitorable); |
697 | ClassDB::bind_method(D_METHOD("is_monitorable" ), &Area3D::is_monitorable); |
698 | |
699 | ClassDB::bind_method(D_METHOD("set_monitoring" , "enable" ), &Area3D::set_monitoring); |
700 | ClassDB::bind_method(D_METHOD("is_monitoring" ), &Area3D::is_monitoring); |
701 | |
702 | ClassDB::bind_method(D_METHOD("get_overlapping_bodies" ), &Area3D::get_overlapping_bodies); |
703 | ClassDB::bind_method(D_METHOD("get_overlapping_areas" ), &Area3D::get_overlapping_areas); |
704 | |
705 | ClassDB::bind_method(D_METHOD("has_overlapping_bodies" ), &Area3D::has_overlapping_bodies); |
706 | ClassDB::bind_method(D_METHOD("has_overlapping_areas" ), &Area3D::has_overlapping_areas); |
707 | |
708 | ClassDB::bind_method(D_METHOD("overlaps_body" , "body" ), &Area3D::overlaps_body); |
709 | ClassDB::bind_method(D_METHOD("overlaps_area" , "area" ), &Area3D::overlaps_area); |
710 | |
711 | ClassDB::bind_method(D_METHOD("set_audio_bus_override" , "enable" ), &Area3D::set_audio_bus_override); |
712 | ClassDB::bind_method(D_METHOD("is_overriding_audio_bus" ), &Area3D::is_overriding_audio_bus); |
713 | |
714 | ClassDB::bind_method(D_METHOD("set_audio_bus_name" , "name" ), &Area3D::set_audio_bus_name); |
715 | ClassDB::bind_method(D_METHOD("get_audio_bus_name" ), &Area3D::get_audio_bus_name); |
716 | |
717 | ClassDB::bind_method(D_METHOD("set_use_reverb_bus" , "enable" ), &Area3D::set_use_reverb_bus); |
718 | ClassDB::bind_method(D_METHOD("is_using_reverb_bus" ), &Area3D::is_using_reverb_bus); |
719 | |
720 | ClassDB::bind_method(D_METHOD("set_reverb_bus_name" , "name" ), &Area3D::set_reverb_bus_name); |
721 | ClassDB::bind_method(D_METHOD("get_reverb_bus_name" ), &Area3D::get_reverb_bus_name); |
722 | |
723 | ClassDB::bind_method(D_METHOD("set_reverb_amount" , "amount" ), &Area3D::set_reverb_amount); |
724 | ClassDB::bind_method(D_METHOD("get_reverb_amount" ), &Area3D::get_reverb_amount); |
725 | |
726 | ClassDB::bind_method(D_METHOD("set_reverb_uniformity" , "amount" ), &Area3D::set_reverb_uniformity); |
727 | ClassDB::bind_method(D_METHOD("get_reverb_uniformity" ), &Area3D::get_reverb_uniformity); |
728 | |
729 | ADD_SIGNAL(MethodInfo("body_shape_entered" , PropertyInfo(Variant::RID, "body_rid" ), PropertyInfo(Variant::OBJECT, "body" , PROPERTY_HINT_RESOURCE_TYPE, "Node3D" ), PropertyInfo(Variant::INT, "body_shape_index" ), PropertyInfo(Variant::INT, "local_shape_index" ))); |
730 | ADD_SIGNAL(MethodInfo("body_shape_exited" , PropertyInfo(Variant::RID, "body_rid" ), PropertyInfo(Variant::OBJECT, "body" , PROPERTY_HINT_RESOURCE_TYPE, "Node3D" ), PropertyInfo(Variant::INT, "body_shape_index" ), PropertyInfo(Variant::INT, "local_shape_index" ))); |
731 | ADD_SIGNAL(MethodInfo("body_entered" , PropertyInfo(Variant::OBJECT, "body" , PROPERTY_HINT_RESOURCE_TYPE, "Node3D" ))); |
732 | ADD_SIGNAL(MethodInfo("body_exited" , PropertyInfo(Variant::OBJECT, "body" , PROPERTY_HINT_RESOURCE_TYPE, "Node3D" ))); |
733 | |
734 | ADD_SIGNAL(MethodInfo("area_shape_entered" , PropertyInfo(Variant::RID, "area_rid" ), PropertyInfo(Variant::OBJECT, "area" , PROPERTY_HINT_RESOURCE_TYPE, "Area3D" ), PropertyInfo(Variant::INT, "area_shape_index" ), PropertyInfo(Variant::INT, "local_shape_index" ))); |
735 | ADD_SIGNAL(MethodInfo("area_shape_exited" , PropertyInfo(Variant::RID, "area_rid" ), PropertyInfo(Variant::OBJECT, "area" , PROPERTY_HINT_RESOURCE_TYPE, "Area3D" ), PropertyInfo(Variant::INT, "area_shape_index" ), PropertyInfo(Variant::INT, "local_shape_index" ))); |
736 | ADD_SIGNAL(MethodInfo("area_entered" , PropertyInfo(Variant::OBJECT, "area" , PROPERTY_HINT_RESOURCE_TYPE, "Area3D" ))); |
737 | ADD_SIGNAL(MethodInfo("area_exited" , PropertyInfo(Variant::OBJECT, "area" , PROPERTY_HINT_RESOURCE_TYPE, "Area3D" ))); |
738 | |
739 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring" ), "set_monitoring" , "is_monitoring" ); |
740 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable" ), "set_monitorable" , "is_monitorable" ); |
741 | ADD_PROPERTY(PropertyInfo(Variant::INT, "priority" , PROPERTY_HINT_RANGE, "0,100000,1,or_greater,or_less" ), "set_priority" , "get_priority" ); |
742 | |
743 | ADD_GROUP("Gravity" , "gravity_" ); |
744 | ADD_PROPERTY(PropertyInfo(Variant::INT, "gravity_space_override" , PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine" , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_space_override_mode" , "get_gravity_space_override_mode" ); |
745 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point" , PROPERTY_HINT_NONE, "" , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_is_point" , "is_gravity_a_point" ); |
746 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_unit_distance" , PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp,suffix:m" ), "set_gravity_point_unit_distance" , "get_gravity_point_unit_distance" ); |
747 | ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_point_center" , PROPERTY_HINT_NONE, "suffix:m" ), "set_gravity_point_center" , "get_gravity_point_center" ); |
748 | ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_direction" ), "set_gravity_direction" , "get_gravity_direction" ); |
749 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity" , PROPERTY_HINT_RANGE, U"-32,32,0.001,or_less,or_greater,suffix:m/s\u00B2" ), "set_gravity" , "get_gravity" ); |
750 | |
751 | ADD_GROUP("Linear Damp" , "linear_damp_" ); |
752 | ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_space_override" , PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine" , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_linear_damp_space_override_mode" , "get_linear_damp_space_override_mode" ); |
753 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp" , PROPERTY_HINT_RANGE, "0,100,0.001,or_greater" ), "set_linear_damp" , "get_linear_damp" ); |
754 | |
755 | ADD_GROUP("Angular Damp" , "angular_damp_" ); |
756 | ADD_PROPERTY(PropertyInfo(Variant::INT, "angular_damp_space_override" , PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine" , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_angular_damp_space_override_mode" , "get_angular_damp_space_override_mode" ); |
757 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp" , PROPERTY_HINT_RANGE, "0,100,0.001,or_greater" ), "set_angular_damp" , "get_angular_damp" ); |
758 | |
759 | ADD_GROUP("Wind" , "wind_" ); |
760 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wind_force_magnitude" , PROPERTY_HINT_RANGE, "0,10,0.001,or_greater" ), "set_wind_force_magnitude" , "get_wind_force_magnitude" ); |
761 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wind_attenuation_factor" , PROPERTY_HINT_RANGE, "0.0,3.0,0.001,or_greater" ), "set_wind_attenuation_factor" , "get_wind_attenuation_factor" ); |
762 | ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "wind_source_path" , PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D" ), "set_wind_source_path" , "get_wind_source_path" ); |
763 | |
764 | ADD_GROUP("Audio Bus" , "audio_bus_" ); |
765 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override" ), "set_audio_bus_override" , "is_overriding_audio_bus" ); |
766 | ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name" , PROPERTY_HINT_ENUM, "" ), "set_audio_bus_name" , "get_audio_bus_name" ); |
767 | |
768 | ADD_GROUP("Reverb Bus" , "reverb_bus_" ); |
769 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enabled" ), "set_use_reverb_bus" , "is_using_reverb_bus" ); |
770 | ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name" , PROPERTY_HINT_ENUM, "" ), "set_reverb_bus_name" , "get_reverb_bus_name" ); |
771 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_amount" , PROPERTY_HINT_RANGE, "0,1,0.01" ), "set_reverb_amount" , "get_reverb_amount" ); |
772 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_uniformity" , PROPERTY_HINT_RANGE, "0,1,0.01" ), "set_reverb_uniformity" , "get_reverb_uniformity" ); |
773 | |
774 | BIND_ENUM_CONSTANT(SPACE_OVERRIDE_DISABLED); |
775 | BIND_ENUM_CONSTANT(SPACE_OVERRIDE_COMBINE); |
776 | BIND_ENUM_CONSTANT(SPACE_OVERRIDE_COMBINE_REPLACE); |
777 | BIND_ENUM_CONSTANT(SPACE_OVERRIDE_REPLACE); |
778 | BIND_ENUM_CONSTANT(SPACE_OVERRIDE_REPLACE_COMBINE); |
779 | } |
780 | |
781 | Area3D::Area3D() : |
782 | CollisionObject3D(PhysicsServer3D::get_singleton()->area_create(), true) { |
783 | set_gravity(9.8); |
784 | set_gravity_direction(Vector3(0, -1, 0)); |
785 | set_monitoring(true); |
786 | set_monitorable(true); |
787 | } |
788 | |
789 | Area3D::~Area3D() { |
790 | } |
791 | |