瀏覽代碼

Fix picking in CanvasLayer

New APIs in 2D physics allow intersection queries filtered by CanvasLayer object instance id. Viewport keep an inventory of its descendant CanvasLayers and takes advantage of all that to test picking with the mouse/touch position correctly transformed for each CanvasLayer.
Pedro J. Estébanez 7 年之前
父節點
當前提交
6d0f4a4ad7

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

@@ -861,6 +861,15 @@ RID CanvasItem::get_canvas() const {
 		return get_viewport()->find_world_2d()->get_canvas();
 		return get_viewport()->find_world_2d()->get_canvas();
 }
 }
 
 
+ObjectID CanvasItem::get_canvas_layer_instance_id() const {
+
+	if (canvas_layer) {
+		return canvas_layer->get_instance_id();
+	} else {
+		return 0;
+	}
+}
+
 CanvasItem *CanvasItem::get_toplevel() const {
 CanvasItem *CanvasItem::get_toplevel() const {
 
 
 	CanvasItem *ci = const_cast<CanvasItem *>(this);
 	CanvasItem *ci = const_cast<CanvasItem *>(this);

+ 1 - 0
scene/2d/canvas_item.h

@@ -326,6 +326,7 @@ public:
 	Rect2 get_viewport_rect() const;
 	Rect2 get_viewport_rect() const;
 	RID get_viewport_rid() const;
 	RID get_viewport_rid() const;
 	RID get_canvas() const;
 	RID get_canvas() const;
+	ObjectID get_canvas_layer_instance_id() const;
 	Ref<World2D> get_world_2d() const;
 	Ref<World2D> get_world_2d() const;
 
 
 	virtual void set_material(const Ref<Material> &p_material);
 	virtual void set_material(const Ref<Material> &p_material);

+ 16 - 0
scene/2d/collision_object_2d.cpp

@@ -58,6 +58,14 @@ void CollisionObject2D::_notification(int p_what) {
 			//get space
 			//get space
 		}
 		}
 
 
+		case NOTIFICATION_ENTER_CANVAS: {
+
+			if (area)
+				Physics2DServer::get_singleton()->area_attach_canvas_instance_id(rid, get_canvas_layer_instance_id());
+			else
+				Physics2DServer::get_singleton()->body_attach_canvas_instance_id(rid, get_canvas_layer_instance_id());
+		}
+
 		case NOTIFICATION_VISIBILITY_CHANGED: {
 		case NOTIFICATION_VISIBILITY_CHANGED: {
 
 
 			_update_pickable();
 			_update_pickable();
@@ -86,6 +94,14 @@ void CollisionObject2D::_notification(int p_what) {
 				Physics2DServer::get_singleton()->body_set_space(rid, RID());
 				Physics2DServer::get_singleton()->body_set_space(rid, RID());
 
 
 		} break;
 		} break;
+
+		case NOTIFICATION_EXIT_CANVAS: {
+
+			if (area)
+				Physics2DServer::get_singleton()->area_attach_canvas_instance_id(rid, 0);
+			else
+				Physics2DServer::get_singleton()->body_attach_canvas_instance_id(rid, 0);
+		}
 	}
 	}
 }
 }
 
 

+ 5 - 0
scene/main/canvas_layer.cpp

@@ -146,6 +146,8 @@ void CanvasLayer::_notification(int p_what) {
 				vp = Node::get_viewport();
 				vp = Node::get_viewport();
 			}
 			}
 			ERR_FAIL_COND(!vp);
 			ERR_FAIL_COND(!vp);
+
+			vp->_canvas_layer_add(this);
 			viewport = vp->get_viewport_rid();
 			viewport = vp->get_viewport_rid();
 
 
 			VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
 			VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
@@ -155,6 +157,7 @@ void CanvasLayer::_notification(int p_what) {
 		} break;
 		} break;
 		case NOTIFICATION_EXIT_TREE: {
 		case NOTIFICATION_EXIT_TREE: {
 
 
+			vp->_canvas_layer_remove(this);
 			VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
 			VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
 			viewport = RID();
 			viewport = RID();
 
 
@@ -179,6 +182,7 @@ RID CanvasLayer::get_viewport() const {
 void CanvasLayer::set_custom_viewport(Node *p_viewport) {
 void CanvasLayer::set_custom_viewport(Node *p_viewport) {
 	ERR_FAIL_NULL(p_viewport);
 	ERR_FAIL_NULL(p_viewport);
 	if (is_inside_tree()) {
 	if (is_inside_tree()) {
+		vp->_canvas_layer_remove(this);
 		VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
 		VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
 		viewport = RID();
 		viewport = RID();
 	}
 	}
@@ -198,6 +202,7 @@ void CanvasLayer::set_custom_viewport(Node *p_viewport) {
 		else
 		else
 			vp = Node::get_viewport();
 			vp = Node::get_viewport();
 
 
+		vp->_canvas_layer_add(this);
 		viewport = vp->get_viewport_rid();
 		viewport = vp->get_viewport_rid();
 
 
 		VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
 		VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas);

+ 43 - 16
scene/main/viewport.cpp

@@ -45,6 +45,7 @@
 #include "scene/gui/panel.h"
 #include "scene/gui/panel.h"
 #include "scene/gui/panel_container.h"
 #include "scene/gui/panel_container.h"
 #include "scene/gui/popup_menu.h"
 #include "scene/gui/popup_menu.h"
+#include "scene/main/canvas_layer.h"
 #include "scene/main/timer.h"
 #include "scene/main/timer.h"
 #include "scene/resources/mesh.h"
 #include "scene/resources/mesh.h"
 #include "scene/scene_string_names.h"
 #include "scene/scene_string_names.h"
@@ -443,24 +444,39 @@ void Viewport::_notification(int p_what) {
 
 
 						uint64_t frame = get_tree()->get_frame();
 						uint64_t frame = get_tree()->get_frame();
 
 
-						Vector2 point = get_canvas_transform().affine_inverse().xform(pos);
 						Physics2DDirectSpaceState::ShapeResult res[64];
 						Physics2DDirectSpaceState::ShapeResult res[64];
-						int rc = ss2d->intersect_point(point, res, 64, Set<RID>(), 0xFFFFFFFF, true, true, true);
-						for (int i = 0; i < rc; i++) {
-
-							if (res[i].collider_id && res[i].collider) {
-								CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider);
-								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;
-									}
+						for (Set<CanvasLayer *>::Element *E = canvas_layers.front(); E; E = E->next()) {
+							Transform2D canvas_transform;
+							ObjectID canvas_layer_id;
+							if (E->get()) {
+								// A descendant CanvasLayer
+								canvas_transform = E->get()->get_transform();
+								canvas_layer_id = E->get()->get_instance_id();
+							} else {
+								// This Viewport's builtin canvas
+								canvas_transform = get_canvas_transform();
+								canvas_layer_id = 0;
+							}
+
+							Vector2 point = canvas_transform.affine_inverse().xform(pos);
+
+							int rc = ss2d->intersect_point_on_canvas(point, canvas_layer_id, res, 64, Set<RID>(), 0xFFFFFFFF, true, true, true);
+							for (int i = 0; i < rc; i++) {
+
+								if (res[i].collider_id && res[i].collider) {
+									CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider);
+									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);
+										co->_input_event(this, ev, res[i].shape);
+									}
 								}
 								}
 							}
 							}
 						}
 						}
@@ -874,6 +890,16 @@ void Viewport::_camera_make_next_current(Camera *p_exclude) {
 }
 }
 #endif
 #endif
 
 
+void Viewport::_canvas_layer_add(CanvasLayer *p_canvas_layer) {
+
+	canvas_layers.insert(p_canvas_layer);
+}
+
+void Viewport::_canvas_layer_remove(CanvasLayer *p_canvas_layer) {
+
+	canvas_layers.erase(p_canvas_layer);
+}
+
 void Viewport::set_transparent_background(bool p_enable) {
 void Viewport::set_transparent_background(bool p_enable) {
 
 
 	transparent_bg = p_enable;
 	transparent_bg = p_enable;
@@ -2921,6 +2947,7 @@ Viewport::Viewport() {
 	parent = NULL;
 	parent = NULL;
 	listener = NULL;
 	listener = NULL;
 	camera = NULL;
 	camera = NULL;
+	canvas_layers.insert(NULL); // This eases picking code (interpreted as the canvas of the Viewport)
 	arvr = false;
 	arvr = false;
 	size_override = false;
 	size_override = false;
 	size_override_stretch = false;
 	size_override_stretch = false;

+ 6 - 0
scene/main/viewport.h

@@ -45,6 +45,7 @@ class Camera2D;
 class Listener;
 class Listener;
 class Control;
 class Control;
 class CanvasItem;
 class CanvasItem;
+class CanvasLayer;
 class Panel;
 class Panel;
 class Label;
 class Label;
 class Timer;
 class Timer;
@@ -163,6 +164,7 @@ private:
 
 
 	Camera *camera;
 	Camera *camera;
 	Set<Camera *> cameras;
 	Set<Camera *> cameras;
+	Set<CanvasLayer *> canvas_layers;
 
 
 	RID viewport;
 	RID viewport;
 	RID current_canvas;
 	RID current_canvas;
@@ -354,6 +356,10 @@ private:
 	void _camera_remove(Camera *p_camera);
 	void _camera_remove(Camera *p_camera);
 	void _camera_make_next_current(Camera *p_exclude);
 	void _camera_make_next_current(Camera *p_exclude);
 
 
+	friend class CanvasLayer;
+	void _canvas_layer_add(CanvasLayer *p_canvas_layer);
+	void _canvas_layer_remove(CanvasLayer *p_canvas_layer);
+
 protected:
 protected:
 	void _notification(int p_what);
 	void _notification(int p_what);
 	static void _bind_methods();
 	static void _bind_methods();

+ 1 - 0
servers/physics_2d/collision_object_2d_sw.cpp

@@ -244,6 +244,7 @@ CollisionObject2DSW::CollisionObject2DSW(Type p_type) {
 	type = p_type;
 	type = p_type;
 	space = NULL;
 	space = NULL;
 	instance_id = 0;
 	instance_id = 0;
+	canvas_instance_id = 0;
 	collision_mask = 1;
 	collision_mask = 1;
 	collision_layer = 1;
 	collision_layer = 1;
 	pickable = true;
 	pickable = true;

+ 4 - 0
servers/physics_2d/collision_object_2d_sw.h

@@ -49,6 +49,7 @@ private:
 	Type type;
 	Type type;
 	RID self;
 	RID self;
 	ObjectID instance_id;
 	ObjectID instance_id;
+	ObjectID canvas_instance_id;
 	bool pickable;
 	bool pickable;
 
 
 	struct Shape {
 	struct Shape {
@@ -102,6 +103,9 @@ public:
 	_FORCE_INLINE_ void set_instance_id(const ObjectID &p_instance_id) { instance_id = p_instance_id; }
 	_FORCE_INLINE_ void set_instance_id(const ObjectID &p_instance_id) { instance_id = p_instance_id; }
 	_FORCE_INLINE_ ObjectID get_instance_id() const { return instance_id; }
 	_FORCE_INLINE_ ObjectID get_instance_id() const { return instance_id; }
 
 
+	_FORCE_INLINE_ void set_canvas_instance_id(const ObjectID &p_canvas_instance_id) { canvas_instance_id = p_canvas_instance_id; }
+	_FORCE_INLINE_ ObjectID get_canvas_instance_id() const { return canvas_instance_id; }
+
 	void _shape_changed();
 	void _shape_changed();
 
 
 	_FORCE_INLINE_ Type get_type() const { return type; }
 	_FORCE_INLINE_ Type get_type() const { return type; }

+ 37 - 0
servers/physics_2d/physics_2d_server_sw.cpp

@@ -469,6 +469,27 @@ ObjectID Physics2DServerSW::area_get_object_instance_id(RID p_area) const {
 	return area->get_instance_id();
 	return area->get_instance_id();
 }
 }
 
 
+void Physics2DServerSW::area_attach_canvas_instance_id(RID p_area, ObjectID p_ID) {
+
+	if (space_owner.owns(p_area)) {
+		Space2DSW *space = space_owner.get(p_area);
+		p_area = space->get_default_area()->get_self();
+	}
+	Area2DSW *area = area_owner.get(p_area);
+	ERR_FAIL_COND(!area);
+	area->set_canvas_instance_id(p_ID);
+}
+ObjectID Physics2DServerSW::area_get_canvas_instance_id(RID p_area) const {
+
+	if (space_owner.owns(p_area)) {
+		Space2DSW *space = space_owner.get(p_area);
+		p_area = space->get_default_area()->get_self();
+	}
+	Area2DSW *area = area_owner.get(p_area);
+	ERR_FAIL_COND_V(!area, 0);
+	return area->get_canvas_instance_id();
+}
+
 void Physics2DServerSW::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) {
 void Physics2DServerSW::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) {
 
 
 	if (space_owner.owns(p_area)) {
 	if (space_owner.owns(p_area)) {
@@ -744,6 +765,22 @@ uint32_t Physics2DServerSW::body_get_object_instance_id(RID p_body) const {
 	return body->get_instance_id();
 	return body->get_instance_id();
 };
 };
 
 
+void Physics2DServerSW::body_attach_canvas_instance_id(RID p_body, uint32_t p_ID) {
+
+	Body2DSW *body = body_owner.get(p_body);
+	ERR_FAIL_COND(!body);
+
+	body->set_canvas_instance_id(p_ID);
+};
+
+uint32_t Physics2DServerSW::body_get_canvas_instance_id(RID p_body) const {
+
+	Body2DSW *body = body_owner.get(p_body);
+	ERR_FAIL_COND_V(!body, 0);
+
+	return body->get_canvas_instance_id();
+};
+
 void Physics2DServerSW::body_set_collision_layer(RID p_body, uint32_t p_layer) {
 void Physics2DServerSW::body_set_collision_layer(RID p_body, uint32_t p_layer) {
 
 
 	Body2DSW *body = body_owner.get(p_body);
 	Body2DSW *body = body_owner.get(p_body);

+ 6 - 0
servers/physics_2d/physics_2d_server_sw.h

@@ -144,6 +144,9 @@ public:
 	virtual void area_attach_object_instance_id(RID p_area, ObjectID p_ID);
 	virtual void area_attach_object_instance_id(RID p_area, ObjectID p_ID);
 	virtual ObjectID area_get_object_instance_id(RID p_area) const;
 	virtual ObjectID area_get_object_instance_id(RID p_area) const;
 
 
+	virtual void area_attach_canvas_instance_id(RID p_area, ObjectID p_ID);
+	virtual ObjectID area_get_canvas_instance_id(RID p_area) const;
+
 	virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value);
 	virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value);
 	virtual void area_set_transform(RID p_area, const Transform2D &p_transform);
 	virtual void area_set_transform(RID p_area, const Transform2D &p_transform);
 
 
@@ -188,6 +191,9 @@ public:
 	virtual void body_attach_object_instance_id(RID p_body, uint32_t p_ID);
 	virtual void body_attach_object_instance_id(RID p_body, uint32_t p_ID);
 	virtual uint32_t body_get_object_instance_id(RID p_body) const;
 	virtual uint32_t body_get_object_instance_id(RID p_body) const;
 
 
+	virtual void body_attach_canvas_instance_id(RID p_body, uint32_t p_ID);
+	virtual uint32_t body_get_canvas_instance_id(RID p_body) const;
+
 	virtual void body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode);
 	virtual void body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode);
 	virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const;
 	virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const;
 
 

+ 6 - 0
servers/physics_2d/physics_2d_server_wrap_mt.h

@@ -154,6 +154,9 @@ public:
 	FUNC2(area_attach_object_instance_id, RID, ObjectID);
 	FUNC2(area_attach_object_instance_id, RID, ObjectID);
 	FUNC1RC(ObjectID, area_get_object_instance_id, RID);
 	FUNC1RC(ObjectID, area_get_object_instance_id, RID);
 
 
+	FUNC2(area_attach_canvas_instance_id, RID, ObjectID);
+	FUNC1RC(ObjectID, area_get_canvas_instance_id, RID);
+
 	FUNC3(area_set_param, RID, AreaParameter, const Variant &);
 	FUNC3(area_set_param, RID, AreaParameter, const Variant &);
 	FUNC2(area_set_transform, RID, const Transform2D &);
 	FUNC2(area_set_transform, RID, const Transform2D &);
 
 
@@ -199,6 +202,9 @@ public:
 	FUNC2(body_attach_object_instance_id, RID, uint32_t);
 	FUNC2(body_attach_object_instance_id, RID, uint32_t);
 	FUNC1RC(uint32_t, body_get_object_instance_id, RID);
 	FUNC1RC(uint32_t, body_get_object_instance_id, RID);
 
 
+	FUNC2(body_attach_canvas_instance_id, RID, uint32_t);
+	FUNC1RC(uint32_t, body_get_canvas_instance_id, RID);
+
 	FUNC2(body_set_continuous_collision_detection_mode, RID, CCDMode);
 	FUNC2(body_set_continuous_collision_detection_mode, RID, CCDMode);
 	FUNC1RC(CCDMode, body_get_continuous_collision_detection_mode, RID);
 	FUNC1RC(CCDMode, body_get_continuous_collision_detection_mode, RID);
 
 

+ 14 - 1
servers/physics_2d/space_2d_sw.cpp

@@ -49,7 +49,7 @@ _FORCE_INLINE_ static bool _can_collide_with(CollisionObject2DSW *p_object, uint
 	return true;
 	return true;
 }
 }
 
 
-int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) {
+int Physics2DDirectSpaceStateSW::_intersect_point_impl(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point, bool p_filter_by_canvas, ObjectID p_canvas_instance_id) {
 
 
 	if (p_result_max <= 0)
 	if (p_result_max <= 0)
 		return 0;
 		return 0;
@@ -75,6 +75,9 @@ int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeRe
 		if (p_pick_point && !col_obj->is_pickable())
 		if (p_pick_point && !col_obj->is_pickable())
 			continue;
 			continue;
 
 
+		if (p_filter_by_canvas && col_obj->get_canvas_instance_id() != p_canvas_instance_id)
+			continue;
+
 		int shape_idx = space->intersection_query_subindex_results[i];
 		int shape_idx = space->intersection_query_subindex_results[i];
 
 
 		Shape2DSW *shape = col_obj->get_shape(shape_idx);
 		Shape2DSW *shape = col_obj->get_shape(shape_idx);
@@ -100,6 +103,16 @@ int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeRe
 	return cc;
 	return cc;
 }
 }
 
 
+int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) {
+
+	return _intersect_point_impl(p_point, r_results, p_result_max, p_exclude, p_collision_mask, p_collide_with_bodies, p_collide_with_areas, p_pick_point);
+}
+
+int Physics2DDirectSpaceStateSW::intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) {
+
+	return _intersect_point_impl(p_point, r_results, p_result_max, p_exclude, p_collision_mask, p_collide_with_bodies, p_collide_with_areas, p_pick_point, true, p_canvas_instance_id);
+}
+
 bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
 bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
 
 
 	ERR_FAIL_COND_V(space->locked, false);
 	ERR_FAIL_COND_V(space->locked, false);

+ 3 - 0
servers/physics_2d/space_2d_sw.h

@@ -45,10 +45,13 @@ class Physics2DDirectSpaceStateSW : public Physics2DDirectSpaceState {
 
 
 	GDCLASS(Physics2DDirectSpaceStateSW, Physics2DDirectSpaceState);
 	GDCLASS(Physics2DDirectSpaceStateSW, Physics2DDirectSpaceState);
 
 
+	int _intersect_point_impl(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point, bool p_filter_by_canvas = false, ObjectID p_canvas_instance_id = 0);
+
 public:
 public:
 	Space2DSW *space;
 	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_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false);
 	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_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false);
+	virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false);
 	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_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
 	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_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
 	virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
 	virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
 	virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
 	virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);

+ 24 - 2
servers/physics_2d_server.cpp

@@ -323,7 +323,7 @@ Array Physics2DDirectSpaceState::_cast_motion(const Ref<Physics2DShapeQueryParam
 	return ret;
 	return ret;
 }
 }
 
 
-Array Physics2DDirectSpaceState::_intersect_point(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) {
+Array Physics2DDirectSpaceState::_intersect_point_impl(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_filter_by_canvas, ObjectID p_canvas_instance_id) {
 
 
 	Set<RID> exclude;
 	Set<RID> exclude;
 	for (int i = 0; i < p_exclude.size(); i++)
 	for (int i = 0; i < p_exclude.size(); i++)
@@ -332,7 +332,12 @@ Array Physics2DDirectSpaceState::_intersect_point(const Vector2 &p_point, int p_
 	Vector<ShapeResult> ret;
 	Vector<ShapeResult> ret;
 	ret.resize(p_max_results);
 	ret.resize(p_max_results);
 
 
-	int rc = intersect_point(p_point, ret.ptrw(), ret.size(), exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
+	int rc;
+	if (p_filter_by_canvas)
+		rc = intersect_point(p_point, ret.ptrw(), ret.size(), exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
+	else
+		rc = intersect_point_on_canvas(p_point, p_canvas_instance_id, ret.ptrw(), ret.size(), exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
+
 	if (rc == 0)
 	if (rc == 0)
 		return Array();
 		return Array();
 
 
@@ -351,6 +356,16 @@ Array Physics2DDirectSpaceState::_intersect_point(const Vector2 &p_point, int p_
 	return r;
 	return r;
 }
 }
 
 
+Array Physics2DDirectSpaceState::_intersect_point(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) {
+
+	return _intersect_point_impl(p_point, p_max_results, p_exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
+}
+
+Array Physics2DDirectSpaceState::_intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_intance_id, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) {
+
+	return _intersect_point_impl(p_point, p_max_results, p_exclude, p_layers, p_collide_with_bodies, p_collide_with_areas, true, p_canvas_intance_id);
+}
+
 Array Physics2DDirectSpaceState::_collide_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results) {
 Array Physics2DDirectSpaceState::_collide_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results) {
 
 
 	Vector<Vector2> ret;
 	Vector<Vector2> ret;
@@ -391,6 +406,7 @@ Physics2DDirectSpaceState::Physics2DDirectSpaceState() {
 void Physics2DDirectSpaceState::_bind_methods() {
 void Physics2DDirectSpaceState::_bind_methods() {
 
 
 	ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &Physics2DDirectSpaceState::_intersect_point, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &Physics2DDirectSpaceState::_intersect_point, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
+	ClassDB::bind_method(D_METHOD("intersect_point_on_canvas", "point", "canvas_instance_id", "max_results", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &Physics2DDirectSpaceState::_intersect_point_on_canvas, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &Physics2DDirectSpaceState::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &Physics2DDirectSpaceState::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &Physics2DDirectSpaceState::_intersect_shape, DEFVAL(32));
 	ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &Physics2DDirectSpaceState::_intersect_shape, DEFVAL(32));
 	ClassDB::bind_method(D_METHOD("cast_motion", "shape"), &Physics2DDirectSpaceState::_cast_motion);
 	ClassDB::bind_method(D_METHOD("cast_motion", "shape"), &Physics2DDirectSpaceState::_cast_motion);
@@ -572,6 +588,9 @@ void Physics2DServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("area_attach_object_instance_id", "area", "id"), &Physics2DServer::area_attach_object_instance_id);
 	ClassDB::bind_method(D_METHOD("area_attach_object_instance_id", "area", "id"), &Physics2DServer::area_attach_object_instance_id);
 	ClassDB::bind_method(D_METHOD("area_get_object_instance_id", "area"), &Physics2DServer::area_get_object_instance_id);
 	ClassDB::bind_method(D_METHOD("area_get_object_instance_id", "area"), &Physics2DServer::area_get_object_instance_id);
 
 
+	ClassDB::bind_method(D_METHOD("area_attach_canvas_instance_id", "area", "id"), &Physics2DServer::area_attach_canvas_instance_id);
+	ClassDB::bind_method(D_METHOD("area_get_canvas_instance_id", "area"), &Physics2DServer::area_get_canvas_instance_id);
+
 	ClassDB::bind_method(D_METHOD("area_set_monitor_callback", "area", "receiver", "method"), &Physics2DServer::area_set_monitor_callback);
 	ClassDB::bind_method(D_METHOD("area_set_monitor_callback", "area", "receiver", "method"), &Physics2DServer::area_set_monitor_callback);
 	ClassDB::bind_method(D_METHOD("area_set_area_monitor_callback", "area", "receiver", "method"), &Physics2DServer::area_set_area_monitor_callback);
 	ClassDB::bind_method(D_METHOD("area_set_area_monitor_callback", "area", "receiver", "method"), &Physics2DServer::area_set_area_monitor_callback);
 	ClassDB::bind_method(D_METHOD("area_set_monitorable", "area", "monitorable"), &Physics2DServer::area_set_monitorable);
 	ClassDB::bind_method(D_METHOD("area_set_monitorable", "area", "monitorable"), &Physics2DServer::area_set_monitorable);
@@ -603,6 +622,9 @@ void Physics2DServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("body_attach_object_instance_id", "body", "id"), &Physics2DServer::body_attach_object_instance_id);
 	ClassDB::bind_method(D_METHOD("body_attach_object_instance_id", "body", "id"), &Physics2DServer::body_attach_object_instance_id);
 	ClassDB::bind_method(D_METHOD("body_get_object_instance_id", "body"), &Physics2DServer::body_get_object_instance_id);
 	ClassDB::bind_method(D_METHOD("body_get_object_instance_id", "body"), &Physics2DServer::body_get_object_instance_id);
 
 
+	ClassDB::bind_method(D_METHOD("body_attach_canvas_instance_id", "body", "id"), &Physics2DServer::body_attach_canvas_instance_id);
+	ClassDB::bind_method(D_METHOD("body_get_canvas_instance_id", "body"), &Physics2DServer::body_get_canvas_instance_id);
+
 	ClassDB::bind_method(D_METHOD("body_set_continuous_collision_detection_mode", "body", "mode"), &Physics2DServer::body_set_continuous_collision_detection_mode);
 	ClassDB::bind_method(D_METHOD("body_set_continuous_collision_detection_mode", "body", "mode"), &Physics2DServer::body_set_continuous_collision_detection_mode);
 	ClassDB::bind_method(D_METHOD("body_get_continuous_collision_detection_mode", "body"), &Physics2DServer::body_get_continuous_collision_detection_mode);
 	ClassDB::bind_method(D_METHOD("body_get_continuous_collision_detection_mode", "body"), &Physics2DServer::body_get_continuous_collision_detection_mode);
 
 

+ 9 - 1
servers/physics_2d_server.h

@@ -147,8 +147,9 @@ class Physics2DDirectSpaceState : public Object {
 	GDCLASS(Physics2DDirectSpaceState, Object);
 	GDCLASS(Physics2DDirectSpaceState, Object);
 
 
 	Dictionary _intersect_ray(const Vector2 &p_from, const Vector2 &p_to, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
 	Dictionary _intersect_ray(const Vector2 &p_from, const Vector2 &p_to, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
-
 	Array _intersect_point(const Vector2 &p_point, int p_max_results = 32, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
 	Array _intersect_point(const Vector2 &p_point, int p_max_results = 32, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+	Array _intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_intance_id, int p_max_results = 32, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+	Array _intersect_point_impl(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclud, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_filter_by_canvas = false, ObjectID p_canvas_instance_id = 0);
 	Array _intersect_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results = 32);
 	Array _intersect_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results = 32);
 	Array _cast_motion(const Ref<Physics2DShapeQueryParameters> &p_shape_query);
 	Array _cast_motion(const Ref<Physics2DShapeQueryParameters> &p_shape_query);
 	Array _collide_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results = 32);
 	Array _collide_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results = 32);
@@ -181,6 +182,7 @@ 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_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0;
 	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_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0;
+	virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0;
 
 
 	virtual int intersect_shape(const RID &p_shape, const Transform2D &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_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
 	virtual int intersect_shape(const RID &p_shape, const Transform2D &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_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
 
 
@@ -348,6 +350,9 @@ public:
 	virtual void area_attach_object_instance_id(RID p_area, ObjectID p_ID) = 0;
 	virtual void area_attach_object_instance_id(RID p_area, ObjectID p_ID) = 0;
 	virtual ObjectID area_get_object_instance_id(RID p_area) const = 0;
 	virtual ObjectID area_get_object_instance_id(RID p_area) const = 0;
 
 
+	virtual void area_attach_canvas_instance_id(RID p_area, ObjectID p_ID) = 0;
+	virtual ObjectID area_get_canvas_instance_id(RID p_area) const = 0;
+
 	virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) = 0;
 	virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) = 0;
 	virtual void area_set_transform(RID p_area, const Transform2D &p_transform) = 0;
 	virtual void area_set_transform(RID p_area, const Transform2D &p_transform) = 0;
 
 
@@ -402,6 +407,9 @@ public:
 	virtual void body_attach_object_instance_id(RID p_body, uint32_t p_ID) = 0;
 	virtual void body_attach_object_instance_id(RID p_body, uint32_t p_ID) = 0;
 	virtual uint32_t body_get_object_instance_id(RID p_body) const = 0;
 	virtual uint32_t body_get_object_instance_id(RID p_body) const = 0;
 
 
+	virtual void body_attach_canvas_instance_id(RID p_body, uint32_t p_ID) = 0;
+	virtual uint32_t body_get_canvas_instance_id(RID p_body) const = 0;
+
 	enum CCDMode {
 	enum CCDMode {
 		CCD_MODE_DISABLED,
 		CCD_MODE_DISABLED,
 		CCD_MODE_CAST_RAY,
 		CCD_MODE_CAST_RAY,