1 | /**************************************************************************/ |
2 | /* collision_object_2d.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 "collision_object_2d.h" |
32 | |
33 | #include "scene/resources/world_2d.h" |
34 | #include "scene/scene_string_names.h" |
35 | |
36 | void CollisionObject2D::_notification(int p_what) { |
37 | switch (p_what) { |
38 | case NOTIFICATION_ENTER_TREE: { |
39 | Transform2D gl_transform = get_global_transform(); |
40 | |
41 | if (area) { |
42 | PhysicsServer2D::get_singleton()->area_set_transform(rid, gl_transform); |
43 | } else { |
44 | PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, gl_transform); |
45 | } |
46 | |
47 | bool disabled = !is_enabled(); |
48 | |
49 | if (disabled && (disable_mode != DISABLE_MODE_REMOVE)) { |
50 | _apply_disabled(); |
51 | } |
52 | |
53 | if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) { |
54 | Ref<World2D> world_ref = get_world_2d(); |
55 | ERR_FAIL_COND(!world_ref.is_valid()); |
56 | RID space = world_ref->get_space(); |
57 | if (area) { |
58 | PhysicsServer2D::get_singleton()->area_set_space(rid, space); |
59 | } else { |
60 | PhysicsServer2D::get_singleton()->body_set_space(rid, space); |
61 | } |
62 | } |
63 | |
64 | _update_pickable(); |
65 | } break; |
66 | |
67 | case NOTIFICATION_ENTER_CANVAS: { |
68 | if (area) { |
69 | PhysicsServer2D::get_singleton()->area_attach_canvas_instance_id(rid, get_canvas_layer_instance_id()); |
70 | } else { |
71 | PhysicsServer2D::get_singleton()->body_attach_canvas_instance_id(rid, get_canvas_layer_instance_id()); |
72 | } |
73 | } break; |
74 | |
75 | case NOTIFICATION_VISIBILITY_CHANGED: { |
76 | _update_pickable(); |
77 | } break; |
78 | |
79 | case NOTIFICATION_TRANSFORM_CHANGED: { |
80 | if (only_update_transform_changes) { |
81 | return; |
82 | } |
83 | |
84 | Transform2D gl_transform = get_global_transform(); |
85 | |
86 | if (area) { |
87 | PhysicsServer2D::get_singleton()->area_set_transform(rid, gl_transform); |
88 | } else { |
89 | PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, gl_transform); |
90 | } |
91 | } break; |
92 | |
93 | case NOTIFICATION_EXIT_TREE: { |
94 | bool disabled = !is_enabled(); |
95 | |
96 | if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) { |
97 | if (callback_lock > 0) { |
98 | ERR_PRINT("Removing a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Remove with call_deferred() instead." ); |
99 | } else { |
100 | if (area) { |
101 | PhysicsServer2D::get_singleton()->area_set_space(rid, RID()); |
102 | } else { |
103 | PhysicsServer2D::get_singleton()->body_set_space(rid, RID()); |
104 | } |
105 | } |
106 | } |
107 | |
108 | if (disabled && (disable_mode != DISABLE_MODE_REMOVE)) { |
109 | _apply_enabled(); |
110 | } |
111 | } break; |
112 | |
113 | case NOTIFICATION_EXIT_CANVAS: { |
114 | if (area) { |
115 | PhysicsServer2D::get_singleton()->area_attach_canvas_instance_id(rid, ObjectID()); |
116 | } else { |
117 | PhysicsServer2D::get_singleton()->body_attach_canvas_instance_id(rid, ObjectID()); |
118 | } |
119 | } break; |
120 | |
121 | case NOTIFICATION_WORLD_2D_CHANGED: { |
122 | RID space = get_world_2d()->get_space(); |
123 | if (area) { |
124 | PhysicsServer2D::get_singleton()->area_set_space(rid, space); |
125 | } else { |
126 | PhysicsServer2D::get_singleton()->body_set_space(rid, space); |
127 | } |
128 | } break; |
129 | |
130 | case NOTIFICATION_DISABLED: { |
131 | _apply_disabled(); |
132 | } break; |
133 | |
134 | case NOTIFICATION_ENABLED: { |
135 | _apply_enabled(); |
136 | } break; |
137 | } |
138 | } |
139 | |
140 | void CollisionObject2D::set_collision_layer(uint32_t p_layer) { |
141 | collision_layer = p_layer; |
142 | if (area) { |
143 | PhysicsServer2D::get_singleton()->area_set_collision_layer(get_rid(), p_layer); |
144 | } else { |
145 | PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), p_layer); |
146 | } |
147 | } |
148 | |
149 | uint32_t CollisionObject2D::get_collision_layer() const { |
150 | return collision_layer; |
151 | } |
152 | |
153 | void CollisionObject2D::set_collision_mask(uint32_t p_mask) { |
154 | collision_mask = p_mask; |
155 | if (area) { |
156 | PhysicsServer2D::get_singleton()->area_set_collision_mask(get_rid(), p_mask); |
157 | } else { |
158 | PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), p_mask); |
159 | } |
160 | } |
161 | |
162 | uint32_t CollisionObject2D::get_collision_mask() const { |
163 | return collision_mask; |
164 | } |
165 | |
166 | void CollisionObject2D::set_collision_layer_value(int p_layer_number, bool p_value) { |
167 | ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive." ); |
168 | ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive." ); |
169 | uint32_t collision_layer_new = get_collision_layer(); |
170 | if (p_value) { |
171 | collision_layer_new |= 1 << (p_layer_number - 1); |
172 | } else { |
173 | collision_layer_new &= ~(1 << (p_layer_number - 1)); |
174 | } |
175 | set_collision_layer(collision_layer_new); |
176 | } |
177 | |
178 | bool CollisionObject2D::get_collision_layer_value(int p_layer_number) const { |
179 | ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive." ); |
180 | ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive." ); |
181 | return get_collision_layer() & (1 << (p_layer_number - 1)); |
182 | } |
183 | |
184 | void CollisionObject2D::set_collision_mask_value(int p_layer_number, bool p_value) { |
185 | ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive." ); |
186 | ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive." ); |
187 | uint32_t mask = get_collision_mask(); |
188 | if (p_value) { |
189 | mask |= 1 << (p_layer_number - 1); |
190 | } else { |
191 | mask &= ~(1 << (p_layer_number - 1)); |
192 | } |
193 | set_collision_mask(mask); |
194 | } |
195 | |
196 | bool CollisionObject2D::get_collision_mask_value(int p_layer_number) const { |
197 | ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive." ); |
198 | ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive." ); |
199 | return get_collision_mask() & (1 << (p_layer_number - 1)); |
200 | } |
201 | |
202 | void CollisionObject2D::set_collision_priority(real_t p_priority) { |
203 | collision_priority = p_priority; |
204 | if (!area) { |
205 | PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), p_priority); |
206 | } |
207 | } |
208 | |
209 | real_t CollisionObject2D::get_collision_priority() const { |
210 | return collision_priority; |
211 | } |
212 | |
213 | void CollisionObject2D::set_disable_mode(DisableMode p_mode) { |
214 | if (disable_mode == p_mode) { |
215 | return; |
216 | } |
217 | |
218 | bool disabled = is_inside_tree() && !is_enabled(); |
219 | |
220 | if (disabled) { |
221 | // Cancel previous disable mode. |
222 | _apply_enabled(); |
223 | } |
224 | |
225 | disable_mode = p_mode; |
226 | |
227 | if (disabled) { |
228 | // Apply new disable mode. |
229 | _apply_disabled(); |
230 | } |
231 | } |
232 | |
233 | CollisionObject2D::DisableMode CollisionObject2D::get_disable_mode() const { |
234 | return disable_mode; |
235 | } |
236 | |
237 | void CollisionObject2D::_apply_disabled() { |
238 | switch (disable_mode) { |
239 | case DISABLE_MODE_REMOVE: { |
240 | if (is_inside_tree()) { |
241 | if (callback_lock > 0) { |
242 | ERR_PRINT("Disabling a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Disable with call_deferred() instead." ); |
243 | } else { |
244 | if (area) { |
245 | PhysicsServer2D::get_singleton()->area_set_space(rid, RID()); |
246 | } else { |
247 | PhysicsServer2D::get_singleton()->body_set_space(rid, RID()); |
248 | } |
249 | } |
250 | } |
251 | } break; |
252 | |
253 | case DISABLE_MODE_MAKE_STATIC: { |
254 | if (!area && (body_mode != PhysicsServer2D::BODY_MODE_STATIC)) { |
255 | PhysicsServer2D::get_singleton()->body_set_mode(rid, PhysicsServer2D::BODY_MODE_STATIC); |
256 | } |
257 | } break; |
258 | |
259 | case DISABLE_MODE_KEEP_ACTIVE: { |
260 | // Nothing to do. |
261 | } break; |
262 | } |
263 | } |
264 | |
265 | void CollisionObject2D::_apply_enabled() { |
266 | switch (disable_mode) { |
267 | case DISABLE_MODE_REMOVE: { |
268 | if (is_inside_tree()) { |
269 | RID space = get_world_2d()->get_space(); |
270 | if (area) { |
271 | PhysicsServer2D::get_singleton()->area_set_space(rid, space); |
272 | } else { |
273 | PhysicsServer2D::get_singleton()->body_set_space(rid, space); |
274 | } |
275 | } |
276 | } break; |
277 | |
278 | case DISABLE_MODE_MAKE_STATIC: { |
279 | if (!area && (body_mode != PhysicsServer2D::BODY_MODE_STATIC)) { |
280 | PhysicsServer2D::get_singleton()->body_set_mode(rid, body_mode); |
281 | } |
282 | } break; |
283 | |
284 | case DISABLE_MODE_KEEP_ACTIVE: { |
285 | // Nothing to do. |
286 | } break; |
287 | } |
288 | } |
289 | |
290 | uint32_t CollisionObject2D::create_shape_owner(Object *p_owner) { |
291 | ShapeData sd; |
292 | uint32_t id; |
293 | |
294 | if (shapes.size() == 0) { |
295 | id = 0; |
296 | } else { |
297 | id = shapes.back()->key() + 1; |
298 | } |
299 | |
300 | sd.owner_id = p_owner ? p_owner->get_instance_id() : ObjectID(); |
301 | |
302 | shapes[id] = sd; |
303 | |
304 | return id; |
305 | } |
306 | |
307 | void CollisionObject2D::remove_shape_owner(uint32_t owner) { |
308 | ERR_FAIL_COND(!shapes.has(owner)); |
309 | |
310 | shape_owner_clear_shapes(owner); |
311 | |
312 | shapes.erase(owner); |
313 | } |
314 | |
315 | void CollisionObject2D::shape_owner_set_disabled(uint32_t p_owner, bool p_disabled) { |
316 | ERR_FAIL_COND(!shapes.has(p_owner)); |
317 | |
318 | ShapeData &sd = shapes[p_owner]; |
319 | sd.disabled = p_disabled; |
320 | for (int i = 0; i < sd.shapes.size(); i++) { |
321 | if (area) { |
322 | PhysicsServer2D::get_singleton()->area_set_shape_disabled(rid, sd.shapes[i].index, p_disabled); |
323 | } else { |
324 | PhysicsServer2D::get_singleton()->body_set_shape_disabled(rid, sd.shapes[i].index, p_disabled); |
325 | } |
326 | } |
327 | } |
328 | |
329 | bool CollisionObject2D::is_shape_owner_disabled(uint32_t p_owner) const { |
330 | ERR_FAIL_COND_V(!shapes.has(p_owner), false); |
331 | |
332 | return shapes[p_owner].disabled; |
333 | } |
334 | |
335 | void CollisionObject2D::shape_owner_set_one_way_collision(uint32_t p_owner, bool p_enable) { |
336 | if (area) { |
337 | return; //not for areas |
338 | } |
339 | |
340 | ERR_FAIL_COND(!shapes.has(p_owner)); |
341 | |
342 | ShapeData &sd = shapes[p_owner]; |
343 | sd.one_way_collision = p_enable; |
344 | for (int i = 0; i < sd.shapes.size(); i++) { |
345 | PhysicsServer2D::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, sd.one_way_collision, sd.one_way_collision_margin); |
346 | } |
347 | } |
348 | |
349 | bool CollisionObject2D::is_shape_owner_one_way_collision_enabled(uint32_t p_owner) const { |
350 | ERR_FAIL_COND_V(!shapes.has(p_owner), false); |
351 | |
352 | return shapes[p_owner].one_way_collision; |
353 | } |
354 | |
355 | void CollisionObject2D::shape_owner_set_one_way_collision_margin(uint32_t p_owner, real_t p_margin) { |
356 | if (area) { |
357 | return; //not for areas |
358 | } |
359 | |
360 | ERR_FAIL_COND(!shapes.has(p_owner)); |
361 | |
362 | ShapeData &sd = shapes[p_owner]; |
363 | sd.one_way_collision_margin = p_margin; |
364 | for (int i = 0; i < sd.shapes.size(); i++) { |
365 | PhysicsServer2D::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, sd.one_way_collision, sd.one_way_collision_margin); |
366 | } |
367 | } |
368 | |
369 | real_t CollisionObject2D::get_shape_owner_one_way_collision_margin(uint32_t p_owner) const { |
370 | ERR_FAIL_COND_V(!shapes.has(p_owner), 0); |
371 | |
372 | return shapes[p_owner].one_way_collision_margin; |
373 | } |
374 | |
375 | void CollisionObject2D::get_shape_owners(List<uint32_t> *r_owners) { |
376 | for (const KeyValue<uint32_t, ShapeData> &E : shapes) { |
377 | r_owners->push_back(E.key); |
378 | } |
379 | } |
380 | |
381 | PackedInt32Array CollisionObject2D::_get_shape_owners() { |
382 | PackedInt32Array ret; |
383 | for (const KeyValue<uint32_t, ShapeData> &E : shapes) { |
384 | ret.push_back(E.key); |
385 | } |
386 | |
387 | return ret; |
388 | } |
389 | |
390 | void CollisionObject2D::shape_owner_set_transform(uint32_t p_owner, const Transform2D &p_transform) { |
391 | ERR_FAIL_COND(!shapes.has(p_owner)); |
392 | |
393 | ShapeData &sd = shapes[p_owner]; |
394 | |
395 | sd.xform = p_transform; |
396 | for (int i = 0; i < sd.shapes.size(); i++) { |
397 | if (area) { |
398 | PhysicsServer2D::get_singleton()->area_set_shape_transform(rid, sd.shapes[i].index, sd.xform); |
399 | } else { |
400 | PhysicsServer2D::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, sd.xform); |
401 | } |
402 | } |
403 | } |
404 | |
405 | Transform2D CollisionObject2D::shape_owner_get_transform(uint32_t p_owner) const { |
406 | ERR_FAIL_COND_V(!shapes.has(p_owner), Transform2D()); |
407 | |
408 | return shapes[p_owner].xform; |
409 | } |
410 | |
411 | Object *CollisionObject2D::shape_owner_get_owner(uint32_t p_owner) const { |
412 | ERR_FAIL_COND_V(!shapes.has(p_owner), nullptr); |
413 | |
414 | return ObjectDB::get_instance(shapes[p_owner].owner_id); |
415 | } |
416 | |
417 | void CollisionObject2D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2D> &p_shape) { |
418 | ERR_FAIL_COND(!shapes.has(p_owner)); |
419 | ERR_FAIL_COND(p_shape.is_null()); |
420 | |
421 | ShapeData &sd = shapes[p_owner]; |
422 | ShapeData::Shape s; |
423 | s.index = total_subshapes; |
424 | s.shape = p_shape; |
425 | if (area) { |
426 | PhysicsServer2D::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled); |
427 | } else { |
428 | PhysicsServer2D::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled); |
429 | } |
430 | sd.shapes.push_back(s); |
431 | |
432 | total_subshapes++; |
433 | } |
434 | |
435 | int CollisionObject2D::shape_owner_get_shape_count(uint32_t p_owner) const { |
436 | ERR_FAIL_COND_V(!shapes.has(p_owner), 0); |
437 | |
438 | return shapes[p_owner].shapes.size(); |
439 | } |
440 | |
441 | Ref<Shape2D> CollisionObject2D::shape_owner_get_shape(uint32_t p_owner, int p_shape) const { |
442 | ERR_FAIL_COND_V(!shapes.has(p_owner), Ref<Shape2D>()); |
443 | ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), Ref<Shape2D>()); |
444 | |
445 | return shapes[p_owner].shapes[p_shape].shape; |
446 | } |
447 | |
448 | int CollisionObject2D::shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const { |
449 | ERR_FAIL_COND_V(!shapes.has(p_owner), -1); |
450 | ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), -1); |
451 | |
452 | return shapes[p_owner].shapes[p_shape].index; |
453 | } |
454 | |
455 | void CollisionObject2D::shape_owner_remove_shape(uint32_t p_owner, int p_shape) { |
456 | ERR_FAIL_COND(!shapes.has(p_owner)); |
457 | ERR_FAIL_INDEX(p_shape, shapes[p_owner].shapes.size()); |
458 | |
459 | int index_to_remove = shapes[p_owner].shapes[p_shape].index; |
460 | if (area) { |
461 | PhysicsServer2D::get_singleton()->area_remove_shape(rid, index_to_remove); |
462 | } else { |
463 | PhysicsServer2D::get_singleton()->body_remove_shape(rid, index_to_remove); |
464 | } |
465 | |
466 | shapes[p_owner].shapes.remove_at(p_shape); |
467 | |
468 | for (KeyValue<uint32_t, ShapeData> &E : shapes) { |
469 | for (int i = 0; i < E.value.shapes.size(); i++) { |
470 | if (E.value.shapes[i].index > index_to_remove) { |
471 | E.value.shapes.write[i].index -= 1; |
472 | } |
473 | } |
474 | } |
475 | |
476 | total_subshapes--; |
477 | } |
478 | |
479 | void CollisionObject2D::shape_owner_clear_shapes(uint32_t p_owner) { |
480 | ERR_FAIL_COND(!shapes.has(p_owner)); |
481 | |
482 | while (shape_owner_get_shape_count(p_owner) > 0) { |
483 | shape_owner_remove_shape(p_owner, 0); |
484 | } |
485 | } |
486 | |
487 | uint32_t CollisionObject2D::shape_find_owner(int p_shape_index) const { |
488 | ERR_FAIL_INDEX_V(p_shape_index, total_subshapes, UINT32_MAX); |
489 | |
490 | for (const KeyValue<uint32_t, ShapeData> &E : shapes) { |
491 | for (int i = 0; i < E.value.shapes.size(); i++) { |
492 | if (E.value.shapes[i].index == p_shape_index) { |
493 | return E.key; |
494 | } |
495 | } |
496 | } |
497 | |
498 | //in theory it should be unreachable |
499 | ERR_FAIL_V_MSG(UINT32_MAX, "Can't find owner for shape index " + itos(p_shape_index) + "." ); |
500 | } |
501 | |
502 | void CollisionObject2D::set_pickable(bool p_enabled) { |
503 | if (pickable == p_enabled) { |
504 | return; |
505 | } |
506 | |
507 | pickable = p_enabled; |
508 | _update_pickable(); |
509 | } |
510 | |
511 | bool CollisionObject2D::is_pickable() const { |
512 | return pickable; |
513 | } |
514 | |
515 | void CollisionObject2D::_input_event_call(Viewport *p_viewport, const Ref<InputEvent> &p_input_event, int p_shape) { |
516 | GDVIRTUAL_CALL(_input_event, p_viewport, p_input_event, p_shape); |
517 | emit_signal(SceneStringNames::get_singleton()->input_event, p_viewport, p_input_event, p_shape); |
518 | } |
519 | |
520 | void CollisionObject2D::_mouse_enter() { |
521 | if (get_script_instance()) { |
522 | get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_enter); |
523 | } |
524 | emit_signal(SceneStringNames::get_singleton()->mouse_entered); |
525 | } |
526 | |
527 | void CollisionObject2D::_mouse_exit() { |
528 | if (get_script_instance()) { |
529 | get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_exit); |
530 | } |
531 | emit_signal(SceneStringNames::get_singleton()->mouse_exited); |
532 | } |
533 | |
534 | void CollisionObject2D::_mouse_shape_enter(int p_shape) { |
535 | if (get_script_instance()) { |
536 | get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_shape_enter, p_shape); |
537 | } |
538 | emit_signal(SceneStringNames::get_singleton()->mouse_shape_entered, p_shape); |
539 | } |
540 | |
541 | void CollisionObject2D::_mouse_shape_exit(int p_shape) { |
542 | if (get_script_instance()) { |
543 | get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_shape_exit, p_shape); |
544 | } |
545 | emit_signal(SceneStringNames::get_singleton()->mouse_shape_exited, p_shape); |
546 | } |
547 | |
548 | void CollisionObject2D::set_only_update_transform_changes(bool p_enable) { |
549 | only_update_transform_changes = p_enable; |
550 | } |
551 | |
552 | bool CollisionObject2D::is_only_update_transform_changes_enabled() const { |
553 | return only_update_transform_changes; |
554 | } |
555 | |
556 | void CollisionObject2D::set_body_mode(PhysicsServer2D::BodyMode p_mode) { |
557 | ERR_FAIL_COND(area); |
558 | |
559 | if (body_mode == p_mode) { |
560 | return; |
561 | } |
562 | |
563 | body_mode = p_mode; |
564 | |
565 | if (is_inside_tree() && !is_enabled() && (disable_mode == DISABLE_MODE_MAKE_STATIC)) { |
566 | return; |
567 | } |
568 | |
569 | PhysicsServer2D::get_singleton()->body_set_mode(rid, p_mode); |
570 | } |
571 | |
572 | void CollisionObject2D::_update_pickable() { |
573 | if (!is_inside_tree()) { |
574 | return; |
575 | } |
576 | |
577 | bool is_pickable = pickable && is_visible_in_tree(); |
578 | if (area) { |
579 | PhysicsServer2D::get_singleton()->area_set_pickable(rid, is_pickable); |
580 | } else { |
581 | PhysicsServer2D::get_singleton()->body_set_pickable(rid, is_pickable); |
582 | } |
583 | } |
584 | |
585 | PackedStringArray CollisionObject2D::get_configuration_warnings() const { |
586 | PackedStringArray warnings = Node::get_configuration_warnings(); |
587 | |
588 | if (shapes.is_empty()) { |
589 | warnings.push_back(RTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape." )); |
590 | } |
591 | |
592 | return warnings; |
593 | } |
594 | |
595 | void CollisionObject2D::_bind_methods() { |
596 | ClassDB::bind_method(D_METHOD("get_rid" ), &CollisionObject2D::get_rid); |
597 | ClassDB::bind_method(D_METHOD("set_collision_layer" , "layer" ), &CollisionObject2D::set_collision_layer); |
598 | ClassDB::bind_method(D_METHOD("get_collision_layer" ), &CollisionObject2D::get_collision_layer); |
599 | ClassDB::bind_method(D_METHOD("set_collision_mask" , "mask" ), &CollisionObject2D::set_collision_mask); |
600 | ClassDB::bind_method(D_METHOD("get_collision_mask" ), &CollisionObject2D::get_collision_mask); |
601 | ClassDB::bind_method(D_METHOD("set_collision_layer_value" , "layer_number" , "value" ), &CollisionObject2D::set_collision_layer_value); |
602 | ClassDB::bind_method(D_METHOD("get_collision_layer_value" , "layer_number" ), &CollisionObject2D::get_collision_layer_value); |
603 | ClassDB::bind_method(D_METHOD("set_collision_mask_value" , "layer_number" , "value" ), &CollisionObject2D::set_collision_mask_value); |
604 | ClassDB::bind_method(D_METHOD("get_collision_mask_value" , "layer_number" ), &CollisionObject2D::get_collision_mask_value); |
605 | ClassDB::bind_method(D_METHOD("set_collision_priority" , "priority" ), &CollisionObject2D::set_collision_priority); |
606 | ClassDB::bind_method(D_METHOD("get_collision_priority" ), &CollisionObject2D::get_collision_priority); |
607 | ClassDB::bind_method(D_METHOD("set_disable_mode" , "mode" ), &CollisionObject2D::set_disable_mode); |
608 | ClassDB::bind_method(D_METHOD("get_disable_mode" ), &CollisionObject2D::get_disable_mode); |
609 | ClassDB::bind_method(D_METHOD("set_pickable" , "enabled" ), &CollisionObject2D::set_pickable); |
610 | ClassDB::bind_method(D_METHOD("is_pickable" ), &CollisionObject2D::is_pickable); |
611 | ClassDB::bind_method(D_METHOD("create_shape_owner" , "owner" ), &CollisionObject2D::create_shape_owner); |
612 | ClassDB::bind_method(D_METHOD("remove_shape_owner" , "owner_id" ), &CollisionObject2D::remove_shape_owner); |
613 | ClassDB::bind_method(D_METHOD("get_shape_owners" ), &CollisionObject2D::_get_shape_owners); |
614 | ClassDB::bind_method(D_METHOD("shape_owner_set_transform" , "owner_id" , "transform" ), &CollisionObject2D::shape_owner_set_transform); |
615 | ClassDB::bind_method(D_METHOD("shape_owner_get_transform" , "owner_id" ), &CollisionObject2D::shape_owner_get_transform); |
616 | ClassDB::bind_method(D_METHOD("shape_owner_get_owner" , "owner_id" ), &CollisionObject2D::shape_owner_get_owner); |
617 | ClassDB::bind_method(D_METHOD("shape_owner_set_disabled" , "owner_id" , "disabled" ), &CollisionObject2D::shape_owner_set_disabled); |
618 | ClassDB::bind_method(D_METHOD("is_shape_owner_disabled" , "owner_id" ), &CollisionObject2D::is_shape_owner_disabled); |
619 | ClassDB::bind_method(D_METHOD("shape_owner_set_one_way_collision" , "owner_id" , "enable" ), &CollisionObject2D::shape_owner_set_one_way_collision); |
620 | ClassDB::bind_method(D_METHOD("is_shape_owner_one_way_collision_enabled" , "owner_id" ), &CollisionObject2D::is_shape_owner_one_way_collision_enabled); |
621 | ClassDB::bind_method(D_METHOD("shape_owner_set_one_way_collision_margin" , "owner_id" , "margin" ), &CollisionObject2D::shape_owner_set_one_way_collision_margin); |
622 | ClassDB::bind_method(D_METHOD("get_shape_owner_one_way_collision_margin" , "owner_id" ), &CollisionObject2D::get_shape_owner_one_way_collision_margin); |
623 | ClassDB::bind_method(D_METHOD("shape_owner_add_shape" , "owner_id" , "shape" ), &CollisionObject2D::shape_owner_add_shape); |
624 | ClassDB::bind_method(D_METHOD("shape_owner_get_shape_count" , "owner_id" ), &CollisionObject2D::shape_owner_get_shape_count); |
625 | ClassDB::bind_method(D_METHOD("shape_owner_get_shape" , "owner_id" , "shape_id" ), &CollisionObject2D::shape_owner_get_shape); |
626 | ClassDB::bind_method(D_METHOD("shape_owner_get_shape_index" , "owner_id" , "shape_id" ), &CollisionObject2D::shape_owner_get_shape_index); |
627 | ClassDB::bind_method(D_METHOD("shape_owner_remove_shape" , "owner_id" , "shape_id" ), &CollisionObject2D::shape_owner_remove_shape); |
628 | ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes" , "owner_id" ), &CollisionObject2D::shape_owner_clear_shapes); |
629 | ClassDB::bind_method(D_METHOD("shape_find_owner" , "shape_index" ), &CollisionObject2D::shape_find_owner); |
630 | |
631 | GDVIRTUAL_BIND(_input_event, "viewport" , "event" , "shape_idx" ); |
632 | GDVIRTUAL_BIND(_mouse_enter); |
633 | GDVIRTUAL_BIND(_mouse_exit); |
634 | GDVIRTUAL_BIND(_mouse_shape_enter, "shape_idx" ); |
635 | GDVIRTUAL_BIND(_mouse_shape_exit, "shape_idx" ); |
636 | |
637 | ADD_SIGNAL(MethodInfo("input_event" , PropertyInfo(Variant::OBJECT, "viewport" , PROPERTY_HINT_RESOURCE_TYPE, "Node" ), PropertyInfo(Variant::OBJECT, "event" , PROPERTY_HINT_RESOURCE_TYPE, "InputEvent" ), PropertyInfo(Variant::INT, "shape_idx" ))); |
638 | ADD_SIGNAL(MethodInfo("mouse_entered" )); |
639 | ADD_SIGNAL(MethodInfo("mouse_exited" )); |
640 | ADD_SIGNAL(MethodInfo("mouse_shape_entered" , PropertyInfo(Variant::INT, "shape_idx" ))); |
641 | ADD_SIGNAL(MethodInfo("mouse_shape_exited" , PropertyInfo(Variant::INT, "shape_idx" ))); |
642 | |
643 | ADD_PROPERTY(PropertyInfo(Variant::INT, "disable_mode" , PROPERTY_HINT_ENUM, "Remove,Make Static,Keep Active" ), "set_disable_mode" , "get_disable_mode" ); |
644 | |
645 | ADD_GROUP("Collision" , "collision_" ); |
646 | ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer" , PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer" , "get_collision_layer" ); |
647 | ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask" , PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask" , "get_collision_mask" ); |
648 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_priority" ), "set_collision_priority" , "get_collision_priority" ); |
649 | |
650 | ADD_GROUP("Input" , "input_" ); |
651 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_pickable" ), "set_pickable" , "is_pickable" ); |
652 | |
653 | BIND_ENUM_CONSTANT(DISABLE_MODE_REMOVE); |
654 | BIND_ENUM_CONSTANT(DISABLE_MODE_MAKE_STATIC); |
655 | BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE); |
656 | } |
657 | |
658 | CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) { |
659 | rid = p_rid; |
660 | area = p_area; |
661 | pickable = true; |
662 | set_notify_transform(true); |
663 | set_hide_clip_children(true); |
664 | total_subshapes = 0; |
665 | only_update_transform_changes = false; |
666 | |
667 | if (p_area) { |
668 | PhysicsServer2D::get_singleton()->area_attach_object_instance_id(rid, get_instance_id()); |
669 | } else { |
670 | PhysicsServer2D::get_singleton()->body_attach_object_instance_id(rid, get_instance_id()); |
671 | PhysicsServer2D::get_singleton()->body_set_mode(rid, body_mode); |
672 | } |
673 | } |
674 | |
675 | CollisionObject2D::CollisionObject2D() { |
676 | //owner= |
677 | |
678 | set_notify_transform(true); |
679 | } |
680 | |
681 | CollisionObject2D::~CollisionObject2D() { |
682 | ERR_FAIL_NULL(PhysicsServer2D::get_singleton()); |
683 | PhysicsServer2D::get_singleton()->free(rid); |
684 | } |
685 | |