1/**************************************************************************/
2/* godot_collision_object_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 GODOT_COLLISION_OBJECT_2D_H
32#define GODOT_COLLISION_OBJECT_2D_H
33
34#include "godot_broad_phase_2d.h"
35#include "godot_shape_2d.h"
36
37#include "core/templates/self_list.h"
38#include "servers/physics_server_2d.h"
39
40class GodotSpace2D;
41
42class GodotCollisionObject2D : public GodotShapeOwner2D {
43public:
44 enum Type {
45 TYPE_AREA,
46 TYPE_BODY
47 };
48
49private:
50 Type type;
51 RID self;
52 ObjectID instance_id;
53 ObjectID canvas_instance_id;
54 bool pickable = true;
55
56 struct Shape {
57 Transform2D xform;
58 Transform2D xform_inv;
59 GodotBroadPhase2D::ID bpid = 0;
60 Rect2 aabb_cache; //for rayqueries
61 GodotShape2D *shape = nullptr;
62 bool disabled = false;
63 bool one_way_collision = false;
64 real_t one_way_collision_margin = 0.0;
65 };
66
67 Vector<Shape> shapes;
68 GodotSpace2D *space = nullptr;
69 Transform2D transform;
70 Transform2D inv_transform;
71 uint32_t collision_mask = 1;
72 uint32_t collision_layer = 1;
73 real_t collision_priority = 1.0;
74 bool _static = true;
75
76 SelfList<GodotCollisionObject2D> pending_shape_update_list;
77
78 void _update_shapes();
79
80protected:
81 void _update_shapes_with_motion(const Vector2 &p_motion);
82 void _unregister_shapes();
83
84 _FORCE_INLINE_ void _set_transform(const Transform2D &p_transform, bool p_update_shapes = true) {
85 transform = p_transform;
86 if (p_update_shapes) {
87 _update_shapes();
88 }
89 }
90 _FORCE_INLINE_ void _set_inv_transform(const Transform2D &p_transform) { inv_transform = p_transform; }
91 void _set_static(bool p_static);
92
93 virtual void _shapes_changed() = 0;
94 void _set_space(GodotSpace2D *p_space);
95
96 GodotCollisionObject2D(Type p_type);
97
98public:
99 _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
100 _FORCE_INLINE_ RID get_self() const { return self; }
101
102 _FORCE_INLINE_ void set_instance_id(const ObjectID &p_instance_id) { instance_id = p_instance_id; }
103 _FORCE_INLINE_ ObjectID get_instance_id() const { return instance_id; }
104
105 _FORCE_INLINE_ void set_canvas_instance_id(const ObjectID &p_canvas_instance_id) { canvas_instance_id = p_canvas_instance_id; }
106 _FORCE_INLINE_ ObjectID get_canvas_instance_id() const { return canvas_instance_id; }
107
108 void _shape_changed() override;
109
110 _FORCE_INLINE_ Type get_type() const { return type; }
111 void add_shape(GodotShape2D *p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false);
112 void set_shape(int p_index, GodotShape2D *p_shape);
113 void set_shape_transform(int p_index, const Transform2D &p_transform);
114
115 _FORCE_INLINE_ int get_shape_count() const { return shapes.size(); }
116 _FORCE_INLINE_ GodotShape2D *get_shape(int p_index) const {
117 CRASH_BAD_INDEX(p_index, shapes.size());
118 return shapes[p_index].shape;
119 }
120 _FORCE_INLINE_ const Transform2D &get_shape_transform(int p_index) const {
121 CRASH_BAD_INDEX(p_index, shapes.size());
122 return shapes[p_index].xform;
123 }
124 _FORCE_INLINE_ const Transform2D &get_shape_inv_transform(int p_index) const {
125 CRASH_BAD_INDEX(p_index, shapes.size());
126 return shapes[p_index].xform_inv;
127 }
128 _FORCE_INLINE_ const Rect2 &get_shape_aabb(int p_index) const {
129 CRASH_BAD_INDEX(p_index, shapes.size());
130 return shapes[p_index].aabb_cache;
131 }
132
133 _FORCE_INLINE_ const Transform2D &get_transform() const { return transform; }
134 _FORCE_INLINE_ const Transform2D &get_inv_transform() const { return inv_transform; }
135 _FORCE_INLINE_ GodotSpace2D *get_space() const { return space; }
136
137 void set_shape_disabled(int p_idx, bool p_disabled);
138 _FORCE_INLINE_ bool is_shape_disabled(int p_idx) const {
139 ERR_FAIL_INDEX_V(p_idx, shapes.size(), false);
140 return shapes[p_idx].disabled;
141 }
142
143 _FORCE_INLINE_ void set_shape_as_one_way_collision(int p_idx, bool p_one_way_collision, real_t p_margin) {
144 CRASH_BAD_INDEX(p_idx, shapes.size());
145 shapes.write[p_idx].one_way_collision = p_one_way_collision;
146 shapes.write[p_idx].one_way_collision_margin = p_margin;
147 }
148 _FORCE_INLINE_ bool is_shape_set_as_one_way_collision(int p_idx) const {
149 CRASH_BAD_INDEX(p_idx, shapes.size());
150 return shapes[p_idx].one_way_collision;
151 }
152
153 _FORCE_INLINE_ real_t get_shape_one_way_collision_margin(int p_idx) const {
154 CRASH_BAD_INDEX(p_idx, shapes.size());
155 return shapes[p_idx].one_way_collision_margin;
156 }
157
158 void set_collision_mask(uint32_t p_mask) {
159 collision_mask = p_mask;
160 _shape_changed();
161 }
162 _FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; }
163
164 void set_collision_layer(uint32_t p_layer) {
165 collision_layer = p_layer;
166 _shape_changed();
167 }
168 _FORCE_INLINE_ uint32_t get_collision_layer() const { return collision_layer; }
169
170 _FORCE_INLINE_ void set_collision_priority(real_t p_priority) {
171 ERR_FAIL_COND_MSG(p_priority <= 0, "Priority must be greater than 0.");
172 collision_priority = p_priority;
173 _shape_changed();
174 }
175 _FORCE_INLINE_ real_t get_collision_priority() const { return collision_priority; }
176
177 void remove_shape(GodotShape2D *p_shape) override;
178 void remove_shape(int p_index);
179
180 virtual void set_space(GodotSpace2D *p_space) = 0;
181
182 _FORCE_INLINE_ bool is_static() const { return _static; }
183
184 void set_pickable(bool p_pickable) { pickable = p_pickable; }
185 _FORCE_INLINE_ bool is_pickable() const { return pickable; }
186
187 _FORCE_INLINE_ bool collides_with(GodotCollisionObject2D *p_other) const {
188 return p_other->collision_layer & collision_mask;
189 }
190
191 _FORCE_INLINE_ bool interacts_with(const GodotCollisionObject2D *p_other) const {
192 return collision_layer & p_other->collision_mask || p_other->collision_layer & collision_mask;
193 }
194
195 virtual ~GodotCollisionObject2D() {}
196};
197
198#endif // GODOT_COLLISION_OBJECT_2D_H
199