joints_2d.cpp 16 KB

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