1/**************************************************************************/
2/* physics_body_2d.h */
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#ifndef PHYSICS_BODY_2D_H
32#define PHYSICS_BODY_2D_H
33
34#include "core/templates/vset.h"
35#include "scene/2d/collision_object_2d.h"
36#include "scene/resources/physics_material.h"
37#include "servers/physics_server_2d.h"
38
39class KinematicCollision2D;
40
41class PhysicsBody2D : public CollisionObject2D {
42 GDCLASS(PhysicsBody2D, CollisionObject2D);
43
44protected:
45 static void _bind_methods();
46 PhysicsBody2D(PhysicsServer2D::BodyMode p_mode);
47
48 Ref<KinematicCollision2D> motion_cache;
49
50 Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_test_only = false, real_t p_margin = 0.08, bool p_recovery_as_collision = false);
51
52public:
53 bool move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true);
54 bool test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08, bool p_recovery_as_collision = false);
55
56 TypedArray<PhysicsBody2D> get_collision_exceptions();
57 void add_collision_exception_with(Node *p_node); //must be physicsbody
58 void remove_collision_exception_with(Node *p_node);
59
60 virtual ~PhysicsBody2D();
61};
62
63class StaticBody2D : public PhysicsBody2D {
64 GDCLASS(StaticBody2D, PhysicsBody2D);
65
66private:
67 Vector2 constant_linear_velocity;
68 real_t constant_angular_velocity = 0.0;
69
70 Ref<PhysicsMaterial> physics_material_override;
71
72protected:
73 static void _bind_methods();
74
75public:
76 void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
77 Ref<PhysicsMaterial> get_physics_material_override() const;
78
79 void set_constant_linear_velocity(const Vector2 &p_vel);
80 void set_constant_angular_velocity(real_t p_vel);
81
82 Vector2 get_constant_linear_velocity() const;
83 real_t get_constant_angular_velocity() const;
84
85 StaticBody2D(PhysicsServer2D::BodyMode p_mode = PhysicsServer2D::BODY_MODE_STATIC);
86
87private:
88 void _reload_physics_characteristics();
89};
90
91class AnimatableBody2D : public StaticBody2D {
92 GDCLASS(AnimatableBody2D, StaticBody2D);
93
94private:
95 bool sync_to_physics = true;
96
97 Transform2D last_valid_transform;
98
99 static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state);
100 void _body_state_changed(PhysicsDirectBodyState2D *p_state);
101
102protected:
103 void _notification(int p_what);
104 static void _bind_methods();
105
106public:
107 AnimatableBody2D();
108
109private:
110 void _update_kinematic_motion();
111
112 void set_sync_to_physics(bool p_enable);
113 bool is_sync_to_physics_enabled() const;
114};
115
116class RigidBody2D : public PhysicsBody2D {
117 GDCLASS(RigidBody2D, PhysicsBody2D);
118
119public:
120 enum FreezeMode {
121 FREEZE_MODE_STATIC,
122 FREEZE_MODE_KINEMATIC,
123 };
124
125 enum CenterOfMassMode {
126 CENTER_OF_MASS_MODE_AUTO,
127 CENTER_OF_MASS_MODE_CUSTOM,
128 };
129
130 enum DampMode {
131 DAMP_MODE_COMBINE,
132 DAMP_MODE_REPLACE,
133 };
134
135 enum CCDMode {
136 CCD_MODE_DISABLED,
137 CCD_MODE_CAST_RAY,
138 CCD_MODE_CAST_SHAPE,
139 };
140
141private:
142 bool can_sleep = true;
143 bool lock_rotation = false;
144 bool freeze = false;
145 FreezeMode freeze_mode = FREEZE_MODE_STATIC;
146
147 real_t mass = 1.0;
148 real_t inertia = 0.0;
149 CenterOfMassMode center_of_mass_mode = CENTER_OF_MASS_MODE_AUTO;
150 Vector2 center_of_mass;
151
152 Ref<PhysicsMaterial> physics_material_override;
153 real_t gravity_scale = 1.0;
154
155 DampMode linear_damp_mode = DAMP_MODE_COMBINE;
156 DampMode angular_damp_mode = DAMP_MODE_COMBINE;
157
158 real_t linear_damp = 0.0;
159 real_t angular_damp = 0.0;
160
161 Vector2 linear_velocity;
162 real_t angular_velocity = 0.0;
163 bool sleeping = false;
164
165 int max_contacts_reported = 0;
166
167 bool custom_integrator = false;
168
169 CCDMode ccd_mode = CCD_MODE_DISABLED;
170
171 struct ShapePair {
172 int body_shape = 0;
173 int local_shape = 0;
174 bool tagged = false;
175 bool operator<(const ShapePair &p_sp) const {
176 if (body_shape == p_sp.body_shape) {
177 return local_shape < p_sp.local_shape;
178 }
179
180 return body_shape < p_sp.body_shape;
181 }
182
183 ShapePair() {}
184 ShapePair(int p_bs, int p_ls) {
185 body_shape = p_bs;
186 local_shape = p_ls;
187 }
188 };
189 struct RigidBody2D_RemoveAction {
190 RID rid;
191 ObjectID body_id;
192 ShapePair pair;
193 };
194 struct BodyState {
195 RID rid;
196 //int rc;
197 bool in_scene = false;
198 VSet<ShapePair> shapes;
199 };
200
201 struct ContactMonitor {
202 bool locked = false;
203 HashMap<ObjectID, BodyState> body_map;
204 };
205
206 ContactMonitor *contact_monitor = nullptr;
207 void _body_enter_tree(ObjectID p_id);
208 void _body_exit_tree(ObjectID p_id);
209
210 void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape);
211
212 static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state);
213 void _body_state_changed(PhysicsDirectBodyState2D *p_state);
214
215 void _sync_body_state(PhysicsDirectBodyState2D *p_state);
216
217protected:
218 void _notification(int p_what);
219 static void _bind_methods();
220
221 void _validate_property(PropertyInfo &p_property) const;
222
223 GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState2D *)
224
225 void _apply_body_mode();
226
227public:
228 void set_lock_rotation_enabled(bool p_lock_rotation);
229 bool is_lock_rotation_enabled() const;
230
231 void set_freeze_enabled(bool p_freeze);
232 bool is_freeze_enabled() const;
233
234 void set_freeze_mode(FreezeMode p_freeze_mode);
235 FreezeMode get_freeze_mode() const;
236
237 void set_mass(real_t p_mass);
238 real_t get_mass() const;
239
240 void set_inertia(real_t p_inertia);
241 real_t get_inertia() const;
242
243 void set_center_of_mass_mode(CenterOfMassMode p_mode);
244 CenterOfMassMode get_center_of_mass_mode() const;
245
246 void set_center_of_mass(const Vector2 &p_center_of_mass);
247 const Vector2 &get_center_of_mass() const;
248
249 void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
250 Ref<PhysicsMaterial> get_physics_material_override() const;
251
252 void set_gravity_scale(real_t p_gravity_scale);
253 real_t get_gravity_scale() const;
254
255 void set_linear_damp_mode(DampMode p_mode);
256 DampMode get_linear_damp_mode() const;
257
258 void set_angular_damp_mode(DampMode p_mode);
259 DampMode get_angular_damp_mode() const;
260
261 void set_linear_damp(real_t p_linear_damp);
262 real_t get_linear_damp() const;
263
264 void set_angular_damp(real_t p_angular_damp);
265 real_t get_angular_damp() const;
266
267 void set_linear_velocity(const Vector2 &p_velocity);
268 Vector2 get_linear_velocity() const;
269
270 void set_axis_velocity(const Vector2 &p_axis);
271
272 void set_angular_velocity(real_t p_velocity);
273 real_t get_angular_velocity() const;
274
275 void set_use_custom_integrator(bool p_enable);
276 bool is_using_custom_integrator();
277
278 void set_sleeping(bool p_sleeping);
279 bool is_sleeping() const;
280
281 void set_can_sleep(bool p_active);
282 bool is_able_to_sleep() const;
283
284 void set_contact_monitor(bool p_enabled);
285 bool is_contact_monitor_enabled() const;
286
287 void set_max_contacts_reported(int p_amount);
288 int get_max_contacts_reported() const;
289 int get_contact_count() const;
290
291 void set_continuous_collision_detection_mode(CCDMode p_mode);
292 CCDMode get_continuous_collision_detection_mode() const;
293
294 void apply_central_impulse(const Vector2 &p_impulse);
295 void apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2());
296 void apply_torque_impulse(real_t p_torque);
297
298 void apply_central_force(const Vector2 &p_force);
299 void apply_force(const Vector2 &p_force, const Vector2 &p_position = Vector2());
300 void apply_torque(real_t p_torque);
301
302 void add_constant_central_force(const Vector2 &p_force);
303 void add_constant_force(const Vector2 &p_force, const Vector2 &p_position = Vector2());
304 void add_constant_torque(real_t p_torque);
305
306 void set_constant_force(const Vector2 &p_force);
307 Vector2 get_constant_force() const;
308
309 void set_constant_torque(real_t p_torque);
310 real_t get_constant_torque() const;
311
312 TypedArray<Node2D> get_colliding_bodies() const; //function for script
313
314 virtual PackedStringArray get_configuration_warnings() const override;
315
316 RigidBody2D();
317 ~RigidBody2D();
318
319private:
320 void _reload_physics_characteristics();
321};
322
323VARIANT_ENUM_CAST(RigidBody2D::FreezeMode);
324VARIANT_ENUM_CAST(RigidBody2D::CenterOfMassMode);
325VARIANT_ENUM_CAST(RigidBody2D::DampMode);
326VARIANT_ENUM_CAST(RigidBody2D::CCDMode);
327
328class CharacterBody2D : public PhysicsBody2D {
329 GDCLASS(CharacterBody2D, PhysicsBody2D);
330
331public:
332 enum MotionMode {
333 MOTION_MODE_GROUNDED,
334 MOTION_MODE_FLOATING,
335 };
336 enum PlatformOnLeave {
337 PLATFORM_ON_LEAVE_ADD_VELOCITY,
338 PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY,
339 PLATFORM_ON_LEAVE_DO_NOTHING,
340 };
341 bool move_and_slide();
342 void apply_floor_snap();
343
344 const Vector2 &get_velocity() const;
345 void set_velocity(const Vector2 &p_velocity);
346
347 bool is_on_floor() const;
348 bool is_on_floor_only() const;
349 bool is_on_wall() const;
350 bool is_on_wall_only() const;
351 bool is_on_ceiling() const;
352 bool is_on_ceiling_only() const;
353 const Vector2 &get_last_motion() const;
354 Vector2 get_position_delta() const;
355 const Vector2 &get_floor_normal() const;
356 const Vector2 &get_wall_normal() const;
357 const Vector2 &get_real_velocity() const;
358
359 real_t get_floor_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const;
360 const Vector2 &get_platform_velocity() const;
361
362 int get_slide_collision_count() const;
363 PhysicsServer2D::MotionResult get_slide_collision(int p_bounce) const;
364
365 CharacterBody2D();
366 ~CharacterBody2D();
367
368private:
369 real_t margin = 0.08;
370 MotionMode motion_mode = MOTION_MODE_GROUNDED;
371 PlatformOnLeave platform_on_leave = PLATFORM_ON_LEAVE_ADD_VELOCITY;
372
373 bool floor_constant_speed = false;
374 bool floor_stop_on_slope = true;
375 bool floor_block_on_wall = true;
376 bool slide_on_ceiling = true;
377 int max_slides = 4;
378 int platform_layer = 0;
379 real_t floor_max_angle = Math::deg_to_rad((real_t)45.0);
380 real_t floor_snap_length = 1;
381 real_t wall_min_slide_angle = Math::deg_to_rad((real_t)15.0);
382 Vector2 up_direction = Vector2(0.0, -1.0);
383 uint32_t platform_floor_layers = UINT32_MAX;
384 uint32_t platform_wall_layers = 0;
385 Vector2 velocity;
386
387 Vector2 floor_normal;
388 Vector2 platform_velocity;
389 Vector2 wall_normal;
390 Vector2 last_motion;
391 Vector2 previous_position;
392 Vector2 real_velocity;
393
394 RID platform_rid;
395 ObjectID platform_object_id;
396 bool on_floor = false;
397 bool on_ceiling = false;
398 bool on_wall = false;
399
400 Vector<PhysicsServer2D::MotionResult> motion_results;
401 Vector<Ref<KinematicCollision2D>> slide_colliders;
402
403 void set_safe_margin(real_t p_margin);
404 real_t get_safe_margin() const;
405
406 bool is_floor_stop_on_slope_enabled() const;
407 void set_floor_stop_on_slope_enabled(bool p_enabled);
408
409 bool is_floor_constant_speed_enabled() const;
410 void set_floor_constant_speed_enabled(bool p_enabled);
411
412 bool is_floor_block_on_wall_enabled() const;
413 void set_floor_block_on_wall_enabled(bool p_enabled);
414
415 bool is_slide_on_ceiling_enabled() const;
416 void set_slide_on_ceiling_enabled(bool p_enabled);
417
418 int get_max_slides() const;
419 void set_max_slides(int p_max_slides);
420
421 real_t get_floor_max_angle() const;
422 void set_floor_max_angle(real_t p_radians);
423
424 real_t get_floor_snap_length();
425 void set_floor_snap_length(real_t p_floor_snap_length);
426
427 real_t get_wall_min_slide_angle() const;
428 void set_wall_min_slide_angle(real_t p_radians);
429
430 uint32_t get_platform_floor_layers() const;
431 void set_platform_floor_layers(const uint32_t p_exclude_layer);
432
433 uint32_t get_platform_wall_layers() const;
434 void set_platform_wall_layers(const uint32_t p_exclude_layer);
435
436 void set_motion_mode(MotionMode p_mode);
437 MotionMode get_motion_mode() const;
438
439 void set_platform_on_leave(PlatformOnLeave p_on_leave_velocity);
440 PlatformOnLeave get_platform_on_leave() const;
441
442 void _move_and_slide_floating(double p_delta);
443 void _move_and_slide_grounded(double p_delta, bool p_was_on_floor);
444
445 Ref<KinematicCollision2D> _get_slide_collision(int p_bounce);
446 Ref<KinematicCollision2D> _get_last_slide_collision();
447 const Vector2 &get_up_direction() const;
448 bool _on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_facing_up);
449 void set_up_direction(const Vector2 &p_up_direction);
450 void _set_collision_direction(const PhysicsServer2D::MotionResult &p_result);
451 void _set_platform_data(const PhysicsServer2D::MotionResult &p_result);
452 void _apply_floor_snap(bool p_wall_as_floor = false);
453 void _snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up, bool p_wall_as_floor = false);
454
455protected:
456 void _notification(int p_what);
457 static void _bind_methods();
458 void _validate_property(PropertyInfo &p_property) const;
459};
460
461VARIANT_ENUM_CAST(CharacterBody2D::MotionMode);
462VARIANT_ENUM_CAST(CharacterBody2D::PlatformOnLeave);
463
464class KinematicCollision2D : public RefCounted {
465 GDCLASS(KinematicCollision2D, RefCounted);
466
467 PhysicsBody2D *owner = nullptr;
468 friend class PhysicsBody2D;
469 friend class CharacterBody2D;
470 PhysicsServer2D::MotionResult result;
471
472protected:
473 static void _bind_methods();
474
475public:
476 Vector2 get_position() const;
477 Vector2 get_normal() const;
478 Vector2 get_travel() const;
479 Vector2 get_remainder() const;
480 real_t get_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const;
481 real_t get_depth() const;
482 Object *get_local_shape() const;
483 Object *get_collider() const;
484 ObjectID get_collider_id() const;
485 RID get_collider_rid() const;
486 Object *get_collider_shape() const;
487 int get_collider_shape_index() const;
488 Vector2 get_collider_velocity() const;
489};
490
491#endif // PHYSICS_BODY_2D_H
492