Prechádzať zdrojové kódy

input events on Area2D is now supported

also added a demo showing how this works
Juan Linietsky 10 rokov pred
rodič
commit
c6c72a3c37

BIN
demos/2d/area_input/box_area.png


BIN
demos/2d/area_input/circle_area.png


+ 4 - 0
demos/2d/area_input/engine.cfg

@@ -0,0 +1,4 @@
+[application]
+
+name="Area 2D Input Events"
+main_scene="res://input.scn"

+ 20 - 0
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("")
+		
+
+

BIN
demos/2d/area_input/input.scn


+ 62 - 0
scene/2d/canvas_item.cpp

@@ -943,7 +943,67 @@ Ref<CanvasItemMaterial> 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_") );

+ 1 - 0
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();

+ 71 - 0
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<PropertyInfo> *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());

+ 12 - 0
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<PropertyInfo> *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<Shape2D>& p_shape, const Matrix32& p_transform=Matrix32());
 	int get_shape_count() const;
 	void set_shape(int p_shape_idx, const Ref<Shape2D>& 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();

+ 1 - 0
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);
 
 }
 

+ 60 - 5
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<RID>(),0xFFFFFFFF,0xFFFFFFFF);
+						for(int i=0;i<rc;i++) {
+
+							if (res[i].collider) {
+								CollisionObject2D *co=res[i].collider->cast_to<CollisionObject2D>();
+								if (co) {
+
+									Map<ObjectID,uint64_t>::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<Map<ObjectID,uint64_t>::Element*> to_erase;
+
+						for (Map<ObjectID,uint64_t>::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<CollisionObject2D>();
+									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;

+ 1 - 0
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<ObjectID,uint64_t> physics_2d_mouseover;
 
 	void _update_rect();
 

+ 4 - 0
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);
 

+ 1 - 1
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<AreaSW*>(space->intersection_query_results[i])->is_ray_pickable()))
+		if (!(static_cast<CollisionObjectSW*>(space->intersection_query_results[i])->is_ray_pickable()))
 			continue;
 
 		if (p_exclude.has( space->intersection_query_results[i]->get_self()))

+ 1 - 0
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;
 }

+ 4 - 0
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() {}
 
 };

+ 15 - 0
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 */
 

+ 5 - 0
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);

+ 63 - 0
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)<half_extents.x && Math::abs(p_point.y)<half_extents.y;
+}
+
 bool RectangleShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const {
 
 
@@ -439,6 +466,17 @@ void CapsuleShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_supports,
 	}
 }
 
+bool CapsuleShape2DSW::contains_point(const Vector2& p_point) const {
+
+	Vector2 p = p_point;
+	p.y=Math::abs(p.y);
+	p.y-=height*0.5;
+	if (p.y<0)
+		p.y=0;
+
+	return p.length_squared() < radius*radius;
+}
+
 bool CapsuleShape2DSW::intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const {
 
 
@@ -574,6 +612,25 @@ void ConvexPolygonShape2DSW::get_supports(const Vector2& p_normal,Vector2 *r_sup
 
 }
 
+
+bool ConvexPolygonShape2DSW::contains_point(const Vector2& p_point) const {
+
+	bool out=false;
+	bool in=false;
+
+	for(int i=0;i<point_count;i++) {
+
+		float d = points[i].normal.dot(p_point) - points[i].normal.dot(points[i].pos);
+		if (d>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);

+ 10 - 0
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; }

+ 51 - 0
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<RID>& 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;i<amount;i++) {
+
+		if (!_match_object_type_query(space->intersection_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<RID>& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask) {
 
 

+ 1 - 0
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<RID>& p_exclude=Set<RID>(),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<RID>& p_exclude=Set<RID>(),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<RID>& p_exclude=Set<RID>(),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<RID>& p_exclude=Set<RID>(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION);

+ 5 - 0
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<RID>& p_exclude=Set<RID>(),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<RID>& p_exclude=Set<RID>(),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<RID>& p_exclude=Set<RID>(),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 {