From c6c72a3c37a44964ec8e6b3353f78635bf588eab Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sun, 22 Mar 2015 01:46:18 -0300 Subject: [PATCH] input events on Area2D is now supported also added a demo showing how this works --- demos/2d/area_input/box_area.png | Bin 0 -> 1246 bytes demos/2d/area_input/circle_area.png | Bin 0 -> 3030 bytes demos/2d/area_input/engine.cfg | 4 + demos/2d/area_input/input.gd | 20 +++++ demos/2d/area_input/input.scn | Bin 0 -> 2886 bytes scene/2d/canvas_item.cpp | 62 +++++++++++++++ scene/2d/canvas_item.h | 1 + scene/2d/collision_object_2d.cpp | 71 ++++++++++++++++++ scene/2d/collision_object_2d.h | 12 +++ scene/2d/physics_body_2d.cpp | 1 + scene/main/viewport.cpp | 65 ++++++++++++++-- scene/main/viewport.h | 1 + scene/resources/font.cpp | 4 + servers/physics/space_sw.cpp | 2 +- servers/physics_2d/collision_object_2d_sw.cpp | 1 + servers/physics_2d/collision_object_2d_sw.h | 4 + servers/physics_2d/physics_2d_server_sw.cpp | 15 ++++ servers/physics_2d/physics_2d_server_sw.h | 5 ++ servers/physics_2d/shape_2d_sw.cpp | 63 ++++++++++++++++ servers/physics_2d/shape_2d_sw.h | 10 +++ servers/physics_2d/space_2d_sw.cpp | 51 +++++++++++++ servers/physics_2d/space_2d_sw.h | 1 + servers/physics_2d_server.h | 5 ++ 23 files changed, 392 insertions(+), 6 deletions(-) create mode 100644 demos/2d/area_input/box_area.png create mode 100644 demos/2d/area_input/circle_area.png create mode 100644 demos/2d/area_input/engine.cfg create mode 100644 demos/2d/area_input/input.gd create mode 100644 demos/2d/area_input/input.scn diff --git a/demos/2d/area_input/box_area.png b/demos/2d/area_input/box_area.png new file mode 100644 index 0000000000000000000000000000000000000000..ba7c37f7de23cca5c6c2fb8ca42b9452403623f6 GIT binary patch literal 1246 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 literal 0 HcmV?d00001 diff --git a/demos/2d/area_input/engine.cfg b/demos/2d/area_input/engine.cfg new file mode 100644 index 00000000000..3227e9278fe --- /dev/null +++ b/demos/2d/area_input/engine.cfg @@ -0,0 +1,4 @@ +[application] + +name="Area 2D Input Events" +main_scene="res://input.scn" diff --git a/demos/2d/area_input/input.gd b/demos/2d/area_input/input.gd new file mode 100644 index 00000000000..acecd095ed3 --- /dev/null +++ b/demos/2d/area_input/input.gd @@ -0,0 +1,20 @@ + +extends Area2D + +# member variables here, example: +# var a=2 +# var b="textvar" + +#virtual from CollisionObject2D (also available as signal) +func _input_event(viewport, event, shape_idx): + #convert event to local coordinates + if (event.type==InputEvent.MOUSE_MOTION): + event = make_input_local( event ) + get_node("label").set_text(str(event.pos)) + +#virtual from CollisionObject2D (also available as signal) +func _mouse_exit(): + get_node("label").set_text("") + + + diff --git a/demos/2d/area_input/input.scn b/demos/2d/area_input/input.scn new file mode 100644 index 0000000000000000000000000000000000000000..0bb3a18834ac8bdc64e1e3e47cf1d80d5afb5687 GIT binary patch literal 2886 zcmYioYj6~0vS((K&F+%jJV+K;Am6?qys|)0lxNS(CV;VoN_>{5Gqbys-7&K>>&$FI z5+6e%;DgsmS(I4no?cm=-XBG;&R4O3mQ^Bp7XG=@I|l*phn`e`Hi0KIb)bu&dy8 zFWAAZ2Cvoutt8VrsOBBTDC+7^NvWu-v%r$s$bpae5$gAGG#dhPd=^CcH7~M?X@L4h z#ud)_Pvf|+k*04R;rL~^3?ux0)`kS>fUShX4lbwIs+?eNF$;JEnn^SyY2}J(IZ{P& zO3J+8sAg+9P1l_9j2r}g*D5*Wc5-G#$&-Z)%psdRw$o>;`mj`w@sE3KETC(}k|UKB zdqnw9$gvc|9yYCVreaQoJ*L%XnGUp&yC?~E{1B+h2H!+x0zxDfn8;YFt~lDLI@QxC zl~qTPBsm%XTs{wc{AzqsSe;wmkf~_-5d}Zt5p4dbPs*EBW9l|J!r7UX8M#Smk^|W0 z!DGtbXCl*zMb(o3!WAuLG~UKZ6;mTSP_DPKqiR0)U@aoYg1Tm?iX|14az&X=EN7~E zy#>GWmrX-+OiN3=g#)#){I0NUdQChk3i5Y8yJBh1t}kH74T>f>FGj_|9lkHfllP^hD;vFyx7V)yijAiw7{25J1X*o;)Bl=YvWcCz`sR zTFaQm`}N#I@q$Q%`*$Cbr*Ph)PFz8IMId`T`>b%8%bSMr;#0uI*U`f=4~*0?kDb@| z3eLkn(eNxy>Aw>el9iCAhvZNl`gUS&_XCW(8SlUdVjbLAy?ut|a4|yP?HEFx{{$pO zYA`LSqE{0iu#)X08^BII;Bnpf!%N4o6Q^-AUg7dp%ZhK6hp6Z1UeP^;&to+E?w(f) zC;Kl^r30zI;awP}XLp0YqU}_5$u{E0v4TLO`YLrWZZC8C&@46Q6p46*vcl z!k>2~8N$f+^eEKtfcF`5x zg8#&>#iFld7EL4hqsJ}8KlY#JJ3S7(yXsV-=KWIlKC1IyZf!obV9`Drd;am0@8E*u zv`?w(j+B2iceK7>OAn`%b6VmvcR~6dRyQp<${l@r?xs48E8T)4;$uyA$sCi4mR9h5 z+k`LWxr;8R+dN-Pd;})8exDC=XFmRTBM#g&UVoaitzvFw4LDyMB=hCh#FrUqr@WqB z*MGmf_omT{@Caj7)4N#Jah5FoU|M_#`|+vnboc6I7ofQ3zj(^GLMJJE(dj+=#mksI z2OFrZO&4c<>&siJYNWqKlKnBg8wdRWw~FBI6UBdVKm4v)z!z{20<@toE&zD+&xGnp zS45cEYa(6D`vUs;9vt9b&wl^XAWyz&?5wBzl{4Y3C*4KM+T$Fk`$PQC0How`T>mD| z59rc)%TKy~I3OP)k(!@*S-@Yh&WEs8TgkY`@l0da<)-XC#e+&K_e~*jl5WW5*nN&| zWn7Q}_qjlKdD7!P+;YbK@XMzXC5Dzq!G@BIEvPp#J7@H*C z3lPU7Ra+$rS^9^iCm4(D>&7ToR2@<*u|yqBb~M<_iDDG$Yr2nizv**`Q&K%&3U4ra zN!({z1DmLnq&89_ml*Vl>ZwqE& zob1E3BsHjH`7;1WG0OOVKNJvsRHi{3@*NYz?hS@bgbWrLrbW*$?594}z6-TIKF6FnwJSvY-iZ&hE3;-4o zAIzr_oTXmY(y@nWVC`qAv$J@~i=3ss?`Av>T{Cm}4{ zSVZ}sVKK#5p_}4gsj=QS4j>3A%b-@OTzkrRD-$Zqe!Dfov zS!zxR0Z(O%L7*~`j-I6f?xli08eo=o_mI$wV{~i_CizKPfid(8dojk3VC-D CanvasItem::get_material() const{ } +InputEvent CanvasItem::make_input_local(const InputEvent& p_event) const { + ERR_FAIL_COND_V(!is_inside_tree(),p_event); + + InputEvent ev = p_event; + + Matrix32 local_matrix = (get_canvas_transform() * get_global_transform()).affine_inverse(); + + switch(ev.type) { + + case InputEvent::MOUSE_BUTTON: { + + Vector2 g = local_matrix.xform(Vector2(ev.mouse_button.global_x,ev.mouse_button.global_y)); + Vector2 l = local_matrix.xform(Vector2(ev.mouse_button.x,ev.mouse_button.y)); + ev.mouse_button.x=l.x; + ev.mouse_button.y=l.y; + ev.mouse_button.global_x=g.x; + ev.mouse_button.global_y=g.y; + + } break; + case InputEvent::MOUSE_MOTION: { + + Vector2 g = local_matrix.xform(Vector2(ev.mouse_motion.global_x,ev.mouse_motion.global_y)); + Vector2 l = local_matrix.xform(Vector2(ev.mouse_motion.x,ev.mouse_motion.y)); + Vector2 r = local_matrix.basis_xform(Vector2(ev.mouse_motion.relative_x,ev.mouse_motion.relative_y)); + Vector2 s = local_matrix.basis_xform(Vector2(ev.mouse_motion.speed_x,ev.mouse_motion.speed_y)); + ev.mouse_motion.x=l.x; + ev.mouse_motion.y=l.y; + ev.mouse_motion.global_x=g.x; + ev.mouse_motion.global_y=g.y; + ev.mouse_motion.relative_x=r.x; + ev.mouse_motion.relative_y=r.y; + ev.mouse_motion.speed_x=s.x; + ev.mouse_motion.speed_y=s.y; + + } break; + case InputEvent::SCREEN_TOUCH: { + + + Vector2 t = local_matrix.xform(Vector2(ev.screen_touch.x,ev.screen_touch.y)); + ev.screen_touch.x=t.x; + ev.screen_touch.y=t.y; + + } break; + case InputEvent::SCREEN_DRAG: { + + + Vector2 t = local_matrix.xform(Vector2(ev.screen_drag.x,ev.screen_drag.y)); + Vector2 r = local_matrix.basis_xform(Vector2(ev.screen_drag.relative_x,ev.screen_drag.relative_y)); + Vector2 s = local_matrix.basis_xform(Vector2(ev.screen_drag.speed_x,ev.screen_drag.speed_y)); + ev.screen_drag.x=t.x; + ev.screen_drag.y=t.y; + ev.screen_drag.relative_x=r.x; + ev.screen_drag.relative_y=r.y; + ev.screen_drag.speed_x=s.x; + ev.screen_drag.speed_y=s.y; + } break; + } + + return ev; +} void CanvasItem::_bind_methods() { @@ -1021,6 +1081,8 @@ void CanvasItem::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_use_parent_material","enable"),&CanvasItem::set_use_parent_material); ObjectTypeDB::bind_method(_MD("get_use_parent_material"),&CanvasItem::get_use_parent_material); + ObjectTypeDB::bind_method(_MD("make_input_local","event"),&CanvasItem::make_input_local); + BIND_VMETHOD(MethodInfo("_draw")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"),_SCS("_is_visible_") ); diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index 0c7be261ab1..c43642a8ecf 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -249,6 +249,7 @@ public: void set_use_parent_material(bool p_use_parent_material); bool get_use_parent_material() const; + InputEvent make_input_local(const InputEvent& pevent) const; CanvasItem(); ~CanvasItem(); diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index 3b859d9366c..a883fee103b 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -28,6 +28,7 @@ /*************************************************************************/ #include "collision_object_2d.h" #include "servers/physics_2d_server.h" +#include "scene/scene_string_names.h" void CollisionObject2D::_update_shapes_from_children() { @@ -58,9 +59,15 @@ void CollisionObject2D::_notification(int p_what) { } else Physics2DServer::get_singleton()->body_set_space(rid,space); + _update_pickable(); + //get space } + case NOTIFICATION_VISIBILITY_CHANGED: { + + _update_pickable(); + } break; case NOTIFICATION_TRANSFORM_CHANGED: { if (area) @@ -166,6 +173,57 @@ void CollisionObject2D::_get_property_list( List *p_list) const { } } + +void CollisionObject2D::set_pickable(bool p_enabled) { + + if (pickable==p_enabled) + return; + + pickable=p_enabled; + _update_pickable(); +} + +bool CollisionObject2D::is_pickable() const { + + return pickable; +} + +void CollisionObject2D::_input_event(Node *p_viewport, const InputEvent& p_input_event, int p_shape) { + + if (get_script_instance()) { + get_script_instance()->call(SceneStringNames::get_singleton()->_input_event,p_viewport,p_input_event,p_shape); + } + emit_signal(SceneStringNames::get_singleton()->input_event,p_viewport,p_input_event,p_shape); +} + +void CollisionObject2D::_mouse_enter() { + + if (get_script_instance()) { + get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_enter); + } + emit_signal(SceneStringNames::get_singleton()->mouse_enter); +} + + +void CollisionObject2D::_mouse_exit() { + + if (get_script_instance()) { + get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_exit); + } + emit_signal(SceneStringNames::get_singleton()->mouse_exit); + +} + +void CollisionObject2D::_update_pickable() { + if (!is_inside_tree()) + return; + bool pickable = this->pickable && is_inside_tree() && is_visible(); + if (area) + Physics2DServer::get_singleton()->area_set_pickable(rid,pickable); + else + Physics2DServer::get_singleton()->body_set_pickable(rid,pickable); +} + void CollisionObject2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("add_shape","shape:Shape2D","transform"),&CollisionObject2D::add_shape,DEFVAL(Matrix32())); @@ -180,6 +238,17 @@ void CollisionObject2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("clear_shapes"),&CollisionObject2D::clear_shapes); ObjectTypeDB::bind_method(_MD("get_rid"),&CollisionObject2D::get_rid); + ObjectTypeDB::bind_method(_MD("set_pickable","enabled"),&CollisionObject2D::set_pickable); + ObjectTypeDB::bind_method(_MD("is_pickable"),&CollisionObject2D::is_pickable); + + BIND_VMETHOD( MethodInfo("_input_event",PropertyInfo(Variant::OBJECT,"viewport"),PropertyInfo(Variant::INPUT_EVENT,"event"),PropertyInfo(Variant::INT,"shape_idx"))); + + ADD_SIGNAL( MethodInfo("input_event",PropertyInfo(Variant::OBJECT,"viewport"),PropertyInfo(Variant::INPUT_EVENT,"event"),PropertyInfo(Variant::INT,"shape_idx"))); + ADD_SIGNAL( MethodInfo("mouse_enter")); + ADD_SIGNAL( MethodInfo("mouse_exit")); + + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"input/pickable"),_SCS("set_pickable"),_SCS("is_pickable")); + } @@ -262,7 +331,9 @@ CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) { rid=p_rid; area=p_area; + pickable=true; if (p_area) { + Physics2DServer::get_singleton()->area_attach_object_instance_ID(rid,get_instance_ID()); } else { Physics2DServer::get_singleton()->body_attach_object_instance_ID(rid,get_instance_ID()); diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index 4a529ce062f..393973ce90b 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -38,6 +38,7 @@ class CollisionObject2D : public Node2D { bool area; RID rid; + bool pickable; struct ShapeData { Matrix32 xform; @@ -66,9 +67,17 @@ protected: bool _get(const StringName& p_name,Variant &r_ret) const; void _get_property_list( List *p_list) const; static void _bind_methods(); + + void _update_pickable(); +friend class Viewport; + void _input_event(Node *p_viewport, const InputEvent& p_input_event, int p_shape); + void _mouse_enter(); + void _mouse_exit(); + public: + void add_shape(const Ref& p_shape, const Matrix32& p_transform=Matrix32()); int get_shape_count() const; void set_shape(int p_shape_idx, const Ref& p_shape); @@ -80,6 +89,9 @@ public: void remove_shape(int p_shape_idx); void clear_shapes(); + void set_pickable(bool p_enabled); + bool is_pickable() const; + _FORCE_INLINE_ RID get_rid() const { return rid; } CollisionObject2D(); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 6f183252124..22dd0f01d0d 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -98,6 +98,7 @@ PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode) : CollisionObject mask=1; set_one_way_collision_max_depth(0); + set_pickable(false); } diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 02e009866ff..18b8b46d903 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -30,7 +30,7 @@ #include "os/os.h" #include "scene/3d/spatial.h" #include "os/input.h" - +#include "servers/physics_2d_server.h" //#include "scene/3d/camera.h" #include "servers/spatial_sound_server.h" @@ -40,7 +40,7 @@ #include "scene/3d/spatial_indexer.h" #include "scene/3d/collision_object.h" - +#include "scene/2d/collision_object_2d.h" int RenderTargetTexture::get_width() const { @@ -355,11 +355,12 @@ void Viewport::_notification(int p_what) { case NOTIFICATION_FIXED_PROCESS: { if (physics_object_picking) { -#ifndef _3D_DISABLED + Vector2 last_pos(1e20,1e20); CollisionObject *last_object; ObjectID last_id=0; PhysicsDirectSpaceState::RayResult result; + Physics2DDirectSpaceState *ss2d=Physics2DServer::get_singleton()->space_get_direct_state(find_world_2d()->get_space()); bool motion_tested=false; @@ -392,6 +393,60 @@ void Viewport::_notification(int p_what) { } + if (ss2d) { + //send to 2D + + + uint64_t frame = get_tree()->get_frame(); + + Vector2 point = get_canvas_transform().affine_inverse().xform(pos); + Physics2DDirectSpaceState::ShapeResult res[64]; + int rc = ss2d->intersect_point(point,res,64,Set(),0xFFFFFFFF,0xFFFFFFFF); + for(int i=0;icast_to(); + if (co) { + + Map::Element *E=physics_2d_mouseover.find(res[i].collider_id); + if (!E) { + E=physics_2d_mouseover.insert(res[i].collider_id,frame); + co->_mouse_enter(); + } else { + E->get()=frame; + } + + co->_input_event(this,ev,res[i].shape); + } + } + } + + List::Element*> to_erase; + + for (Map::Element*E=physics_2d_mouseover.front();E;E=E->next()) { + if (E->get()!=frame) { + Object *o=ObjectDB::get_instance(E->key()); + if (o) { + + CollisionObject2D *co=o->cast_to(); + if (co) { + co->_mouse_exit(); + } + } + to_erase.push_back(E); + } + } + + while(to_erase.size()) { + physics_2d_mouseover.erase(to_erase.front()->get()); + to_erase.pop_front(); + } + + } + + + +#ifndef _3D_DISABLED bool captured=false; if (physics_object_capture!=0) { @@ -499,9 +554,9 @@ void Viewport::_notification(int p_what) { _test_new_mouseover(new_collider); } - - } #endif + } + } } break; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index d2a22401bd4..14f4f682175 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -124,6 +124,7 @@ friend class RenderTargetTexture; ObjectID physics_object_over; Vector2 physics_last_mousepos; void _test_new_mouseover(ObjectID new_collider); + Map physics_2d_mouseover; void _update_rect(); diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 24d413ed60c..79316f0019e 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -523,6 +523,10 @@ void Font::_bind_methods() { ObjectTypeDB::bind_method(_MD("add_texture","texture:Texture"),&Font::add_texture); ObjectTypeDB::bind_method(_MD("add_char","character","texture","rect","align","advance"),&Font::add_char,DEFVAL(Point2()),DEFVAL(-1)); + + ObjectTypeDB::bind_method(_MD("get_texture_count"),&Font::get_texture_count); + ObjectTypeDB::bind_method(_MD("get_texture:Texture","idx"),&Font::get_texture); + ObjectTypeDB::bind_method(_MD("get_char_size","char","next"),&Font::get_char_size,DEFVAL(0)); ObjectTypeDB::bind_method(_MD("get_string_size","string"),&Font::get_string_size); diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp index 4e8b60b86bc..3fc34889f22 100644 --- a/servers/physics/space_sw.cpp +++ b/servers/physics/space_sw.cpp @@ -77,7 +77,7 @@ bool PhysicsDirectSpaceStateSW::intersect_ray(const Vector3& p_from, const Vecto if (!_match_object_type_query(space->intersection_query_results[i],p_layer_mask,p_object_type_mask)) continue; - if (!(static_cast(space->intersection_query_results[i])->is_ray_pickable())) + if (!(static_cast(space->intersection_query_results[i])->is_ray_pickable())) continue; if (p_exclude.has( space->intersection_query_results[i]->get_self())) diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp index d0443f8110b..eefc598b393 100644 --- a/servers/physics_2d/collision_object_2d_sw.cpp +++ b/servers/physics_2d/collision_object_2d_sw.cpp @@ -228,4 +228,5 @@ CollisionObject2DSW::CollisionObject2DSW(Type p_type) { instance_id=0; user_mask=0; layer_mask=1; + pickable=true; } diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h index 00ad3612451..0c912378765 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/collision_object_2d_sw.h @@ -47,6 +47,7 @@ private: Type type; RID self; ObjectID instance_id; + bool pickable; struct Shape { @@ -129,6 +130,9 @@ public: _FORCE_INLINE_ bool is_static() const { return _static; } + void set_pickable(bool p_pickable) { pickable=p_pickable; } + _FORCE_INLINE_ bool is_pickable() const { return pickable; } + virtual ~CollisionObject2DSW() {} }; diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index 0a02a9568a9..883acd02004 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -463,6 +463,14 @@ Matrix32 Physics2DServerSW::area_get_transform(RID p_area) const { return area->get_transform(); }; +void Physics2DServerSW::area_set_pickable(RID p_area,bool p_pickable) { + + Area2DSW *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + area->set_pickable(p_pickable); + +} + void Physics2DServerSW::area_set_monitorable(RID p_area,bool p_monitorable) { Area2DSW *area = area_owner.get(p_area); @@ -943,6 +951,13 @@ bool Physics2DServerSW::body_collide_shape(RID p_body, int p_body_shape, RID p_s } +void Physics2DServerSW::body_set_pickable(RID p_body,bool p_pickable) { + + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_pickable(p_pickable); + +} /* JOINT API */ diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h index eba5845e5b4..58fc4eeb333 100644 --- a/servers/physics_2d/physics_2d_server_sw.h +++ b/servers/physics_2d/physics_2d_server_sw.h @@ -138,6 +138,9 @@ public: virtual void area_set_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method); virtual void area_set_area_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method); + virtual void area_set_pickable(RID p_area,bool p_pickable); + + /* BODY API */ // create a body of a given type @@ -218,6 +221,8 @@ public: virtual void body_set_force_integration_callback(RID p_body,Object *p_receiver,const StringName& p_method,const Variant& p_udata=Variant()); virtual bool body_collide_shape(RID p_body, int p_body_shape,RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,Vector2 *r_results,int p_result_max,int &r_result_count); + virtual void body_set_pickable(RID p_body,bool p_pickable); + /* JOINT API */ virtual void joint_set_param(RID p_joint, JointParam p_param, real_t p_value); diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp index ed63870a122..9a4b52d5631 100644 --- a/servers/physics_2d/shape_2d_sw.cpp +++ b/servers/physics_2d/shape_2d_sw.cpp @@ -106,6 +106,11 @@ void LineShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_supports,int r_amount=0; } +bool LineShape2DSW::contains_point(const Vector2& p_point) const { + + return normal.dot(p_point) < d; +} + bool LineShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const { Vector2 segment= p_begin - p_end; @@ -175,6 +180,11 @@ void RayShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_supports,int } +bool RayShape2DSW::contains_point(const Vector2& p_point) const { + + return false; +} + bool RayShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const { return false; //rays can't be intersected @@ -223,6 +233,11 @@ void SegmentShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_supports, } +bool SegmentShape2DSW::contains_point(const Vector2& p_point) const { + + return false; +} + bool SegmentShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const { if (!Geometry::segment_intersects_segment_2d(p_begin,p_end,a,b,&r_point)) @@ -288,6 +303,13 @@ void CircleShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_supports,i } + +bool CircleShape2DSW::contains_point(const Vector2& p_point) const { + + return p_point.length_squared() < radius*radius; +} + + bool CircleShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const { @@ -375,6 +397,11 @@ void RectangleShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_support } +bool RectangleShape2DSW::contains_point(const Vector2& p_point) const { + + return Math::abs(p_point.x)0) + out=true; + else + in=true; + } + + return (in && !out) || (!in && out); +} + + bool ConvexPolygonShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const { Vector2 n = (p_end-p_begin).normalized(); @@ -734,6 +791,12 @@ void ConcavePolygonShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_su } +bool ConcavePolygonShape2DSW::contains_point(const Vector2& p_point) const { + + return false; //sorry +} + + bool ConcavePolygonShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const{ uint32_t* stack = (uint32_t*)alloca(sizeof(int)*bvh_depth); diff --git a/servers/physics_2d/shape_2d_sw.h b/servers/physics_2d/shape_2d_sw.h index 931491efd55..05ea5b21cd4 100644 --- a/servers/physics_2d/shape_2d_sw.h +++ b/servers/physics_2d/shape_2d_sw.h @@ -78,6 +78,8 @@ public: virtual bool is_concave() const { return false; } + virtual bool contains_point(const Vector2& p_point) const=0; + virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const=0; virtual void project_range_castv(const Vector2& p_cast, const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const=0; virtual Vector2 get_support(const Vector2& p_normal) const; @@ -171,6 +173,7 @@ public: virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal,p_transform,r_min,r_max); } virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const; + virtual bool contains_point(const Vector2& p_point) const; virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const; virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const; @@ -213,6 +216,7 @@ public: virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal,p_transform,r_min,r_max); } virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const; + virtual bool contains_point(const Vector2& p_point) const; virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const; virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const; @@ -260,6 +264,7 @@ public: virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal,p_transform,r_min,r_max); } virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const; + virtual bool contains_point(const Vector2& p_point) const; virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const; virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const; @@ -297,6 +302,7 @@ public: virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal,p_transform,r_min,r_max); } virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const; + virtual bool contains_point(const Vector2& p_point) const; virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const; virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const; @@ -336,6 +342,7 @@ public: virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal,p_transform,r_min,r_max); } virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const; + virtual bool contains_point(const Vector2& p_point) const; virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const; virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const; @@ -423,6 +430,7 @@ public: virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal,p_transform,r_min,r_max); } virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const; + virtual bool contains_point(const Vector2& p_point) const; virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const; virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const; @@ -485,6 +493,7 @@ public: virtual void project_rangev(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal,p_transform,r_min,r_max); } virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const; + virtual bool contains_point(const Vector2& p_point) const; virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const; virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const; @@ -572,6 +581,7 @@ public: virtual void project_range(const Vector2& p_normal, const Matrix32& p_transform, real_t &r_min, real_t &r_max) const { /*project_range(p_normal,p_transform,r_min,r_max);*/ } virtual void get_supports(const Vector2& p_normal,Vector2 *r_supports,int & r_amount) const; + virtual bool contains_point(const Vector2& p_point) const; virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const; virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const { return 0; } diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 9523e8bf8a8..5aaf9a76135 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -45,6 +45,57 @@ _FORCE_INLINE_ static bool _match_object_type_query(CollisionObject2DSW *p_objec } + +int Physics2DDirectSpaceStateSW::intersect_point(const Vector2& p_point,ShapeResult *r_results,int p_result_max,const Set& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask) { + + if (p_result_max<=0) + return 0; + + Rect2 aabb; + aabb.pos=p_point-Vector2(0.00001,0.00001); + aabb.size=Vector2(0.00002,0.00002); + + int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,Space2DSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results); + + int cc=0; + + for(int i=0;iintersection_query_results[i],p_layer_mask,p_object_type_mask)) + continue; + + if (p_exclude.has( space->intersection_query_results[i]->get_self())) + continue; + + const CollisionObject2DSW *col_obj=space->intersection_query_results[i]; + + if (!col_obj->is_pickable()) + continue; + + int shape_idx=space->intersection_query_subindex_results[i]; + + Shape2DSW * shape = col_obj->get_shape(shape_idx); + + Vector2 local_point = (col_obj->get_transform() * col_obj->get_shape_transform(shape_idx)).affine_inverse().xform(p_point); + + if (!shape->contains_point(local_point)) + continue; + + r_results[cc].collider_id=col_obj->get_instance_id(); + if (r_results[cc].collider_id!=0) + r_results[cc].collider=ObjectDB::get_instance(r_results[cc].collider_id); + r_results[cc].rid=col_obj->get_self(); + r_results[cc].shape=shape_idx; + r_results[cc].metadata=col_obj->get_shape_metadata(shape_idx); + + cc++; + } + + return cc; + + +} + bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2& p_from, const Vector2& p_to,RayResult &r_result,const Set& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask) { diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index 7977b190639..05b55fe807d 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -46,6 +46,7 @@ public: Space2DSW *space; + virtual int intersect_point(const Vector2& p_point,ShapeResult *r_results,int p_result_max,const Set& p_exclude=Set(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION); virtual bool intersect_ray(const Vector2& p_from, const Vector2& p_to,RayResult &r_result,const Set& p_exclude=Set(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION); virtual int intersect_shape(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,float p_margin,ShapeResult *r_results,int p_result_max,const Set& p_exclude=Set(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION); virtual bool cast_motion(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,float p_margin,float &p_closest_safe,float &p_closest_unsafe, const Set& p_exclude=Set(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION); diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index 1fb47fc1d92..657e5ce4419 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -181,6 +181,8 @@ public: }; + virtual int intersect_point(const Vector2& p_point,ShapeResult *r_results,int p_result_max,const Set& p_exclude=Set(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION)=0; + virtual int intersect_shape(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,float p_margin,ShapeResult *r_results,int p_result_max,const Set& p_exclude=Set(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION)=0; virtual bool cast_motion(const RID& p_shape, const Matrix32& p_xform,const Vector2& p_motion,float p_margin,float &p_closest_safe,float &p_closest_unsafe, const Set& p_exclude=Set(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION)=0; @@ -342,6 +344,7 @@ public: virtual Matrix32 area_get_transform(RID p_area) const=0; virtual void area_set_monitorable(RID p_area,bool p_monitorable)=0; + virtual void area_set_pickable(RID p_area,bool p_pickable)=0; virtual void area_set_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method)=0; virtual void area_set_area_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method)=0; @@ -462,6 +465,8 @@ public: virtual bool body_collide_shape(RID p_body, int p_body_shape,RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,Vector2 *r_results,int p_result_max,int &r_result_count)=0; + virtual void body_set_pickable(RID p_body,bool p_pickable)=0; + /* JOINT API */ enum JointType {