collision_object.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. /*************************************************************************/
  2. /* collision_object.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* http://www.godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
  9. /* */
  10. /* Permission is hereby granted, free of charge, to any person obtaining */
  11. /* a copy of this software and associated documentation files (the */
  12. /* "Software"), to deal in the Software without restriction, including */
  13. /* without limitation the rights to use, copy, modify, merge, publish, */
  14. /* distribute, sublicense, and/or sell copies of the Software, and to */
  15. /* permit persons to whom the Software is furnished to do so, subject to */
  16. /* the following conditions: */
  17. /* */
  18. /* The above copyright notice and this permission notice shall be */
  19. /* included in all copies or substantial portions of the Software. */
  20. /* */
  21. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  22. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  23. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  24. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  25. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  26. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  27. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  28. /*************************************************************************/
  29. #include "collision_object.h"
  30. #include "servers/physics_server.h"
  31. #include "scene/scene_string_names.h"
  32. void CollisionObject::_update_shapes_from_children() {
  33. shapes.clear();
  34. for(int i=0;i<get_child_count();i++) {
  35. Node* n = get_child(i);
  36. n->call("_add_to_collision_object",this);
  37. }
  38. _update_shapes();
  39. }
  40. void CollisionObject::_notification(int p_what) {
  41. switch(p_what) {
  42. case NOTIFICATION_ENTER_WORLD: {
  43. if (area)
  44. PhysicsServer::get_singleton()->area_set_transform(rid,get_global_transform());
  45. else
  46. PhysicsServer::get_singleton()->body_set_state(rid,PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform());
  47. RID space = get_world()->get_space();
  48. if (area) {
  49. PhysicsServer::get_singleton()->area_set_space(rid,space);
  50. } else
  51. PhysicsServer::get_singleton()->body_set_space(rid,space);
  52. _update_pickable();
  53. //get space
  54. };
  55. case NOTIFICATION_TRANSFORM_CHANGED: {
  56. if (area)
  57. PhysicsServer::get_singleton()->area_set_transform(rid,get_global_transform());
  58. else
  59. PhysicsServer::get_singleton()->body_set_state(rid,PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform());
  60. } break;
  61. case NOTIFICATION_VISIBILITY_CHANGED: {
  62. _update_pickable();
  63. } break;
  64. case NOTIFICATION_EXIT_WORLD: {
  65. if (area) {
  66. PhysicsServer::get_singleton()->area_set_space(rid,RID());
  67. } else
  68. PhysicsServer::get_singleton()->body_set_space(rid,RID());
  69. } break;
  70. }
  71. }
  72. void CollisionObject::_update_shapes() {
  73. if (!rid.is_valid())
  74. return;
  75. if (area)
  76. PhysicsServer::get_singleton()->area_clear_shapes(rid);
  77. else
  78. PhysicsServer::get_singleton()->body_clear_shapes(rid);
  79. for(int i=0;i<shapes.size();i++) {
  80. if (shapes[i].shape.is_null())
  81. continue;
  82. if (area)
  83. PhysicsServer::get_singleton()->area_add_shape(rid,shapes[i].shape->get_rid(),shapes[i].xform);
  84. else {
  85. PhysicsServer::get_singleton()->body_add_shape(rid,shapes[i].shape->get_rid(),shapes[i].xform);
  86. if (shapes[i].trigger)
  87. PhysicsServer::get_singleton()->body_set_shape_as_trigger(rid,i,shapes[i].trigger);
  88. }
  89. }
  90. }
  91. bool CollisionObject::_set(const StringName& p_name, const Variant& p_value) {
  92. String name=p_name;
  93. if (name=="shape_count") {
  94. shapes.resize(p_value);
  95. _update_shapes();
  96. _change_notify();
  97. } else if (name.begins_with("shapes/")) {
  98. int idx=name.get_slicec('/',1).to_int();
  99. String what=name.get_slicec('/',2);
  100. if (what=="shape")
  101. set_shape(idx,RefPtr(p_value));
  102. else if (what=="transform")
  103. set_shape_transform(idx,p_value);
  104. else if (what=="trigger")
  105. set_shape_as_trigger(idx,p_value);
  106. } else
  107. return false;
  108. return true;
  109. }
  110. bool CollisionObject::_get(const StringName& p_name,Variant &r_ret) const {
  111. String name=p_name;
  112. if (name=="shape_count") {
  113. r_ret= shapes.size();
  114. } else if (name.begins_with("shapes/")) {
  115. int idx=name.get_slicec('/',1).to_int();
  116. String what=name.get_slicec('/',2);
  117. if (what=="shape")
  118. r_ret= get_shape(idx);
  119. else if (what=="transform")
  120. r_ret= get_shape_transform(idx);
  121. else if (what=="trigger")
  122. r_ret= is_shape_set_as_trigger(idx);
  123. } else
  124. return false;
  125. return true;
  126. }
  127. void CollisionObject::_get_property_list( List<PropertyInfo> *p_list) const {
  128. p_list->push_back( PropertyInfo(Variant::INT,"shape_count",PROPERTY_HINT_RANGE,"0,256,1",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
  129. for(int i=0;i<shapes.size();i++) {
  130. String path="shapes/"+itos(i)+"/";
  131. p_list->push_back( PropertyInfo(Variant::OBJECT,path+"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
  132. p_list->push_back( PropertyInfo(Variant::TRANSFORM,path+"transform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
  133. p_list->push_back( PropertyInfo(Variant::BOOL,path+"trigger",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
  134. }
  135. }
  136. void CollisionObject::_input_event(Node *p_camera, const InputEvent& p_input_event, const Vector3& p_pos, const Vector3& p_normal, int p_shape) {
  137. if (get_script_instance()) {
  138. get_script_instance()->call(SceneStringNames::get_singleton()->_input_event,p_camera,p_input_event,p_pos,p_normal,p_shape);
  139. }
  140. emit_signal(SceneStringNames::get_singleton()->input_event,p_camera,p_input_event,p_pos,p_normal,p_shape);
  141. }
  142. void CollisionObject::_mouse_enter() {
  143. if (get_script_instance()) {
  144. get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_enter);
  145. }
  146. emit_signal(SceneStringNames::get_singleton()->mouse_entered);
  147. }
  148. void CollisionObject::_mouse_exit() {
  149. if (get_script_instance()) {
  150. get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_exit);
  151. }
  152. emit_signal(SceneStringNames::get_singleton()->mouse_exited);
  153. }
  154. void CollisionObject::_update_pickable() {
  155. if (!is_inside_tree())
  156. return;
  157. bool pickable = ray_pickable && is_inside_tree() && is_visible_in_tree();
  158. if (area)
  159. PhysicsServer::get_singleton()->area_set_ray_pickable(rid,pickable);
  160. else
  161. PhysicsServer::get_singleton()->body_set_ray_pickable(rid,pickable);
  162. }
  163. void CollisionObject::set_ray_pickable(bool p_ray_pickable) {
  164. ray_pickable=p_ray_pickable;
  165. _update_pickable();
  166. }
  167. bool CollisionObject::is_ray_pickable() const {
  168. return ray_pickable;
  169. }
  170. void CollisionObject::_bind_methods() {
  171. ClassDB::bind_method(_MD("add_shape","shape:Shape","transform"),&CollisionObject::add_shape,DEFVAL(Transform()));
  172. ClassDB::bind_method(_MD("get_shape_count"),&CollisionObject::get_shape_count);
  173. ClassDB::bind_method(_MD("set_shape","shape_idx","shape:Shape"),&CollisionObject::set_shape);
  174. ClassDB::bind_method(_MD("set_shape_transform","shape_idx","transform"),&CollisionObject::set_shape_transform);
  175. // ClassDB::bind_method(_MD("set_shape_transform","shape_idx","transform"),&CollisionObject::set_shape_transform);
  176. ClassDB::bind_method(_MD("set_shape_as_trigger","shape_idx","enable"),&CollisionObject::set_shape_as_trigger);
  177. ClassDB::bind_method(_MD("is_shape_set_as_trigger","shape_idx"),&CollisionObject::is_shape_set_as_trigger);
  178. ClassDB::bind_method(_MD("get_shape:Shape","shape_idx"),&CollisionObject::get_shape);
  179. ClassDB::bind_method(_MD("get_shape_transform","shape_idx"),&CollisionObject::get_shape_transform);
  180. ClassDB::bind_method(_MD("remove_shape","shape_idx"),&CollisionObject::remove_shape);
  181. ClassDB::bind_method(_MD("clear_shapes"),&CollisionObject::clear_shapes);
  182. ClassDB::bind_method(_MD("set_ray_pickable","ray_pickable"),&CollisionObject::set_ray_pickable);
  183. ClassDB::bind_method(_MD("is_ray_pickable"),&CollisionObject::is_ray_pickable);
  184. ClassDB::bind_method(_MD("set_capture_input_on_drag","enable"),&CollisionObject::set_capture_input_on_drag);
  185. ClassDB::bind_method(_MD("get_capture_input_on_drag"),&CollisionObject::get_capture_input_on_drag);
  186. ClassDB::bind_method(_MD("get_rid"),&CollisionObject::get_rid);
  187. BIND_VMETHOD( MethodInfo("_input_event",PropertyInfo(Variant::OBJECT,"camera"),PropertyInfo(Variant::INPUT_EVENT,"event"),PropertyInfo(Variant::VECTOR3,"click_pos"),PropertyInfo(Variant::VECTOR3,"click_normal"),PropertyInfo(Variant::INT,"shape_idx")));
  188. ADD_SIGNAL( MethodInfo("input_event",PropertyInfo(Variant::OBJECT,"camera"),PropertyInfo(Variant::INPUT_EVENT,"event"),PropertyInfo(Variant::VECTOR3,"click_pos"),PropertyInfo(Variant::VECTOR3,"click_normal"),PropertyInfo(Variant::INT,"shape_idx")));
  189. ADD_SIGNAL( MethodInfo("mouse_entered"));
  190. ADD_SIGNAL( MethodInfo("mouse_exited"));
  191. ADD_PROPERTY( PropertyInfo(Variant::BOOL,"input_ray_pickable"),"set_ray_pickable","is_ray_pickable");
  192. ADD_PROPERTY(PropertyInfo(Variant::BOOL,"input_capture_on_drag"),"set_capture_input_on_drag","get_capture_input_on_drag");
  193. }
  194. void CollisionObject::add_shape(const Ref<Shape>& p_shape, const Transform& p_transform) {
  195. ShapeData sdata;
  196. sdata.shape=p_shape;
  197. sdata.xform=p_transform;
  198. shapes.push_back(sdata);
  199. _update_shapes();
  200. }
  201. int CollisionObject::get_shape_count() const {
  202. return shapes.size();
  203. }
  204. void CollisionObject::set_shape(int p_shape_idx, const Ref<Shape>& p_shape) {
  205. ERR_FAIL_INDEX(p_shape_idx,shapes.size());
  206. shapes[p_shape_idx].shape=p_shape;
  207. _update_shapes();
  208. }
  209. void CollisionObject::set_shape_transform(int p_shape_idx, const Transform& p_transform) {
  210. ERR_FAIL_INDEX(p_shape_idx,shapes.size());
  211. shapes[p_shape_idx].xform=p_transform;
  212. _update_shapes();
  213. }
  214. Ref<Shape> CollisionObject::get_shape(int p_shape_idx) const {
  215. ERR_FAIL_INDEX_V(p_shape_idx,shapes.size(),Ref<Shape>());
  216. return shapes[p_shape_idx].shape;
  217. }
  218. Transform CollisionObject::get_shape_transform(int p_shape_idx) const {
  219. ERR_FAIL_INDEX_V(p_shape_idx,shapes.size(),Transform());
  220. return shapes[p_shape_idx].xform;
  221. }
  222. void CollisionObject::remove_shape(int p_shape_idx) {
  223. ERR_FAIL_INDEX(p_shape_idx,shapes.size());
  224. shapes.remove(p_shape_idx);
  225. _update_shapes();
  226. }
  227. void CollisionObject::clear_shapes() {
  228. shapes.clear();
  229. _update_shapes();
  230. }
  231. void CollisionObject::set_shape_as_trigger(int p_shape_idx, bool p_trigger) {
  232. ERR_FAIL_INDEX(p_shape_idx,shapes.size());
  233. shapes[p_shape_idx].trigger=p_trigger;
  234. if (!area && rid.is_valid()) {
  235. PhysicsServer::get_singleton()->body_set_shape_as_trigger(rid,p_shape_idx,p_trigger);
  236. }
  237. }
  238. bool CollisionObject::is_shape_set_as_trigger(int p_shape_idx) const {
  239. ERR_FAIL_INDEX_V(p_shape_idx,shapes.size(),false);
  240. return shapes[p_shape_idx].trigger;
  241. }
  242. CollisionObject::CollisionObject(RID p_rid, bool p_area) {
  243. rid=p_rid;
  244. area=p_area;
  245. capture_input_on_drag=false;
  246. ray_pickable=true;
  247. if (p_area) {
  248. PhysicsServer::get_singleton()->area_attach_object_instance_ID(rid,get_instance_ID());
  249. } else {
  250. PhysicsServer::get_singleton()->body_attach_object_instance_ID(rid,get_instance_ID());
  251. }
  252. //set_transform_notify(true);
  253. }
  254. void CollisionObject::set_capture_input_on_drag(bool p_capture) {
  255. capture_input_on_drag=p_capture;
  256. }
  257. bool CollisionObject::get_capture_input_on_drag() const {
  258. return capture_input_on_drag;
  259. }
  260. CollisionObject::CollisionObject() {
  261. capture_input_on_drag=false;
  262. ray_pickable=true;
  263. set_notify_transform(true);
  264. //owner=
  265. //set_transform_notify(true);
  266. }
  267. CollisionObject::~CollisionObject() {
  268. PhysicsServer::get_singleton()->free(rid);
  269. }