1 /*************************************************************************/
2 /*  joints_2d.cpp                                                        */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
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 #include "joints_2d.h"
31 #include "physics_body_2d.h"
32 #include "servers/physics_2d_server.h"
33 
_update_joint(bool p_only_free)34 void Joint2D::_update_joint(bool p_only_free) {
35 
36 	if (joint.is_valid()) {
37 		if (ba.is_valid() && bb.is_valid())
38 			Physics2DServer::get_singleton()->body_remove_collision_exception(ba, bb);
39 
40 		Physics2DServer::get_singleton()->free(joint);
41 		joint = RID();
42 		ba = RID();
43 		bb = RID();
44 	}
45 
46 	if (p_only_free || !is_inside_tree())
47 		return;
48 
49 	Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL;
50 	Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL;
51 
52 	if (!node_a && !node_b)
53 		return;
54 
55 	PhysicsBody2D *body_a = node_a ? node_a->cast_to<PhysicsBody2D>() : (PhysicsBody2D *)NULL;
56 	PhysicsBody2D *body_b = node_b ? node_b->cast_to<PhysicsBody2D>() : (PhysicsBody2D *)NULL;
57 
58 	if (!body_a && !body_b)
59 		return;
60 
61 	if (!body_a) {
62 		SWAP(body_a, body_b);
63 	}
64 
65 	joint = _configure_joint(body_a, body_b);
66 
67 	if (!joint.is_valid())
68 		return;
69 
70 	Physics2DServer::get_singleton()->get_singleton()->joint_set_param(joint, Physics2DServer::JOINT_PARAM_BIAS, bias);
71 
72 	ba = body_a->get_rid();
73 	bb = body_b ? body_b->get_rid() : RID();
74 
75 	if (exclude_from_collision && bb.is_valid())
76 		Physics2DServer::get_singleton()->body_add_collision_exception(ba, bb);
77 }
78 
set_node_a(const NodePath & p_node_a)79 void Joint2D::set_node_a(const NodePath &p_node_a) {
80 
81 	if (a == p_node_a)
82 		return;
83 
84 	a = p_node_a;
85 	_update_joint();
86 }
87 
get_node_a() const88 NodePath Joint2D::get_node_a() const {
89 
90 	return a;
91 }
92 
set_node_b(const NodePath & p_node_b)93 void Joint2D::set_node_b(const NodePath &p_node_b) {
94 
95 	if (b == p_node_b)
96 		return;
97 	b = p_node_b;
98 	_update_joint();
99 }
get_node_b() const100 NodePath Joint2D::get_node_b() const {
101 
102 	return b;
103 }
104 
_notification(int p_what)105 void Joint2D::_notification(int p_what) {
106 
107 	switch (p_what) {
108 
109 		case NOTIFICATION_READY: {
110 			_update_joint();
111 		} break;
112 		case NOTIFICATION_EXIT_TREE: {
113 			if (joint.is_valid()) {
114 				_update_joint(true);
115 			}
116 		} break;
117 	}
118 }
119 
set_bias(real_t p_bias)120 void Joint2D::set_bias(real_t p_bias) {
121 
122 	bias = p_bias;
123 	if (joint.is_valid())
124 		Physics2DServer::get_singleton()->get_singleton()->joint_set_param(joint, Physics2DServer::JOINT_PARAM_BIAS, bias);
125 }
126 
get_bias() const127 real_t Joint2D::get_bias() const {
128 
129 	return bias;
130 }
131 
set_exclude_nodes_from_collision(bool p_enable)132 void Joint2D::set_exclude_nodes_from_collision(bool p_enable) {
133 
134 	if (exclude_from_collision == p_enable)
135 		return;
136 	exclude_from_collision = p_enable;
137 	_update_joint();
138 }
139 
get_exclude_nodes_from_collision() const140 bool Joint2D::get_exclude_nodes_from_collision() const {
141 
142 	return exclude_from_collision;
143 }
144 
_bind_methods()145 void Joint2D::_bind_methods() {
146 
147 	ObjectTypeDB::bind_method(_MD("set_node_a", "node"), &Joint2D::set_node_a);
148 	ObjectTypeDB::bind_method(_MD("get_node_a"), &Joint2D::get_node_a);
149 
150 	ObjectTypeDB::bind_method(_MD("set_node_b", "node"), &Joint2D::set_node_b);
151 	ObjectTypeDB::bind_method(_MD("get_node_b"), &Joint2D::get_node_b);
152 
153 	ObjectTypeDB::bind_method(_MD("set_bias", "bias"), &Joint2D::set_bias);
154 	ObjectTypeDB::bind_method(_MD("get_bias"), &Joint2D::get_bias);
155 
156 	ObjectTypeDB::bind_method(_MD("set_exclude_nodes_from_collision", "enable"), &Joint2D::set_exclude_nodes_from_collision);
157 	ObjectTypeDB::bind_method(_MD("get_exclude_nodes_from_collision"), &Joint2D::get_exclude_nodes_from_collision);
158 
159 	ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_a"), _SCS("set_node_a"), _SCS("get_node_a"));
160 	ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_b"), _SCS("set_node_b"), _SCS("get_node_b"));
161 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "bias/bias", PROPERTY_HINT_RANGE, "0,0.9,0.001"), _SCS("set_bias"), _SCS("get_bias"));
162 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision/exclude_nodes"), _SCS("set_exclude_nodes_from_collision"), _SCS("get_exclude_nodes_from_collision"));
163 }
164 
Joint2D()165 Joint2D::Joint2D() {
166 
167 	bias = 0;
168 	exclude_from_collision = true;
169 }
170 
171 ///////////////////////////////////////////////////////////////////////////////
172 ///////////////////////////////////////////////////////////////////////////////
173 ///////////////////////////////////////////////////////////////////////////////
174 
_notification(int p_what)175 void PinJoint2D::_notification(int p_what) {
176 
177 	switch (p_what) {
178 		case NOTIFICATION_DRAW: {
179 
180 			if (!is_inside_tree())
181 				break;
182 
183 			if (!get_tree()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) {
184 				break;
185 			}
186 
187 			draw_line(Point2(-10, 0), Point2(+10, 0), Color(0.7, 0.6, 0.0, 0.5), 3);
188 			draw_line(Point2(0, -10), Point2(0, +10), Color(0.7, 0.6, 0.0, 0.5), 3);
189 		} break;
190 	}
191 }
192 
_configure_joint(PhysicsBody2D * body_a,PhysicsBody2D * body_b)193 RID PinJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) {
194 
195 	RID pj = Physics2DServer::get_singleton()->pin_joint_create(get_global_transform().get_origin(), body_a->get_rid(), body_b ? body_b->get_rid() : RID());
196 	Physics2DServer::get_singleton()->pin_joint_set_param(pj, Physics2DServer::PIN_JOINT_SOFTNESS, softness);
197 	return pj;
198 }
199 
set_softness(real_t p_softness)200 void PinJoint2D::set_softness(real_t p_softness) {
201 
202 	softness = p_softness;
203 	update();
204 	if (get_joint().is_valid())
205 		Physics2DServer::get_singleton()->pin_joint_set_param(get_joint(), Physics2DServer::PIN_JOINT_SOFTNESS, p_softness);
206 }
207 
get_softness() const208 real_t PinJoint2D::get_softness() const {
209 
210 	return softness;
211 }
212 
_bind_methods()213 void PinJoint2D::_bind_methods() {
214 
215 	ObjectTypeDB::bind_method(_MD("set_softness", "softness"), &PinJoint2D::set_softness);
216 	ObjectTypeDB::bind_method(_MD("get_softness"), &PinJoint2D::get_softness);
217 
218 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "softness", PROPERTY_HINT_EXP_RANGE, "0.00,16,0.01"), _SCS("set_softness"), _SCS("get_softness"));
219 }
220 
PinJoint2D()221 PinJoint2D::PinJoint2D() {
222 
223 	softness = 0;
224 }
225 
226 ///////////////////////////////////////////////////////////////////////////////
227 ///////////////////////////////////////////////////////////////////////////////
228 ///////////////////////////////////////////////////////////////////////////////
229 
_notification(int p_what)230 void GrooveJoint2D::_notification(int p_what) {
231 
232 	switch (p_what) {
233 		case NOTIFICATION_DRAW: {
234 			if (!is_inside_tree())
235 				break;
236 
237 			if (!get_tree()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) {
238 				break;
239 			}
240 
241 			draw_line(Point2(-10, 0), Point2(+10, 0), Color(0.7, 0.6, 0.0, 0.5), 3);
242 			draw_line(Point2(-10, length), Point2(+10, length), Color(0.7, 0.6, 0.0, 0.5), 3);
243 			draw_line(Point2(0, 0), Point2(0, length), Color(0.7, 0.6, 0.0, 0.5), 3);
244 			draw_line(Point2(-10, initial_offset), Point2(+10, initial_offset), Color(0.8, 0.8, 0.9, 0.5), 5);
245 		} break;
246 	}
247 }
248 
_configure_joint(PhysicsBody2D * body_a,PhysicsBody2D * body_b)249 RID GrooveJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) {
250 
251 	Matrix32 gt = get_global_transform();
252 	Vector2 groove_A1 = gt.get_origin();
253 	Vector2 groove_A2 = gt.xform(Vector2(0, length));
254 	Vector2 anchor_B = gt.xform(Vector2(0, initial_offset));
255 
256 	return Physics2DServer::get_singleton()->groove_joint_create(groove_A1, groove_A2, anchor_B, body_a->get_rid(), body_b->get_rid());
257 }
258 
set_length(real_t p_length)259 void GrooveJoint2D::set_length(real_t p_length) {
260 
261 	length = p_length;
262 	update();
263 }
264 
get_length() const265 real_t GrooveJoint2D::get_length() const {
266 
267 	return length;
268 }
269 
set_initial_offset(real_t p_initial_offset)270 void GrooveJoint2D::set_initial_offset(real_t p_initial_offset) {
271 
272 	initial_offset = p_initial_offset;
273 	update();
274 }
275 
get_initial_offset() const276 real_t GrooveJoint2D::get_initial_offset() const {
277 
278 	return initial_offset;
279 }
280 
_bind_methods()281 void GrooveJoint2D::_bind_methods() {
282 
283 	ObjectTypeDB::bind_method(_MD("set_length", "length"), &GrooveJoint2D::set_length);
284 	ObjectTypeDB::bind_method(_MD("get_length"), &GrooveJoint2D::get_length);
285 	ObjectTypeDB::bind_method(_MD("set_initial_offset", "offset"), &GrooveJoint2D::set_initial_offset);
286 	ObjectTypeDB::bind_method(_MD("get_initial_offset"), &GrooveJoint2D::get_initial_offset);
287 
288 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "length", PROPERTY_HINT_EXP_RANGE, "1,65535,1"), _SCS("set_length"), _SCS("get_length"));
289 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "initial_offset", PROPERTY_HINT_EXP_RANGE, "1,65535,1"), _SCS("set_initial_offset"), _SCS("get_initial_offset"));
290 }
291 
GrooveJoint2D()292 GrooveJoint2D::GrooveJoint2D() {
293 
294 	length = 50;
295 	initial_offset = 25;
296 }
297 
298 ///////////////////////////////////////////////////////////////////////////////
299 ///////////////////////////////////////////////////////////////////////////////
300 ///////////////////////////////////////////////////////////////////////////////
301 
_notification(int p_what)302 void DampedSpringJoint2D::_notification(int p_what) {
303 
304 	switch (p_what) {
305 		case NOTIFICATION_DRAW: {
306 
307 			if (!is_inside_tree())
308 				break;
309 
310 			if (!get_tree()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) {
311 				break;
312 			}
313 
314 			draw_line(Point2(-10, 0), Point2(+10, 0), Color(0.7, 0.6, 0.0, 0.5), 3);
315 			draw_line(Point2(-10, length), Point2(+10, length), Color(0.7, 0.6, 0.0, 0.5), 3);
316 			draw_line(Point2(0, 0), Point2(0, length), Color(0.7, 0.6, 0.0, 0.5), 3);
317 		} break;
318 	}
319 }
320 
_configure_joint(PhysicsBody2D * body_a,PhysicsBody2D * body_b)321 RID DampedSpringJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) {
322 
323 	Matrix32 gt = get_global_transform();
324 	Vector2 anchor_A = gt.get_origin();
325 	Vector2 anchor_B = gt.xform(Vector2(0, length));
326 
327 	RID dsj = Physics2DServer::get_singleton()->damped_spring_joint_create(anchor_A, anchor_B, body_a->get_rid(), body_b->get_rid());
328 	if (rest_length)
329 		Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj, Physics2DServer::DAMPED_STRING_REST_LENGTH, rest_length);
330 	Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj, Physics2DServer::DAMPED_STRING_STIFFNESS, stiffness);
331 	Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj, Physics2DServer::DAMPED_STRING_DAMPING, damping);
332 
333 	return dsj;
334 }
335 
set_length(real_t p_length)336 void DampedSpringJoint2D::set_length(real_t p_length) {
337 
338 	length = p_length;
339 	update();
340 }
341 
get_length() const342 real_t DampedSpringJoint2D::get_length() const {
343 
344 	return length;
345 }
346 
set_rest_length(real_t p_rest_length)347 void DampedSpringJoint2D::set_rest_length(real_t p_rest_length) {
348 
349 	rest_length = p_rest_length;
350 	update();
351 	if (get_joint().is_valid())
352 		Physics2DServer::get_singleton()->damped_string_joint_set_param(get_joint(), Physics2DServer::DAMPED_STRING_REST_LENGTH, p_rest_length ? p_rest_length : length);
353 }
354 
get_rest_length() const355 real_t DampedSpringJoint2D::get_rest_length() const {
356 
357 	return rest_length;
358 }
359 
set_stiffness(real_t p_stiffness)360 void DampedSpringJoint2D::set_stiffness(real_t p_stiffness) {
361 
362 	stiffness = p_stiffness;
363 	update();
364 	if (get_joint().is_valid())
365 		Physics2DServer::get_singleton()->damped_string_joint_set_param(get_joint(), Physics2DServer::DAMPED_STRING_STIFFNESS, p_stiffness);
366 }
367 
get_stiffness() const368 real_t DampedSpringJoint2D::get_stiffness() const {
369 
370 	return stiffness;
371 }
372 
set_damping(real_t p_damping)373 void DampedSpringJoint2D::set_damping(real_t p_damping) {
374 
375 	damping = p_damping;
376 	update();
377 	if (get_joint().is_valid())
378 		Physics2DServer::get_singleton()->damped_string_joint_set_param(get_joint(), Physics2DServer::DAMPED_STRING_DAMPING, p_damping);
379 }
380 
get_damping() const381 real_t DampedSpringJoint2D::get_damping() const {
382 
383 	return damping;
384 }
385 
_bind_methods()386 void DampedSpringJoint2D::_bind_methods() {
387 
388 	ObjectTypeDB::bind_method(_MD("set_length", "length"), &DampedSpringJoint2D::set_length);
389 	ObjectTypeDB::bind_method(_MD("get_length"), &DampedSpringJoint2D::get_length);
390 	ObjectTypeDB::bind_method(_MD("set_rest_length", "rest_length"), &DampedSpringJoint2D::set_rest_length);
391 	ObjectTypeDB::bind_method(_MD("get_rest_length"), &DampedSpringJoint2D::get_rest_length);
392 	ObjectTypeDB::bind_method(_MD("set_stiffness", "stiffness"), &DampedSpringJoint2D::set_stiffness);
393 	ObjectTypeDB::bind_method(_MD("get_stiffness"), &DampedSpringJoint2D::get_stiffness);
394 	ObjectTypeDB::bind_method(_MD("set_damping", "damping"), &DampedSpringJoint2D::set_damping);
395 	ObjectTypeDB::bind_method(_MD("get_damping"), &DampedSpringJoint2D::get_damping);
396 
397 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "length", PROPERTY_HINT_EXP_RANGE, "1,65535,1"), _SCS("set_length"), _SCS("get_length"));
398 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "rest_length", PROPERTY_HINT_EXP_RANGE, "0,65535,1"), _SCS("set_rest_length"), _SCS("get_rest_length"));
399 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "stiffness", PROPERTY_HINT_EXP_RANGE, "0.1,64,0.1"), _SCS("set_stiffness"), _SCS("get_stiffness"));
400 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_EXP_RANGE, "0.01,16,0.01"), _SCS("set_damping"), _SCS("get_damping"));
401 }
402 
DampedSpringJoint2D()403 DampedSpringJoint2D::DampedSpringJoint2D() {
404 
405 	length = 50;
406 	rest_length = 0;
407 	stiffness = 20;
408 	damping = 1;
409 }
410