1 | /**************************************************************************/ |
2 | /* godot_physics_server_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 "godot_physics_server_2d.h" |
32 | |
33 | #include "godot_body_direct_state_2d.h" |
34 | #include "godot_broad_phase_2d_bvh.h" |
35 | #include "godot_collision_solver_2d.h" |
36 | |
37 | #include "core/config/project_settings.h" |
38 | #include "core/debugger/engine_debugger.h" |
39 | #include "core/os/os.h" |
40 | |
41 | #define FLUSH_QUERY_CHECK(m_object) \ |
42 | ERR_FAIL_COND_MSG(m_object->get_space() && flushing_queries, "Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead."); |
43 | |
44 | RID GodotPhysicsServer2D::_shape_create(ShapeType p_shape) { |
45 | GodotShape2D *shape = nullptr; |
46 | switch (p_shape) { |
47 | case SHAPE_WORLD_BOUNDARY: { |
48 | shape = memnew(GodotWorldBoundaryShape2D); |
49 | } break; |
50 | case SHAPE_SEPARATION_RAY: { |
51 | shape = memnew(GodotSeparationRayShape2D); |
52 | } break; |
53 | case SHAPE_SEGMENT: { |
54 | shape = memnew(GodotSegmentShape2D); |
55 | } break; |
56 | case SHAPE_CIRCLE: { |
57 | shape = memnew(GodotCircleShape2D); |
58 | } break; |
59 | case SHAPE_RECTANGLE: { |
60 | shape = memnew(GodotRectangleShape2D); |
61 | } break; |
62 | case SHAPE_CAPSULE: { |
63 | shape = memnew(GodotCapsuleShape2D); |
64 | } break; |
65 | case SHAPE_CONVEX_POLYGON: { |
66 | shape = memnew(GodotConvexPolygonShape2D); |
67 | } break; |
68 | case SHAPE_CONCAVE_POLYGON: { |
69 | shape = memnew(GodotConcavePolygonShape2D); |
70 | } break; |
71 | case SHAPE_CUSTOM: { |
72 | ERR_FAIL_V(RID()); |
73 | |
74 | } break; |
75 | } |
76 | |
77 | RID id = shape_owner.make_rid(shape); |
78 | shape->set_self(id); |
79 | |
80 | return id; |
81 | } |
82 | |
83 | RID GodotPhysicsServer2D::world_boundary_shape_create() { |
84 | return _shape_create(SHAPE_WORLD_BOUNDARY); |
85 | } |
86 | |
87 | RID GodotPhysicsServer2D::separation_ray_shape_create() { |
88 | return _shape_create(SHAPE_SEPARATION_RAY); |
89 | } |
90 | |
91 | RID GodotPhysicsServer2D::segment_shape_create() { |
92 | return _shape_create(SHAPE_SEGMENT); |
93 | } |
94 | |
95 | RID GodotPhysicsServer2D::circle_shape_create() { |
96 | return _shape_create(SHAPE_CIRCLE); |
97 | } |
98 | |
99 | RID GodotPhysicsServer2D::rectangle_shape_create() { |
100 | return _shape_create(SHAPE_RECTANGLE); |
101 | } |
102 | |
103 | RID GodotPhysicsServer2D::capsule_shape_create() { |
104 | return _shape_create(SHAPE_CAPSULE); |
105 | } |
106 | |
107 | RID GodotPhysicsServer2D::convex_polygon_shape_create() { |
108 | return _shape_create(SHAPE_CONVEX_POLYGON); |
109 | } |
110 | |
111 | RID GodotPhysicsServer2D::concave_polygon_shape_create() { |
112 | return _shape_create(SHAPE_CONCAVE_POLYGON); |
113 | } |
114 | |
115 | void GodotPhysicsServer2D::shape_set_data(RID p_shape, const Variant &p_data) { |
116 | GodotShape2D *shape = shape_owner.get_or_null(p_shape); |
117 | ERR_FAIL_COND(!shape); |
118 | shape->set_data(p_data); |
119 | }; |
120 | |
121 | void GodotPhysicsServer2D::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) { |
122 | GodotShape2D *shape = shape_owner.get_or_null(p_shape); |
123 | ERR_FAIL_COND(!shape); |
124 | shape->set_custom_bias(p_bias); |
125 | } |
126 | |
127 | PhysicsServer2D::ShapeType GodotPhysicsServer2D::shape_get_type(RID p_shape) const { |
128 | const GodotShape2D *shape = shape_owner.get_or_null(p_shape); |
129 | ERR_FAIL_COND_V(!shape, SHAPE_CUSTOM); |
130 | return shape->get_type(); |
131 | }; |
132 | |
133 | Variant GodotPhysicsServer2D::shape_get_data(RID p_shape) const { |
134 | const GodotShape2D *shape = shape_owner.get_or_null(p_shape); |
135 | ERR_FAIL_COND_V(!shape, Variant()); |
136 | ERR_FAIL_COND_V(!shape->is_configured(), Variant()); |
137 | return shape->get_data(); |
138 | }; |
139 | |
140 | real_t GodotPhysicsServer2D::shape_get_custom_solver_bias(RID p_shape) const { |
141 | const GodotShape2D *shape = shape_owner.get_or_null(p_shape); |
142 | ERR_FAIL_COND_V(!shape, 0); |
143 | return shape->get_custom_bias(); |
144 | } |
145 | |
146 | void GodotPhysicsServer2D::_shape_col_cbk(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata) { |
147 | CollCbkData *cbk = static_cast<CollCbkData *>(p_userdata); |
148 | |
149 | if (cbk->max == 0) { |
150 | return; |
151 | } |
152 | |
153 | Vector2 rel_dir = (p_point_A - p_point_B); |
154 | real_t rel_length2 = rel_dir.length_squared(); |
155 | if (cbk->valid_dir != Vector2()) { |
156 | if (cbk->valid_depth < 10e20) { |
157 | if (rel_length2 > cbk->valid_depth * cbk->valid_depth || |
158 | (rel_length2 > CMP_EPSILON && cbk->valid_dir.dot(rel_dir.normalized()) < CMP_EPSILON)) { |
159 | cbk->invalid_by_dir++; |
160 | return; |
161 | } |
162 | } else { |
163 | if (rel_length2 > 0 && cbk->valid_dir.dot(rel_dir.normalized()) < CMP_EPSILON) { |
164 | return; |
165 | } |
166 | } |
167 | } |
168 | |
169 | if (cbk->amount == cbk->max) { |
170 | //find least deep |
171 | real_t min_depth = 1e20; |
172 | int min_depth_idx = 0; |
173 | for (int i = 0; i < cbk->amount; i++) { |
174 | real_t d = cbk->ptr[i * 2 + 0].distance_squared_to(cbk->ptr[i * 2 + 1]); |
175 | if (d < min_depth) { |
176 | min_depth = d; |
177 | min_depth_idx = i; |
178 | } |
179 | } |
180 | |
181 | if (rel_length2 < min_depth) { |
182 | return; |
183 | } |
184 | cbk->ptr[min_depth_idx * 2 + 0] = p_point_A; |
185 | cbk->ptr[min_depth_idx * 2 + 1] = p_point_B; |
186 | cbk->passed++; |
187 | |
188 | } else { |
189 | cbk->ptr[cbk->amount * 2 + 0] = p_point_A; |
190 | cbk->ptr[cbk->amount * 2 + 1] = p_point_B; |
191 | cbk->amount++; |
192 | cbk->passed++; |
193 | } |
194 | } |
195 | |
196 | bool GodotPhysicsServer2D::shape_collide(RID p_shape_A, const Transform2D &p_xform_A, const Vector2 &p_motion_A, RID p_shape_B, const Transform2D &p_xform_B, const Vector2 &p_motion_B, Vector2 *r_results, int p_result_max, int &r_result_count) { |
197 | GodotShape2D *shape_A = shape_owner.get_or_null(p_shape_A); |
198 | ERR_FAIL_COND_V(!shape_A, false); |
199 | GodotShape2D *shape_B = shape_owner.get_or_null(p_shape_B); |
200 | ERR_FAIL_COND_V(!shape_B, false); |
201 | |
202 | if (p_result_max == 0) { |
203 | return GodotCollisionSolver2D::solve(shape_A, p_xform_A, p_motion_A, shape_B, p_xform_B, p_motion_B, nullptr, nullptr); |
204 | } |
205 | |
206 | CollCbkData cbk; |
207 | cbk.max = p_result_max; |
208 | cbk.amount = 0; |
209 | cbk.passed = 0; |
210 | cbk.ptr = r_results; |
211 | |
212 | bool res = GodotCollisionSolver2D::solve(shape_A, p_xform_A, p_motion_A, shape_B, p_xform_B, p_motion_B, _shape_col_cbk, &cbk); |
213 | r_result_count = cbk.amount; |
214 | return res; |
215 | } |
216 | |
217 | RID GodotPhysicsServer2D::space_create() { |
218 | GodotSpace2D *space = memnew(GodotSpace2D); |
219 | RID id = space_owner.make_rid(space); |
220 | space->set_self(id); |
221 | RID area_id = area_create(); |
222 | GodotArea2D *area = area_owner.get_or_null(area_id); |
223 | ERR_FAIL_COND_V(!area, RID()); |
224 | space->set_default_area(area); |
225 | area->set_space(space); |
226 | area->set_priority(-1); |
227 | |
228 | return id; |
229 | }; |
230 | |
231 | void GodotPhysicsServer2D::space_set_active(RID p_space, bool p_active) { |
232 | GodotSpace2D *space = space_owner.get_or_null(p_space); |
233 | ERR_FAIL_COND(!space); |
234 | if (p_active) { |
235 | active_spaces.insert(space); |
236 | } else { |
237 | active_spaces.erase(space); |
238 | } |
239 | } |
240 | |
241 | bool GodotPhysicsServer2D::space_is_active(RID p_space) const { |
242 | const GodotSpace2D *space = space_owner.get_or_null(p_space); |
243 | ERR_FAIL_COND_V(!space, false); |
244 | |
245 | return active_spaces.has(space); |
246 | } |
247 | |
248 | void GodotPhysicsServer2D::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) { |
249 | GodotSpace2D *space = space_owner.get_or_null(p_space); |
250 | ERR_FAIL_COND(!space); |
251 | |
252 | space->set_param(p_param, p_value); |
253 | } |
254 | |
255 | real_t GodotPhysicsServer2D::space_get_param(RID p_space, SpaceParameter p_param) const { |
256 | const GodotSpace2D *space = space_owner.get_or_null(p_space); |
257 | ERR_FAIL_COND_V(!space, 0); |
258 | return space->get_param(p_param); |
259 | } |
260 | |
261 | void GodotPhysicsServer2D::space_set_debug_contacts(RID p_space, int p_max_contacts) { |
262 | GodotSpace2D *space = space_owner.get_or_null(p_space); |
263 | ERR_FAIL_COND(!space); |
264 | space->set_debug_contacts(p_max_contacts); |
265 | } |
266 | |
267 | Vector<Vector2> GodotPhysicsServer2D::space_get_contacts(RID p_space) const { |
268 | GodotSpace2D *space = space_owner.get_or_null(p_space); |
269 | ERR_FAIL_COND_V(!space, Vector<Vector2>()); |
270 | return space->get_debug_contacts(); |
271 | } |
272 | |
273 | int GodotPhysicsServer2D::space_get_contact_count(RID p_space) const { |
274 | GodotSpace2D *space = space_owner.get_or_null(p_space); |
275 | ERR_FAIL_COND_V(!space, 0); |
276 | return space->get_debug_contact_count(); |
277 | } |
278 | |
279 | PhysicsDirectSpaceState2D *GodotPhysicsServer2D::space_get_direct_state(RID p_space) { |
280 | GodotSpace2D *space = space_owner.get_or_null(p_space); |
281 | ERR_FAIL_COND_V(!space, nullptr); |
282 | ERR_FAIL_COND_V_MSG((using_threads && !doing_sync) || space->is_locked(), nullptr, "Space state is inaccessible right now, wait for iteration or physics process notification." ); |
283 | |
284 | return space->get_direct_state(); |
285 | } |
286 | |
287 | RID GodotPhysicsServer2D::area_create() { |
288 | GodotArea2D *area = memnew(GodotArea2D); |
289 | RID rid = area_owner.make_rid(area); |
290 | area->set_self(rid); |
291 | return rid; |
292 | } |
293 | |
294 | void GodotPhysicsServer2D::area_set_space(RID p_area, RID p_space) { |
295 | GodotArea2D *area = area_owner.get_or_null(p_area); |
296 | ERR_FAIL_COND(!area); |
297 | |
298 | GodotSpace2D *space = nullptr; |
299 | if (p_space.is_valid()) { |
300 | space = space_owner.get_or_null(p_space); |
301 | ERR_FAIL_COND(!space); |
302 | } |
303 | |
304 | if (area->get_space() == space) { |
305 | return; //pointless |
306 | } |
307 | |
308 | area->clear_constraints(); |
309 | area->set_space(space); |
310 | } |
311 | |
312 | RID GodotPhysicsServer2D::area_get_space(RID p_area) const { |
313 | GodotArea2D *area = area_owner.get_or_null(p_area); |
314 | ERR_FAIL_COND_V(!area, RID()); |
315 | |
316 | GodotSpace2D *space = area->get_space(); |
317 | if (!space) { |
318 | return RID(); |
319 | } |
320 | return space->get_self(); |
321 | } |
322 | |
323 | void GodotPhysicsServer2D::area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform, bool p_disabled) { |
324 | GodotArea2D *area = area_owner.get_or_null(p_area); |
325 | ERR_FAIL_COND(!area); |
326 | |
327 | GodotShape2D *shape = shape_owner.get_or_null(p_shape); |
328 | ERR_FAIL_COND(!shape); |
329 | |
330 | area->add_shape(shape, p_transform, p_disabled); |
331 | } |
332 | |
333 | void GodotPhysicsServer2D::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) { |
334 | GodotArea2D *area = area_owner.get_or_null(p_area); |
335 | ERR_FAIL_COND(!area); |
336 | |
337 | GodotShape2D *shape = shape_owner.get_or_null(p_shape); |
338 | ERR_FAIL_COND(!shape); |
339 | ERR_FAIL_COND(!shape->is_configured()); |
340 | |
341 | area->set_shape(p_shape_idx, shape); |
342 | } |
343 | |
344 | void GodotPhysicsServer2D::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform) { |
345 | GodotArea2D *area = area_owner.get_or_null(p_area); |
346 | ERR_FAIL_COND(!area); |
347 | |
348 | area->set_shape_transform(p_shape_idx, p_transform); |
349 | } |
350 | |
351 | void GodotPhysicsServer2D::area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) { |
352 | GodotArea2D *area = area_owner.get_or_null(p_area); |
353 | ERR_FAIL_COND(!area); |
354 | ERR_FAIL_INDEX(p_shape, area->get_shape_count()); |
355 | FLUSH_QUERY_CHECK(area); |
356 | |
357 | area->set_shape_disabled(p_shape, p_disabled); |
358 | } |
359 | |
360 | int GodotPhysicsServer2D::area_get_shape_count(RID p_area) const { |
361 | GodotArea2D *area = area_owner.get_or_null(p_area); |
362 | ERR_FAIL_COND_V(!area, -1); |
363 | |
364 | return area->get_shape_count(); |
365 | } |
366 | |
367 | RID GodotPhysicsServer2D::area_get_shape(RID p_area, int p_shape_idx) const { |
368 | GodotArea2D *area = area_owner.get_or_null(p_area); |
369 | ERR_FAIL_COND_V(!area, RID()); |
370 | |
371 | GodotShape2D *shape = area->get_shape(p_shape_idx); |
372 | ERR_FAIL_COND_V(!shape, RID()); |
373 | |
374 | return shape->get_self(); |
375 | } |
376 | |
377 | Transform2D GodotPhysicsServer2D::area_get_shape_transform(RID p_area, int p_shape_idx) const { |
378 | GodotArea2D *area = area_owner.get_or_null(p_area); |
379 | ERR_FAIL_COND_V(!area, Transform2D()); |
380 | |
381 | return area->get_shape_transform(p_shape_idx); |
382 | } |
383 | |
384 | void GodotPhysicsServer2D::area_remove_shape(RID p_area, int p_shape_idx) { |
385 | GodotArea2D *area = area_owner.get_or_null(p_area); |
386 | ERR_FAIL_COND(!area); |
387 | |
388 | area->remove_shape(p_shape_idx); |
389 | } |
390 | |
391 | void GodotPhysicsServer2D::area_clear_shapes(RID p_area) { |
392 | GodotArea2D *area = area_owner.get_or_null(p_area); |
393 | ERR_FAIL_COND(!area); |
394 | |
395 | while (area->get_shape_count()) { |
396 | area->remove_shape(0); |
397 | } |
398 | } |
399 | |
400 | void GodotPhysicsServer2D::area_attach_object_instance_id(RID p_area, ObjectID p_id) { |
401 | if (space_owner.owns(p_area)) { |
402 | GodotSpace2D *space = space_owner.get_or_null(p_area); |
403 | p_area = space->get_default_area()->get_self(); |
404 | } |
405 | GodotArea2D *area = area_owner.get_or_null(p_area); |
406 | ERR_FAIL_COND(!area); |
407 | area->set_instance_id(p_id); |
408 | } |
409 | |
410 | ObjectID GodotPhysicsServer2D::area_get_object_instance_id(RID p_area) const { |
411 | if (space_owner.owns(p_area)) { |
412 | GodotSpace2D *space = space_owner.get_or_null(p_area); |
413 | p_area = space->get_default_area()->get_self(); |
414 | } |
415 | GodotArea2D *area = area_owner.get_or_null(p_area); |
416 | ERR_FAIL_COND_V(!area, ObjectID()); |
417 | return area->get_instance_id(); |
418 | } |
419 | |
420 | void GodotPhysicsServer2D::area_attach_canvas_instance_id(RID p_area, ObjectID p_id) { |
421 | if (space_owner.owns(p_area)) { |
422 | GodotSpace2D *space = space_owner.get_or_null(p_area); |
423 | p_area = space->get_default_area()->get_self(); |
424 | } |
425 | GodotArea2D *area = area_owner.get_or_null(p_area); |
426 | ERR_FAIL_COND(!area); |
427 | area->set_canvas_instance_id(p_id); |
428 | } |
429 | |
430 | ObjectID GodotPhysicsServer2D::area_get_canvas_instance_id(RID p_area) const { |
431 | if (space_owner.owns(p_area)) { |
432 | GodotSpace2D *space = space_owner.get_or_null(p_area); |
433 | p_area = space->get_default_area()->get_self(); |
434 | } |
435 | GodotArea2D *area = area_owner.get_or_null(p_area); |
436 | ERR_FAIL_COND_V(!area, ObjectID()); |
437 | return area->get_canvas_instance_id(); |
438 | } |
439 | |
440 | void GodotPhysicsServer2D::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) { |
441 | if (space_owner.owns(p_area)) { |
442 | GodotSpace2D *space = space_owner.get_or_null(p_area); |
443 | p_area = space->get_default_area()->get_self(); |
444 | } |
445 | GodotArea2D *area = area_owner.get_or_null(p_area); |
446 | ERR_FAIL_COND(!area); |
447 | area->set_param(p_param, p_value); |
448 | }; |
449 | |
450 | void GodotPhysicsServer2D::area_set_transform(RID p_area, const Transform2D &p_transform) { |
451 | GodotArea2D *area = area_owner.get_or_null(p_area); |
452 | ERR_FAIL_COND(!area); |
453 | area->set_transform(p_transform); |
454 | }; |
455 | |
456 | Variant GodotPhysicsServer2D::area_get_param(RID p_area, AreaParameter p_param) const { |
457 | if (space_owner.owns(p_area)) { |
458 | GodotSpace2D *space = space_owner.get_or_null(p_area); |
459 | p_area = space->get_default_area()->get_self(); |
460 | } |
461 | GodotArea2D *area = area_owner.get_or_null(p_area); |
462 | ERR_FAIL_COND_V(!area, Variant()); |
463 | |
464 | return area->get_param(p_param); |
465 | }; |
466 | |
467 | Transform2D GodotPhysicsServer2D::area_get_transform(RID p_area) const { |
468 | GodotArea2D *area = area_owner.get_or_null(p_area); |
469 | ERR_FAIL_COND_V(!area, Transform2D()); |
470 | |
471 | return area->get_transform(); |
472 | }; |
473 | |
474 | void GodotPhysicsServer2D::area_set_pickable(RID p_area, bool p_pickable) { |
475 | GodotArea2D *area = area_owner.get_or_null(p_area); |
476 | ERR_FAIL_COND(!area); |
477 | area->set_pickable(p_pickable); |
478 | } |
479 | |
480 | void GodotPhysicsServer2D::area_set_monitorable(RID p_area, bool p_monitorable) { |
481 | GodotArea2D *area = area_owner.get_or_null(p_area); |
482 | ERR_FAIL_COND(!area); |
483 | FLUSH_QUERY_CHECK(area); |
484 | |
485 | area->set_monitorable(p_monitorable); |
486 | } |
487 | |
488 | void GodotPhysicsServer2D::area_set_collision_layer(RID p_area, uint32_t p_layer) { |
489 | GodotArea2D *area = area_owner.get_or_null(p_area); |
490 | ERR_FAIL_COND(!area); |
491 | |
492 | area->set_collision_layer(p_layer); |
493 | } |
494 | |
495 | uint32_t GodotPhysicsServer2D::area_get_collision_layer(RID p_area) const { |
496 | GodotArea2D *area = area_owner.get_or_null(p_area); |
497 | ERR_FAIL_COND_V(!area, 0); |
498 | |
499 | return area->get_collision_layer(); |
500 | } |
501 | |
502 | void GodotPhysicsServer2D::area_set_collision_mask(RID p_area, uint32_t p_mask) { |
503 | GodotArea2D *area = area_owner.get_or_null(p_area); |
504 | ERR_FAIL_COND(!area); |
505 | |
506 | area->set_collision_mask(p_mask); |
507 | } |
508 | |
509 | uint32_t GodotPhysicsServer2D::area_get_collision_mask(RID p_area) const { |
510 | GodotArea2D *area = area_owner.get_or_null(p_area); |
511 | ERR_FAIL_COND_V(!area, 0); |
512 | |
513 | return area->get_collision_mask(); |
514 | } |
515 | |
516 | void GodotPhysicsServer2D::area_set_monitor_callback(RID p_area, const Callable &p_callback) { |
517 | GodotArea2D *area = area_owner.get_or_null(p_area); |
518 | ERR_FAIL_COND(!area); |
519 | |
520 | area->set_monitor_callback(p_callback.is_valid() ? p_callback : Callable()); |
521 | } |
522 | |
523 | void GodotPhysicsServer2D::area_set_area_monitor_callback(RID p_area, const Callable &p_callback) { |
524 | GodotArea2D *area = area_owner.get_or_null(p_area); |
525 | ERR_FAIL_COND(!area); |
526 | |
527 | area->set_area_monitor_callback(p_callback.is_valid() ? p_callback : Callable()); |
528 | } |
529 | |
530 | /* BODY API */ |
531 | |
532 | RID GodotPhysicsServer2D::body_create() { |
533 | GodotBody2D *body = memnew(GodotBody2D); |
534 | RID rid = body_owner.make_rid(body); |
535 | body->set_self(rid); |
536 | return rid; |
537 | } |
538 | |
539 | void GodotPhysicsServer2D::body_set_space(RID p_body, RID p_space) { |
540 | GodotBody2D *body = body_owner.get_or_null(p_body); |
541 | ERR_FAIL_COND(!body); |
542 | GodotSpace2D *space = nullptr; |
543 | if (p_space.is_valid()) { |
544 | space = space_owner.get_or_null(p_space); |
545 | ERR_FAIL_COND(!space); |
546 | } |
547 | |
548 | if (body->get_space() == space) { |
549 | return; //pointless |
550 | } |
551 | |
552 | body->clear_constraint_list(); |
553 | body->set_space(space); |
554 | }; |
555 | |
556 | RID GodotPhysicsServer2D::body_get_space(RID p_body) const { |
557 | GodotBody2D *body = body_owner.get_or_null(p_body); |
558 | ERR_FAIL_COND_V(!body, RID()); |
559 | |
560 | GodotSpace2D *space = body->get_space(); |
561 | if (!space) { |
562 | return RID(); |
563 | } |
564 | return space->get_self(); |
565 | }; |
566 | |
567 | void GodotPhysicsServer2D::body_set_mode(RID p_body, BodyMode p_mode) { |
568 | GodotBody2D *body = body_owner.get_or_null(p_body); |
569 | ERR_FAIL_COND(!body); |
570 | FLUSH_QUERY_CHECK(body); |
571 | |
572 | body->set_mode(p_mode); |
573 | }; |
574 | |
575 | PhysicsServer2D::BodyMode GodotPhysicsServer2D::body_get_mode(RID p_body) const { |
576 | GodotBody2D *body = body_owner.get_or_null(p_body); |
577 | ERR_FAIL_COND_V(!body, BODY_MODE_STATIC); |
578 | |
579 | return body->get_mode(); |
580 | }; |
581 | |
582 | void GodotPhysicsServer2D::body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform, bool p_disabled) { |
583 | GodotBody2D *body = body_owner.get_or_null(p_body); |
584 | ERR_FAIL_COND(!body); |
585 | |
586 | GodotShape2D *shape = shape_owner.get_or_null(p_shape); |
587 | ERR_FAIL_COND(!shape); |
588 | |
589 | body->add_shape(shape, p_transform, p_disabled); |
590 | } |
591 | |
592 | void GodotPhysicsServer2D::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) { |
593 | GodotBody2D *body = body_owner.get_or_null(p_body); |
594 | ERR_FAIL_COND(!body); |
595 | |
596 | GodotShape2D *shape = shape_owner.get_or_null(p_shape); |
597 | ERR_FAIL_COND(!shape); |
598 | ERR_FAIL_COND(!shape->is_configured()); |
599 | |
600 | body->set_shape(p_shape_idx, shape); |
601 | } |
602 | |
603 | void GodotPhysicsServer2D::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform) { |
604 | GodotBody2D *body = body_owner.get_or_null(p_body); |
605 | ERR_FAIL_COND(!body); |
606 | |
607 | body->set_shape_transform(p_shape_idx, p_transform); |
608 | } |
609 | |
610 | int GodotPhysicsServer2D::body_get_shape_count(RID p_body) const { |
611 | GodotBody2D *body = body_owner.get_or_null(p_body); |
612 | ERR_FAIL_COND_V(!body, -1); |
613 | |
614 | return body->get_shape_count(); |
615 | } |
616 | |
617 | RID GodotPhysicsServer2D::body_get_shape(RID p_body, int p_shape_idx) const { |
618 | GodotBody2D *body = body_owner.get_or_null(p_body); |
619 | ERR_FAIL_COND_V(!body, RID()); |
620 | |
621 | GodotShape2D *shape = body->get_shape(p_shape_idx); |
622 | ERR_FAIL_COND_V(!shape, RID()); |
623 | |
624 | return shape->get_self(); |
625 | } |
626 | |
627 | Transform2D GodotPhysicsServer2D::body_get_shape_transform(RID p_body, int p_shape_idx) const { |
628 | GodotBody2D *body = body_owner.get_or_null(p_body); |
629 | ERR_FAIL_COND_V(!body, Transform2D()); |
630 | |
631 | return body->get_shape_transform(p_shape_idx); |
632 | } |
633 | |
634 | void GodotPhysicsServer2D::body_remove_shape(RID p_body, int p_shape_idx) { |
635 | GodotBody2D *body = body_owner.get_or_null(p_body); |
636 | ERR_FAIL_COND(!body); |
637 | |
638 | body->remove_shape(p_shape_idx); |
639 | } |
640 | |
641 | void GodotPhysicsServer2D::body_clear_shapes(RID p_body) { |
642 | GodotBody2D *body = body_owner.get_or_null(p_body); |
643 | ERR_FAIL_COND(!body); |
644 | |
645 | while (body->get_shape_count()) { |
646 | body->remove_shape(0); |
647 | } |
648 | } |
649 | |
650 | void GodotPhysicsServer2D::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) { |
651 | GodotBody2D *body = body_owner.get_or_null(p_body); |
652 | ERR_FAIL_COND(!body); |
653 | ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); |
654 | FLUSH_QUERY_CHECK(body); |
655 | |
656 | body->set_shape_disabled(p_shape_idx, p_disabled); |
657 | } |
658 | |
659 | void GodotPhysicsServer2D::body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, real_t p_margin) { |
660 | GodotBody2D *body = body_owner.get_or_null(p_body); |
661 | ERR_FAIL_COND(!body); |
662 | ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); |
663 | FLUSH_QUERY_CHECK(body); |
664 | |
665 | body->set_shape_as_one_way_collision(p_shape_idx, p_enable, p_margin); |
666 | } |
667 | |
668 | void GodotPhysicsServer2D::body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode) { |
669 | GodotBody2D *body = body_owner.get_or_null(p_body); |
670 | ERR_FAIL_COND(!body); |
671 | body->set_continuous_collision_detection_mode(p_mode); |
672 | } |
673 | |
674 | GodotPhysicsServer2D::CCDMode GodotPhysicsServer2D::body_get_continuous_collision_detection_mode(RID p_body) const { |
675 | const GodotBody2D *body = body_owner.get_or_null(p_body); |
676 | ERR_FAIL_COND_V(!body, CCD_MODE_DISABLED); |
677 | |
678 | return body->get_continuous_collision_detection_mode(); |
679 | } |
680 | |
681 | void GodotPhysicsServer2D::body_attach_object_instance_id(RID p_body, ObjectID p_id) { |
682 | GodotBody2D *body = body_owner.get_or_null(p_body); |
683 | ERR_FAIL_COND(!body); |
684 | |
685 | body->set_instance_id(p_id); |
686 | } |
687 | |
688 | ObjectID GodotPhysicsServer2D::body_get_object_instance_id(RID p_body) const { |
689 | GodotBody2D *body = body_owner.get_or_null(p_body); |
690 | ERR_FAIL_COND_V(!body, ObjectID()); |
691 | |
692 | return body->get_instance_id(); |
693 | } |
694 | |
695 | void GodotPhysicsServer2D::body_attach_canvas_instance_id(RID p_body, ObjectID p_id) { |
696 | GodotBody2D *body = body_owner.get_or_null(p_body); |
697 | ERR_FAIL_COND(!body); |
698 | |
699 | body->set_canvas_instance_id(p_id); |
700 | } |
701 | |
702 | ObjectID GodotPhysicsServer2D::body_get_canvas_instance_id(RID p_body) const { |
703 | GodotBody2D *body = body_owner.get_or_null(p_body); |
704 | ERR_FAIL_COND_V(!body, ObjectID()); |
705 | |
706 | return body->get_canvas_instance_id(); |
707 | } |
708 | |
709 | void GodotPhysicsServer2D::body_set_collision_layer(RID p_body, uint32_t p_layer) { |
710 | GodotBody2D *body = body_owner.get_or_null(p_body); |
711 | ERR_FAIL_COND(!body); |
712 | body->set_collision_layer(p_layer); |
713 | } |
714 | |
715 | uint32_t GodotPhysicsServer2D::body_get_collision_layer(RID p_body) const { |
716 | GodotBody2D *body = body_owner.get_or_null(p_body); |
717 | ERR_FAIL_COND_V(!body, 0); |
718 | |
719 | return body->get_collision_layer(); |
720 | } |
721 | |
722 | void GodotPhysicsServer2D::body_set_collision_mask(RID p_body, uint32_t p_mask) { |
723 | GodotBody2D *body = body_owner.get_or_null(p_body); |
724 | ERR_FAIL_COND(!body); |
725 | body->set_collision_mask(p_mask); |
726 | } |
727 | |
728 | uint32_t GodotPhysicsServer2D::body_get_collision_mask(RID p_body) const { |
729 | GodotBody2D *body = body_owner.get_or_null(p_body); |
730 | ERR_FAIL_COND_V(!body, 0); |
731 | |
732 | return body->get_collision_mask(); |
733 | } |
734 | |
735 | void GodotPhysicsServer2D::body_set_collision_priority(RID p_body, real_t p_priority) { |
736 | GodotBody2D *body = body_owner.get_or_null(p_body); |
737 | ERR_FAIL_COND(!body); |
738 | |
739 | body->set_collision_priority(p_priority); |
740 | } |
741 | |
742 | real_t GodotPhysicsServer2D::body_get_collision_priority(RID p_body) const { |
743 | const GodotBody2D *body = body_owner.get_or_null(p_body); |
744 | ERR_FAIL_COND_V(!body, 0); |
745 | |
746 | return body->get_collision_priority(); |
747 | } |
748 | |
749 | void GodotPhysicsServer2D::body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) { |
750 | GodotBody2D *body = body_owner.get_or_null(p_body); |
751 | ERR_FAIL_COND(!body); |
752 | |
753 | body->set_param(p_param, p_value); |
754 | } |
755 | |
756 | Variant GodotPhysicsServer2D::body_get_param(RID p_body, BodyParameter p_param) const { |
757 | GodotBody2D *body = body_owner.get_or_null(p_body); |
758 | ERR_FAIL_COND_V(!body, 0); |
759 | |
760 | return body->get_param(p_param); |
761 | } |
762 | |
763 | void GodotPhysicsServer2D::body_reset_mass_properties(RID p_body) { |
764 | GodotBody2D *body = body_owner.get_or_null(p_body); |
765 | ERR_FAIL_COND(!body); |
766 | |
767 | return body->reset_mass_properties(); |
768 | } |
769 | |
770 | void GodotPhysicsServer2D::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { |
771 | GodotBody2D *body = body_owner.get_or_null(p_body); |
772 | ERR_FAIL_COND(!body); |
773 | |
774 | body->set_state(p_state, p_variant); |
775 | } |
776 | |
777 | Variant GodotPhysicsServer2D::body_get_state(RID p_body, BodyState p_state) const { |
778 | GodotBody2D *body = body_owner.get_or_null(p_body); |
779 | ERR_FAIL_COND_V(!body, Variant()); |
780 | |
781 | return body->get_state(p_state); |
782 | } |
783 | |
784 | void GodotPhysicsServer2D::body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) { |
785 | GodotBody2D *body = body_owner.get_or_null(p_body); |
786 | ERR_FAIL_COND(!body); |
787 | |
788 | body->apply_central_impulse(p_impulse); |
789 | body->wakeup(); |
790 | } |
791 | |
792 | void GodotPhysicsServer2D::body_apply_torque_impulse(RID p_body, real_t p_torque) { |
793 | GodotBody2D *body = body_owner.get_or_null(p_body); |
794 | ERR_FAIL_COND(!body); |
795 | |
796 | _update_shapes(); |
797 | |
798 | body->apply_torque_impulse(p_torque); |
799 | body->wakeup(); |
800 | } |
801 | |
802 | void GodotPhysicsServer2D::body_apply_impulse(RID p_body, const Vector2 &p_impulse, const Vector2 &p_position) { |
803 | GodotBody2D *body = body_owner.get_or_null(p_body); |
804 | ERR_FAIL_COND(!body); |
805 | |
806 | _update_shapes(); |
807 | |
808 | body->apply_impulse(p_impulse, p_position); |
809 | body->wakeup(); |
810 | } |
811 | |
812 | void GodotPhysicsServer2D::body_apply_central_force(RID p_body, const Vector2 &p_force) { |
813 | GodotBody2D *body = body_owner.get_or_null(p_body); |
814 | ERR_FAIL_COND(!body); |
815 | |
816 | body->apply_central_force(p_force); |
817 | body->wakeup(); |
818 | } |
819 | |
820 | void GodotPhysicsServer2D::body_apply_force(RID p_body, const Vector2 &p_force, const Vector2 &p_position) { |
821 | GodotBody2D *body = body_owner.get_or_null(p_body); |
822 | ERR_FAIL_COND(!body); |
823 | |
824 | body->apply_force(p_force, p_position); |
825 | body->wakeup(); |
826 | } |
827 | |
828 | void GodotPhysicsServer2D::body_apply_torque(RID p_body, real_t p_torque) { |
829 | GodotBody2D *body = body_owner.get_or_null(p_body); |
830 | ERR_FAIL_COND(!body); |
831 | |
832 | body->apply_torque(p_torque); |
833 | body->wakeup(); |
834 | } |
835 | |
836 | void GodotPhysicsServer2D::body_add_constant_central_force(RID p_body, const Vector2 &p_force) { |
837 | GodotBody2D *body = body_owner.get_or_null(p_body); |
838 | ERR_FAIL_COND(!body); |
839 | |
840 | body->add_constant_central_force(p_force); |
841 | body->wakeup(); |
842 | } |
843 | |
844 | void GodotPhysicsServer2D::body_add_constant_force(RID p_body, const Vector2 &p_force, const Vector2 &p_position) { |
845 | GodotBody2D *body = body_owner.get_or_null(p_body); |
846 | ERR_FAIL_COND(!body); |
847 | |
848 | body->add_constant_force(p_force, p_position); |
849 | body->wakeup(); |
850 | } |
851 | |
852 | void GodotPhysicsServer2D::body_add_constant_torque(RID p_body, real_t p_torque) { |
853 | GodotBody2D *body = body_owner.get_or_null(p_body); |
854 | ERR_FAIL_COND(!body); |
855 | |
856 | body->add_constant_torque(p_torque); |
857 | body->wakeup(); |
858 | } |
859 | |
860 | void GodotPhysicsServer2D::body_set_constant_force(RID p_body, const Vector2 &p_force) { |
861 | GodotBody2D *body = body_owner.get_or_null(p_body); |
862 | ERR_FAIL_COND(!body); |
863 | |
864 | body->set_constant_force(p_force); |
865 | if (!p_force.is_zero_approx()) { |
866 | body->wakeup(); |
867 | } |
868 | } |
869 | |
870 | Vector2 GodotPhysicsServer2D::body_get_constant_force(RID p_body) const { |
871 | GodotBody2D *body = body_owner.get_or_null(p_body); |
872 | ERR_FAIL_COND_V(!body, Vector2()); |
873 | return body->get_constant_force(); |
874 | } |
875 | |
876 | void GodotPhysicsServer2D::body_set_constant_torque(RID p_body, real_t p_torque) { |
877 | GodotBody2D *body = body_owner.get_or_null(p_body); |
878 | ERR_FAIL_COND(!body); |
879 | |
880 | body->set_constant_torque(p_torque); |
881 | if (!Math::is_zero_approx(p_torque)) { |
882 | body->wakeup(); |
883 | } |
884 | } |
885 | |
886 | real_t GodotPhysicsServer2D::body_get_constant_torque(RID p_body) const { |
887 | GodotBody2D *body = body_owner.get_or_null(p_body); |
888 | ERR_FAIL_COND_V(!body, 0); |
889 | |
890 | return body->get_constant_torque(); |
891 | } |
892 | |
893 | void GodotPhysicsServer2D::body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity) { |
894 | GodotBody2D *body = body_owner.get_or_null(p_body); |
895 | ERR_FAIL_COND(!body); |
896 | |
897 | _update_shapes(); |
898 | |
899 | Vector2 v = body->get_linear_velocity(); |
900 | Vector2 axis = p_axis_velocity.normalized(); |
901 | v -= axis * axis.dot(v); |
902 | v += p_axis_velocity; |
903 | body->set_linear_velocity(v); |
904 | body->wakeup(); |
905 | }; |
906 | |
907 | void GodotPhysicsServer2D::body_add_collision_exception(RID p_body, RID p_body_b) { |
908 | GodotBody2D *body = body_owner.get_or_null(p_body); |
909 | ERR_FAIL_COND(!body); |
910 | |
911 | body->add_exception(p_body_b); |
912 | body->wakeup(); |
913 | }; |
914 | |
915 | void GodotPhysicsServer2D::body_remove_collision_exception(RID p_body, RID p_body_b) { |
916 | GodotBody2D *body = body_owner.get_or_null(p_body); |
917 | ERR_FAIL_COND(!body); |
918 | |
919 | body->remove_exception(p_body_b); |
920 | body->wakeup(); |
921 | }; |
922 | |
923 | void GodotPhysicsServer2D::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) { |
924 | GodotBody2D *body = body_owner.get_or_null(p_body); |
925 | ERR_FAIL_COND(!body); |
926 | |
927 | for (int i = 0; i < body->get_exceptions().size(); i++) { |
928 | p_exceptions->push_back(body->get_exceptions()[i]); |
929 | } |
930 | }; |
931 | |
932 | void GodotPhysicsServer2D::body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) { |
933 | GodotBody2D *body = body_owner.get_or_null(p_body); |
934 | ERR_FAIL_COND(!body); |
935 | }; |
936 | |
937 | real_t GodotPhysicsServer2D::body_get_contacts_reported_depth_threshold(RID p_body) const { |
938 | GodotBody2D *body = body_owner.get_or_null(p_body); |
939 | ERR_FAIL_COND_V(!body, 0); |
940 | return 0; |
941 | }; |
942 | |
943 | void GodotPhysicsServer2D::body_set_omit_force_integration(RID p_body, bool p_omit) { |
944 | GodotBody2D *body = body_owner.get_or_null(p_body); |
945 | ERR_FAIL_COND(!body); |
946 | |
947 | body->set_omit_force_integration(p_omit); |
948 | }; |
949 | |
950 | bool GodotPhysicsServer2D::body_is_omitting_force_integration(RID p_body) const { |
951 | GodotBody2D *body = body_owner.get_or_null(p_body); |
952 | ERR_FAIL_COND_V(!body, false); |
953 | return body->get_omit_force_integration(); |
954 | }; |
955 | |
956 | void GodotPhysicsServer2D::body_set_max_contacts_reported(RID p_body, int p_contacts) { |
957 | GodotBody2D *body = body_owner.get_or_null(p_body); |
958 | ERR_FAIL_COND(!body); |
959 | body->set_max_contacts_reported(p_contacts); |
960 | } |
961 | |
962 | int GodotPhysicsServer2D::body_get_max_contacts_reported(RID p_body) const { |
963 | GodotBody2D *body = body_owner.get_or_null(p_body); |
964 | ERR_FAIL_COND_V(!body, -1); |
965 | return body->get_max_contacts_reported(); |
966 | } |
967 | |
968 | void GodotPhysicsServer2D::body_set_state_sync_callback(RID p_body, const Callable &p_callable) { |
969 | GodotBody2D *body = body_owner.get_or_null(p_body); |
970 | ERR_FAIL_COND(!body); |
971 | body->set_state_sync_callback(p_callable); |
972 | } |
973 | |
974 | void GodotPhysicsServer2D::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) { |
975 | GodotBody2D *body = body_owner.get_or_null(p_body); |
976 | ERR_FAIL_COND(!body); |
977 | body->set_force_integration_callback(p_callable, p_udata); |
978 | } |
979 | |
980 | bool GodotPhysicsServer2D::body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) { |
981 | GodotBody2D *body = body_owner.get_or_null(p_body); |
982 | ERR_FAIL_COND_V(!body, false); |
983 | ERR_FAIL_INDEX_V(p_body_shape, body->get_shape_count(), false); |
984 | |
985 | return shape_collide(body->get_shape(p_body_shape)->get_self(), body->get_transform() * body->get_shape_transform(p_body_shape), Vector2(), p_shape, p_shape_xform, p_motion, r_results, p_result_max, r_result_count); |
986 | } |
987 | |
988 | void GodotPhysicsServer2D::body_set_pickable(RID p_body, bool p_pickable) { |
989 | GodotBody2D *body = body_owner.get_or_null(p_body); |
990 | ERR_FAIL_COND(!body); |
991 | body->set_pickable(p_pickable); |
992 | } |
993 | |
994 | bool GodotPhysicsServer2D::body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result) { |
995 | GodotBody2D *body = body_owner.get_or_null(p_body); |
996 | ERR_FAIL_COND_V(!body, false); |
997 | ERR_FAIL_COND_V(!body->get_space(), false); |
998 | ERR_FAIL_COND_V(body->get_space()->is_locked(), false); |
999 | |
1000 | _update_shapes(); |
1001 | |
1002 | return body->get_space()->test_body_motion(body, p_parameters, r_result); |
1003 | } |
1004 | |
1005 | PhysicsDirectBodyState2D *GodotPhysicsServer2D::body_get_direct_state(RID p_body) { |
1006 | ERR_FAIL_COND_V_MSG((using_threads && !doing_sync), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification." ); |
1007 | |
1008 | if (!body_owner.owns(p_body)) { |
1009 | return nullptr; |
1010 | } |
1011 | |
1012 | GodotBody2D *body = body_owner.get_or_null(p_body); |
1013 | ERR_FAIL_COND_V(!body, nullptr); |
1014 | |
1015 | if (!body->get_space()) { |
1016 | return nullptr; |
1017 | } |
1018 | |
1019 | ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification." ); |
1020 | |
1021 | return body->get_direct_state(); |
1022 | } |
1023 | |
1024 | /* JOINT API */ |
1025 | |
1026 | RID GodotPhysicsServer2D::joint_create() { |
1027 | GodotJoint2D *joint = memnew(GodotJoint2D); |
1028 | RID joint_rid = joint_owner.make_rid(joint); |
1029 | joint->set_self(joint_rid); |
1030 | return joint_rid; |
1031 | } |
1032 | |
1033 | void GodotPhysicsServer2D::joint_clear(RID p_joint) { |
1034 | GodotJoint2D *joint = joint_owner.get_or_null(p_joint); |
1035 | ERR_FAIL_NULL(joint); |
1036 | if (joint->get_type() != JOINT_TYPE_MAX) { |
1037 | GodotJoint2D *empty_joint = memnew(GodotJoint2D); |
1038 | empty_joint->copy_settings_from(joint); |
1039 | |
1040 | joint_owner.replace(p_joint, empty_joint); |
1041 | memdelete(joint); |
1042 | } |
1043 | } |
1044 | |
1045 | void GodotPhysicsServer2D::joint_set_param(RID p_joint, JointParam p_param, real_t p_value) { |
1046 | GodotJoint2D *joint = joint_owner.get_or_null(p_joint); |
1047 | ERR_FAIL_COND(!joint); |
1048 | |
1049 | switch (p_param) { |
1050 | case JOINT_PARAM_BIAS: |
1051 | joint->set_bias(p_value); |
1052 | break; |
1053 | case JOINT_PARAM_MAX_BIAS: |
1054 | joint->set_max_bias(p_value); |
1055 | break; |
1056 | case JOINT_PARAM_MAX_FORCE: |
1057 | joint->set_max_force(p_value); |
1058 | break; |
1059 | } |
1060 | } |
1061 | |
1062 | real_t GodotPhysicsServer2D::joint_get_param(RID p_joint, JointParam p_param) const { |
1063 | const GodotJoint2D *joint = joint_owner.get_or_null(p_joint); |
1064 | ERR_FAIL_COND_V(!joint, -1); |
1065 | |
1066 | switch (p_param) { |
1067 | case JOINT_PARAM_BIAS: |
1068 | return joint->get_bias(); |
1069 | break; |
1070 | case JOINT_PARAM_MAX_BIAS: |
1071 | return joint->get_max_bias(); |
1072 | break; |
1073 | case JOINT_PARAM_MAX_FORCE: |
1074 | return joint->get_max_force(); |
1075 | break; |
1076 | } |
1077 | |
1078 | return 0; |
1079 | } |
1080 | |
1081 | void GodotPhysicsServer2D::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) { |
1082 | GodotJoint2D *joint = joint_owner.get_or_null(p_joint); |
1083 | ERR_FAIL_COND(!joint); |
1084 | |
1085 | joint->disable_collisions_between_bodies(p_disable); |
1086 | |
1087 | if (2 == joint->get_body_count()) { |
1088 | GodotBody2D *body_a = *joint->get_body_ptr(); |
1089 | GodotBody2D *body_b = *(joint->get_body_ptr() + 1); |
1090 | |
1091 | if (p_disable) { |
1092 | body_add_collision_exception(body_a->get_self(), body_b->get_self()); |
1093 | body_add_collision_exception(body_b->get_self(), body_a->get_self()); |
1094 | } else { |
1095 | body_remove_collision_exception(body_a->get_self(), body_b->get_self()); |
1096 | body_remove_collision_exception(body_b->get_self(), body_a->get_self()); |
1097 | } |
1098 | } |
1099 | } |
1100 | |
1101 | bool GodotPhysicsServer2D::joint_is_disabled_collisions_between_bodies(RID p_joint) const { |
1102 | const GodotJoint2D *joint = joint_owner.get_or_null(p_joint); |
1103 | ERR_FAIL_COND_V(!joint, true); |
1104 | |
1105 | return joint->is_disabled_collisions_between_bodies(); |
1106 | } |
1107 | |
1108 | void GodotPhysicsServer2D::joint_make_pin(RID p_joint, const Vector2 &p_pos, RID p_body_a, RID p_body_b) { |
1109 | GodotBody2D *A = body_owner.get_or_null(p_body_a); |
1110 | ERR_FAIL_COND(!A); |
1111 | GodotBody2D *B = nullptr; |
1112 | if (body_owner.owns(p_body_b)) { |
1113 | B = body_owner.get_or_null(p_body_b); |
1114 | ERR_FAIL_COND(!B); |
1115 | } |
1116 | |
1117 | GodotJoint2D *prev_joint = joint_owner.get_or_null(p_joint); |
1118 | ERR_FAIL_COND(prev_joint == nullptr); |
1119 | |
1120 | GodotJoint2D *joint = memnew(GodotPinJoint2D(p_pos, A, B)); |
1121 | |
1122 | joint_owner.replace(p_joint, joint); |
1123 | joint->copy_settings_from(prev_joint); |
1124 | memdelete(prev_joint); |
1125 | } |
1126 | |
1127 | void GodotPhysicsServer2D::joint_make_groove(RID p_joint, const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) { |
1128 | GodotBody2D *A = body_owner.get_or_null(p_body_a); |
1129 | ERR_FAIL_COND(!A); |
1130 | |
1131 | GodotBody2D *B = body_owner.get_or_null(p_body_b); |
1132 | ERR_FAIL_COND(!B); |
1133 | |
1134 | GodotJoint2D *prev_joint = joint_owner.get_or_null(p_joint); |
1135 | ERR_FAIL_COND(prev_joint == nullptr); |
1136 | |
1137 | GodotJoint2D *joint = memnew(GodotGrooveJoint2D(p_a_groove1, p_a_groove2, p_b_anchor, A, B)); |
1138 | |
1139 | joint_owner.replace(p_joint, joint); |
1140 | joint->copy_settings_from(prev_joint); |
1141 | memdelete(prev_joint); |
1142 | } |
1143 | |
1144 | void GodotPhysicsServer2D::joint_make_damped_spring(RID p_joint, const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b) { |
1145 | GodotBody2D *A = body_owner.get_or_null(p_body_a); |
1146 | ERR_FAIL_COND(!A); |
1147 | |
1148 | GodotBody2D *B = body_owner.get_or_null(p_body_b); |
1149 | ERR_FAIL_COND(!B); |
1150 | |
1151 | GodotJoint2D *prev_joint = joint_owner.get_or_null(p_joint); |
1152 | ERR_FAIL_COND(prev_joint == nullptr); |
1153 | |
1154 | GodotJoint2D *joint = memnew(GodotDampedSpringJoint2D(p_anchor_a, p_anchor_b, A, B)); |
1155 | |
1156 | joint_owner.replace(p_joint, joint); |
1157 | joint->copy_settings_from(prev_joint); |
1158 | memdelete(prev_joint); |
1159 | } |
1160 | |
1161 | void GodotPhysicsServer2D::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) { |
1162 | GodotJoint2D *joint = joint_owner.get_or_null(p_joint); |
1163 | ERR_FAIL_NULL(joint); |
1164 | ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_PIN); |
1165 | |
1166 | GodotPinJoint2D *pin_joint = static_cast<GodotPinJoint2D *>(joint); |
1167 | pin_joint->set_param(p_param, p_value); |
1168 | } |
1169 | |
1170 | real_t GodotPhysicsServer2D::pin_joint_get_param(RID p_joint, PinJointParam p_param) const { |
1171 | GodotJoint2D *joint = joint_owner.get_or_null(p_joint); |
1172 | ERR_FAIL_NULL_V(joint, 0); |
1173 | ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_PIN, 0); |
1174 | |
1175 | GodotPinJoint2D *pin_joint = static_cast<GodotPinJoint2D *>(joint); |
1176 | return pin_joint->get_param(p_param); |
1177 | } |
1178 | |
1179 | void GodotPhysicsServer2D::damped_spring_joint_set_param(RID p_joint, DampedSpringParam p_param, real_t p_value) { |
1180 | GodotJoint2D *joint = joint_owner.get_or_null(p_joint); |
1181 | ERR_FAIL_NULL(joint); |
1182 | ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_DAMPED_SPRING); |
1183 | |
1184 | GodotDampedSpringJoint2D *dsj = static_cast<GodotDampedSpringJoint2D *>(joint); |
1185 | dsj->set_param(p_param, p_value); |
1186 | } |
1187 | |
1188 | real_t GodotPhysicsServer2D::damped_spring_joint_get_param(RID p_joint, DampedSpringParam p_param) const { |
1189 | GodotJoint2D *joint = joint_owner.get_or_null(p_joint); |
1190 | ERR_FAIL_NULL_V(joint, 0); |
1191 | ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_DAMPED_SPRING, 0); |
1192 | |
1193 | GodotDampedSpringJoint2D *dsj = static_cast<GodotDampedSpringJoint2D *>(joint); |
1194 | return dsj->get_param(p_param); |
1195 | } |
1196 | |
1197 | PhysicsServer2D::JointType GodotPhysicsServer2D::joint_get_type(RID p_joint) const { |
1198 | GodotJoint2D *joint = joint_owner.get_or_null(p_joint); |
1199 | ERR_FAIL_COND_V(!joint, JOINT_TYPE_PIN); |
1200 | |
1201 | return joint->get_type(); |
1202 | } |
1203 | |
1204 | void GodotPhysicsServer2D::free(RID p_rid) { |
1205 | _update_shapes(); // just in case |
1206 | |
1207 | if (shape_owner.owns(p_rid)) { |
1208 | GodotShape2D *shape = shape_owner.get_or_null(p_rid); |
1209 | |
1210 | while (shape->get_owners().size()) { |
1211 | GodotShapeOwner2D *so = shape->get_owners().begin()->key; |
1212 | so->remove_shape(shape); |
1213 | } |
1214 | |
1215 | shape_owner.free(p_rid); |
1216 | memdelete(shape); |
1217 | } else if (body_owner.owns(p_rid)) { |
1218 | GodotBody2D *body = body_owner.get_or_null(p_rid); |
1219 | |
1220 | body_set_space(p_rid, RID()); |
1221 | |
1222 | while (body->get_shape_count()) { |
1223 | body->remove_shape(0); |
1224 | } |
1225 | |
1226 | body_owner.free(p_rid); |
1227 | memdelete(body); |
1228 | |
1229 | } else if (area_owner.owns(p_rid)) { |
1230 | GodotArea2D *area = area_owner.get_or_null(p_rid); |
1231 | |
1232 | area->set_space(nullptr); |
1233 | |
1234 | while (area->get_shape_count()) { |
1235 | area->remove_shape(0); |
1236 | } |
1237 | |
1238 | area_owner.free(p_rid); |
1239 | memdelete(area); |
1240 | } else if (space_owner.owns(p_rid)) { |
1241 | GodotSpace2D *space = space_owner.get_or_null(p_rid); |
1242 | |
1243 | while (space->get_objects().size()) { |
1244 | GodotCollisionObject2D *co = static_cast<GodotCollisionObject2D *>(*space->get_objects().begin()); |
1245 | co->set_space(nullptr); |
1246 | } |
1247 | |
1248 | active_spaces.erase(space); |
1249 | free(space->get_default_area()->get_self()); |
1250 | space_owner.free(p_rid); |
1251 | memdelete(space); |
1252 | } else if (joint_owner.owns(p_rid)) { |
1253 | GodotJoint2D *joint = joint_owner.get_or_null(p_rid); |
1254 | |
1255 | joint_owner.free(p_rid); |
1256 | memdelete(joint); |
1257 | |
1258 | } else { |
1259 | ERR_FAIL_MSG("Invalid ID." ); |
1260 | } |
1261 | } |
1262 | |
1263 | void GodotPhysicsServer2D::set_active(bool p_active) { |
1264 | active = p_active; |
1265 | } |
1266 | |
1267 | void GodotPhysicsServer2D::init() { |
1268 | doing_sync = false; |
1269 | stepper = memnew(GodotStep2D); |
1270 | } |
1271 | |
1272 | void GodotPhysicsServer2D::step(real_t p_step) { |
1273 | if (!active) { |
1274 | return; |
1275 | } |
1276 | |
1277 | _update_shapes(); |
1278 | |
1279 | island_count = 0; |
1280 | active_objects = 0; |
1281 | collision_pairs = 0; |
1282 | for (const GodotSpace2D *E : active_spaces) { |
1283 | stepper->step(const_cast<GodotSpace2D *>(E), p_step); |
1284 | island_count += E->get_island_count(); |
1285 | active_objects += E->get_active_objects(); |
1286 | collision_pairs += E->get_collision_pairs(); |
1287 | } |
1288 | } |
1289 | |
1290 | void GodotPhysicsServer2D::sync() { |
1291 | doing_sync = true; |
1292 | } |
1293 | |
1294 | void GodotPhysicsServer2D::flush_queries() { |
1295 | if (!active) { |
1296 | return; |
1297 | } |
1298 | |
1299 | flushing_queries = true; |
1300 | |
1301 | uint64_t time_beg = OS::get_singleton()->get_ticks_usec(); |
1302 | |
1303 | for (const GodotSpace2D *E : active_spaces) { |
1304 | GodotSpace2D *space = const_cast<GodotSpace2D *>(E); |
1305 | space->call_queries(); |
1306 | } |
1307 | |
1308 | flushing_queries = false; |
1309 | |
1310 | if (EngineDebugger::is_profiling("servers" )) { |
1311 | uint64_t total_time[GodotSpace2D::ELAPSED_TIME_MAX]; |
1312 | static const char *time_name[GodotSpace2D::ELAPSED_TIME_MAX] = { |
1313 | "integrate_forces" , |
1314 | "generate_islands" , |
1315 | "setup_constraints" , |
1316 | "solve_constraints" , |
1317 | "integrate_velocities" |
1318 | }; |
1319 | |
1320 | for (int i = 0; i < GodotSpace2D::ELAPSED_TIME_MAX; i++) { |
1321 | total_time[i] = 0; |
1322 | } |
1323 | |
1324 | for (const GodotSpace2D *E : active_spaces) { |
1325 | for (int i = 0; i < GodotSpace2D::ELAPSED_TIME_MAX; i++) { |
1326 | total_time[i] += E->get_elapsed_time(GodotSpace2D::ElapsedTime(i)); |
1327 | } |
1328 | } |
1329 | |
1330 | Array values; |
1331 | values.resize(GodotSpace2D::ELAPSED_TIME_MAX * 2); |
1332 | for (int i = 0; i < GodotSpace2D::ELAPSED_TIME_MAX; i++) { |
1333 | values[i * 2 + 0] = time_name[i]; |
1334 | values[i * 2 + 1] = USEC_TO_SEC(total_time[i]); |
1335 | } |
1336 | values.push_back("flush_queries" ); |
1337 | values.push_back(USEC_TO_SEC(OS::get_singleton()->get_ticks_usec() - time_beg)); |
1338 | |
1339 | values.push_front("physics_2d" ); |
1340 | EngineDebugger::profiler_add_frame_data("servers" , values); |
1341 | } |
1342 | } |
1343 | |
1344 | void GodotPhysicsServer2D::end_sync() { |
1345 | doing_sync = false; |
1346 | } |
1347 | |
1348 | void GodotPhysicsServer2D::finish() { |
1349 | memdelete(stepper); |
1350 | } |
1351 | |
1352 | void GodotPhysicsServer2D::_update_shapes() { |
1353 | while (pending_shape_update_list.first()) { |
1354 | pending_shape_update_list.first()->self()->_shape_changed(); |
1355 | pending_shape_update_list.remove(pending_shape_update_list.first()); |
1356 | } |
1357 | } |
1358 | |
1359 | int GodotPhysicsServer2D::get_process_info(ProcessInfo p_info) { |
1360 | switch (p_info) { |
1361 | case INFO_ACTIVE_OBJECTS: { |
1362 | return active_objects; |
1363 | } break; |
1364 | case INFO_COLLISION_PAIRS: { |
1365 | return collision_pairs; |
1366 | } break; |
1367 | case INFO_ISLAND_COUNT: { |
1368 | return island_count; |
1369 | } break; |
1370 | } |
1371 | |
1372 | return 0; |
1373 | } |
1374 | |
1375 | GodotPhysicsServer2D *GodotPhysicsServer2D::godot_singleton = nullptr; |
1376 | |
1377 | GodotPhysicsServer2D::GodotPhysicsServer2D(bool p_using_threads) { |
1378 | godot_singleton = this; |
1379 | GodotBroadPhase2D::create_func = GodotBroadPhase2DBVH::_create; |
1380 | |
1381 | using_threads = p_using_threads; |
1382 | } |
1383 | |