Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/godot_physics_3d/godot_area_3d.cpp
10278 views
1
/**************************************************************************/
2
/* godot_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 "godot_area_3d.h"
32
33
#include "godot_body_3d.h"
34
#include "godot_soft_body_3d.h"
35
#include "godot_space_3d.h"
36
37
GodotArea3D::BodyKey::BodyKey(GodotSoftBody3D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
38
rid = p_body->get_self();
39
instance_id = p_body->get_instance_id();
40
body_shape = p_body_shape;
41
area_shape = p_area_shape;
42
}
43
44
GodotArea3D::BodyKey::BodyKey(GodotBody3D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
45
rid = p_body->get_self();
46
instance_id = p_body->get_instance_id();
47
body_shape = p_body_shape;
48
area_shape = p_area_shape;
49
}
50
51
GodotArea3D::BodyKey::BodyKey(GodotArea3D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
52
rid = p_body->get_self();
53
instance_id = p_body->get_instance_id();
54
body_shape = p_body_shape;
55
area_shape = p_area_shape;
56
}
57
58
void GodotArea3D::_shapes_changed() {
59
if (!moved_list.in_list() && get_space()) {
60
get_space()->area_add_to_moved_list(&moved_list);
61
}
62
}
63
64
void GodotArea3D::set_transform(const Transform3D &p_transform) {
65
if (!moved_list.in_list() && get_space()) {
66
get_space()->area_add_to_moved_list(&moved_list);
67
}
68
69
_set_transform(p_transform);
70
_set_inv_transform(p_transform.affine_inverse());
71
}
72
73
void GodotArea3D::set_space(GodotSpace3D *p_space) {
74
if (get_space()) {
75
if (monitor_query_list.in_list()) {
76
get_space()->area_remove_from_monitor_query_list(&monitor_query_list);
77
}
78
if (moved_list.in_list()) {
79
get_space()->area_remove_from_moved_list(&moved_list);
80
}
81
}
82
83
monitored_bodies.clear();
84
monitored_areas.clear();
85
86
_set_space(p_space);
87
}
88
89
void GodotArea3D::set_monitor_callback(const Callable &p_callback) {
90
_unregister_shapes();
91
92
monitor_callback = p_callback;
93
94
monitored_bodies.clear();
95
monitored_areas.clear();
96
97
_shape_changed();
98
99
if (!moved_list.in_list() && get_space()) {
100
get_space()->area_add_to_moved_list(&moved_list);
101
}
102
}
103
104
void GodotArea3D::set_area_monitor_callback(const Callable &p_callback) {
105
_unregister_shapes();
106
107
area_monitor_callback = p_callback;
108
109
monitored_bodies.clear();
110
monitored_areas.clear();
111
112
_shape_changed();
113
114
if (!moved_list.in_list() && get_space()) {
115
get_space()->area_add_to_moved_list(&moved_list);
116
}
117
}
118
119
void GodotArea3D::_set_space_override_mode(PhysicsServer3D::AreaSpaceOverrideMode &r_mode, PhysicsServer3D::AreaSpaceOverrideMode p_new_mode) {
120
bool do_override = p_new_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED;
121
if (do_override == (r_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED)) {
122
return;
123
}
124
_unregister_shapes();
125
r_mode = p_new_mode;
126
_shape_changed();
127
}
128
129
void GodotArea3D::set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value) {
130
switch (p_param) {
131
case PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE:
132
_set_space_override_mode(gravity_override_mode, (PhysicsServer3D::AreaSpaceOverrideMode)(int)p_value);
133
break;
134
case PhysicsServer3D::AREA_PARAM_GRAVITY:
135
gravity = p_value;
136
break;
137
case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR:
138
gravity_vector = p_value;
139
break;
140
case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT:
141
gravity_is_point = p_value;
142
break;
143
case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE:
144
gravity_point_unit_distance = p_value;
145
break;
146
case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE:
147
_set_space_override_mode(linear_damping_override_mode, (PhysicsServer3D::AreaSpaceOverrideMode)(int)p_value);
148
break;
149
case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP:
150
linear_damp = p_value;
151
break;
152
case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE:
153
_set_space_override_mode(angular_damping_override_mode, (PhysicsServer3D::AreaSpaceOverrideMode)(int)p_value);
154
break;
155
case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP:
156
angular_damp = p_value;
157
break;
158
case PhysicsServer3D::AREA_PARAM_PRIORITY:
159
priority = p_value;
160
break;
161
case PhysicsServer3D::AREA_PARAM_WIND_FORCE_MAGNITUDE:
162
ERR_FAIL_COND_MSG(wind_force_magnitude < 0, "Wind force magnitude must be a non-negative real number, but a negative number was specified.");
163
wind_force_magnitude = p_value;
164
break;
165
case PhysicsServer3D::AREA_PARAM_WIND_SOURCE:
166
wind_source = p_value;
167
break;
168
case PhysicsServer3D::AREA_PARAM_WIND_DIRECTION:
169
wind_direction = p_value;
170
break;
171
case PhysicsServer3D::AREA_PARAM_WIND_ATTENUATION_FACTOR:
172
ERR_FAIL_COND_MSG(wind_attenuation_factor < 0, "Wind attenuation factor must be a non-negative real number, but a negative number was specified.");
173
wind_attenuation_factor = p_value;
174
break;
175
}
176
}
177
178
Variant GodotArea3D::get_param(PhysicsServer3D::AreaParameter p_param) const {
179
switch (p_param) {
180
case PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE:
181
return gravity_override_mode;
182
case PhysicsServer3D::AREA_PARAM_GRAVITY:
183
return gravity;
184
case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR:
185
return gravity_vector;
186
case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT:
187
return gravity_is_point;
188
case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE:
189
return gravity_point_unit_distance;
190
case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE:
191
return linear_damping_override_mode;
192
case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP:
193
return linear_damp;
194
case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE:
195
return angular_damping_override_mode;
196
case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP:
197
return angular_damp;
198
case PhysicsServer3D::AREA_PARAM_PRIORITY:
199
return priority;
200
case PhysicsServer3D::AREA_PARAM_WIND_FORCE_MAGNITUDE:
201
return wind_force_magnitude;
202
case PhysicsServer3D::AREA_PARAM_WIND_SOURCE:
203
return wind_source;
204
case PhysicsServer3D::AREA_PARAM_WIND_DIRECTION:
205
return wind_direction;
206
case PhysicsServer3D::AREA_PARAM_WIND_ATTENUATION_FACTOR:
207
return wind_attenuation_factor;
208
}
209
210
return Variant();
211
}
212
213
void GodotArea3D::_queue_monitor_update() {
214
ERR_FAIL_NULL(get_space());
215
216
if (!monitor_query_list.in_list()) {
217
get_space()->area_add_to_monitor_query_list(&monitor_query_list);
218
}
219
}
220
221
void GodotArea3D::set_monitorable(bool p_monitorable) {
222
if (monitorable == p_monitorable) {
223
return;
224
}
225
226
monitorable = p_monitorable;
227
_set_static(!monitorable);
228
_shapes_changed();
229
}
230
231
void GodotArea3D::call_queries() {
232
if (!monitor_callback.is_null() && !monitored_bodies.is_empty()) {
233
if (monitor_callback.is_valid()) {
234
Variant res[5];
235
Variant *resptr[5];
236
for (int i = 0; i < 5; i++) {
237
resptr[i] = &res[i];
238
}
239
240
for (HashMap<BodyKey, BodyState, BodyKey>::Iterator E = monitored_bodies.begin(); E;) {
241
if (E->value.state == 0) { // Nothing happened
242
HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;
243
++next;
244
monitored_bodies.remove(E);
245
E = next;
246
continue;
247
}
248
249
res[0] = E->value.state > 0 ? PhysicsServer3D::AREA_BODY_ADDED : PhysicsServer3D::AREA_BODY_REMOVED;
250
res[1] = E->key.rid;
251
res[2] = E->key.instance_id;
252
res[3] = E->key.body_shape;
253
res[4] = E->key.area_shape;
254
255
HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;
256
++next;
257
monitored_bodies.remove(E);
258
E = next;
259
260
Callable::CallError ce;
261
Variant ret;
262
monitor_callback.callp((const Variant **)resptr, 5, ret, ce);
263
264
if (ce.error != Callable::CallError::CALL_OK) {
265
ERR_PRINT_ONCE("Error calling monitor callback method " + Variant::get_callable_error_text(monitor_callback, (const Variant **)resptr, 5, ce));
266
}
267
}
268
} else {
269
monitored_bodies.clear();
270
monitor_callback = Callable();
271
}
272
}
273
274
if (!area_monitor_callback.is_null() && !monitored_areas.is_empty()) {
275
if (area_monitor_callback.is_valid()) {
276
Variant res[5];
277
Variant *resptr[5];
278
for (int i = 0; i < 5; i++) {
279
resptr[i] = &res[i];
280
}
281
282
for (HashMap<BodyKey, BodyState, BodyKey>::Iterator E = monitored_areas.begin(); E;) {
283
if (E->value.state == 0) { // Nothing happened
284
HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;
285
++next;
286
monitored_areas.remove(E);
287
E = next;
288
continue;
289
}
290
291
res[0] = E->value.state > 0 ? PhysicsServer3D::AREA_BODY_ADDED : PhysicsServer3D::AREA_BODY_REMOVED;
292
res[1] = E->key.rid;
293
res[2] = E->key.instance_id;
294
res[3] = E->key.body_shape;
295
res[4] = E->key.area_shape;
296
297
HashMap<BodyKey, BodyState, BodyKey>::Iterator next = E;
298
++next;
299
monitored_areas.remove(E);
300
E = next;
301
302
Callable::CallError ce;
303
Variant ret;
304
area_monitor_callback.callp((const Variant **)resptr, 5, ret, ce);
305
306
if (ce.error != Callable::CallError::CALL_OK) {
307
ERR_PRINT_ONCE("Error calling area monitor callback method " + Variant::get_callable_error_text(area_monitor_callback, (const Variant **)resptr, 5, ce));
308
}
309
}
310
} else {
311
monitored_areas.clear();
312
area_monitor_callback = Callable();
313
}
314
}
315
}
316
317
void GodotArea3D::compute_gravity(const Vector3 &p_position, Vector3 &r_gravity) const {
318
if (is_gravity_point()) {
319
const real_t gr_unit_dist = get_gravity_point_unit_distance();
320
Vector3 v = get_transform().xform(get_gravity_vector()) - p_position;
321
if (gr_unit_dist > 0) {
322
const real_t v_length_sq = v.length_squared();
323
if (v_length_sq > 0) {
324
const real_t gravity_strength = get_gravity() * gr_unit_dist * gr_unit_dist / v_length_sq;
325
r_gravity = v.normalized() * gravity_strength;
326
} else {
327
r_gravity = Vector3();
328
}
329
} else {
330
r_gravity = v.normalized() * get_gravity();
331
}
332
} else {
333
r_gravity = get_gravity_vector() * get_gravity();
334
}
335
}
336
337
GodotArea3D::GodotArea3D() :
338
GodotCollisionObject3D(TYPE_AREA),
339
monitor_query_list(this),
340
moved_list(this) {
341
_set_static(true); //areas are never active
342
set_ray_pickable(false);
343
}
344
345
GodotArea3D::~GodotArea3D() {
346
}
347
348