summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scene/2d/area_2d.cpp235
-rw-r--r--scene/2d/area_2d.h35
-rw-r--r--scene/scene_string_names.cpp6
-rw-r--r--scene/scene_string_names.h7
-rw-r--r--servers/physics_2d/area_2d_sw.cpp71
-rw-r--r--servers/physics_2d/area_2d_sw.h34
-rw-r--r--servers/physics_2d/area_pair_2d_sw.cpp69
-rw-r--r--servers/physics_2d/area_pair_2d_sw.h18
-rw-r--r--servers/physics_2d/physics_2d_server_sw.cpp18
-rw-r--r--servers/physics_2d/physics_2d_server_sw.h3
-rw-r--r--servers/physics_2d/space_2d_sw.cpp15
-rw-r--r--servers/physics_2d_server.h3
-rw-r--r--tools/editor/connections_dialog.cpp11
13 files changed, 500 insertions, 25 deletions
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index fce21f6001..b972ddfa3c 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -216,6 +216,119 @@ void Area2D::_body_inout(int p_status,const RID& p_body, int p_instance, int p_b
}
+
+void Area2D::_area_enter_tree(ObjectID p_id) {
+
+ Object *obj = ObjectDB::get_instance(p_id);
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+ ERR_FAIL_COND(!node);
+
+ Map<ObjectID,AreaState>::Element *E=area_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ ERR_FAIL_COND(E->get().in_tree);
+
+ E->get().in_tree=true;
+ emit_signal(SceneStringNames::get_singleton()->area_enter,node);
+ for(int i=0;i<E->get().shapes.size();i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->area_enter_shape,p_id,node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape);
+ }
+
+}
+
+void Area2D::_area_exit_tree(ObjectID p_id) {
+
+ Object *obj = ObjectDB::get_instance(p_id);
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+ ERR_FAIL_COND(!node);
+ Map<ObjectID,AreaState>::Element *E=area_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ ERR_FAIL_COND(!E->get().in_tree);
+ E->get().in_tree=false;
+ emit_signal(SceneStringNames::get_singleton()->area_exit,node);
+ for(int i=0;i<E->get().shapes.size();i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->area_exit_shape,p_id,node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape);
+ }
+
+}
+
+void Area2D::_area_inout(int p_status,const RID& p_area, int p_instance, int p_area_shape,int p_self_shape) {
+
+ bool area_in = p_status==Physics2DServer::AREA_BODY_ADDED;
+ ObjectID objid=p_instance;
+
+ Object *obj = ObjectDB::get_instance(objid);
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+
+ Map<ObjectID,AreaState>::Element *E=area_map.find(objid);
+
+ ERR_FAIL_COND(!area_in && !E);
+
+ locked=true;
+
+ if (area_in) {
+ if (!E) {
+
+ E = area_map.insert(objid,AreaState());
+ E->get().rc=0;
+ E->get().in_tree=node && node->is_inside_tree();
+ if (node) {
+ node->connect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree,make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree,make_binds(objid));
+ if (E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->area_enter,node);
+ }
+ }
+
+ }
+ E->get().rc++;
+ if (node)
+ E->get().shapes.insert(AreaShapePair(p_area_shape,p_self_shape));
+
+
+ if (!node || E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->area_enter_shape,objid,node,p_area_shape,p_self_shape);
+ }
+
+ } else {
+
+ E->get().rc--;
+
+ if (node)
+ E->get().shapes.erase(AreaShapePair(p_area_shape,p_self_shape));
+
+ bool eraseit=false;
+
+ if (E->get().rc==0) {
+
+ if (node) {
+ node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree);
+ if (E->get().in_tree)
+ emit_signal(SceneStringNames::get_singleton()->area_exit,obj);
+
+ }
+
+ eraseit=true;
+
+ }
+ if (!node || E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->area_exit_shape,objid,obj,p_area_shape,p_self_shape);
+ }
+
+ if (eraseit)
+ area_map.erase(E);
+
+ }
+
+ locked=false;
+
+
+}
+
+
+
void Area2D::_clear_monitoring() {
if (locked) {
@@ -223,27 +336,56 @@ void Area2D::_clear_monitoring() {
}
ERR_FAIL_COND(locked);
- Map<ObjectID,BodyState> bmcopy = body_map;
- body_map.clear();
- //disconnect all monitored stuff
+ {
+ Map<ObjectID,BodyState> bmcopy = body_map;
+ body_map.clear();
+ //disconnect all monitored stuff
- for (Map<ObjectID,BodyState>::Element *E=bmcopy.front();E;E=E->next()) {
+ for (Map<ObjectID,BodyState>::Element *E=bmcopy.front();E;E=E->next()) {
- Object *obj = ObjectDB::get_instance(E->key());
- Node *node = obj ? obj->cast_to<Node>() : NULL;
- ERR_CONTINUE(!node);
- if (!E->get().in_tree)
- continue;
+ Object *obj = ObjectDB::get_instance(E->key());
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+ ERR_CONTINUE(!node);
+ if (!E->get().in_tree)
+ continue;
- for(int i=0;i<E->get().shapes.size();i++) {
+ for(int i=0;i<E->get().shapes.size();i++) {
- emit_signal(SceneStringNames::get_singleton()->body_exit_shape,E->key(),node,E->get().shapes[i].body_shape,E->get().shapes[i].area_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_exit_shape,E->key(),node,E->get().shapes[i].body_shape,E->get().shapes[i].area_shape);
+ }
+
+ emit_signal(SceneStringNames::get_singleton()->body_exit,obj);
+
+ node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree);
}
- emit_signal(SceneStringNames::get_singleton()->body_exit,obj);
+ }
+
+ {
- node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree);
- node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree);
+ Map<ObjectID,AreaState> bmcopy = area_map;
+ area_map.clear();
+ //disconnect all monitored stuff
+
+ for (Map<ObjectID,AreaState>::Element *E=bmcopy.front();E;E=E->next()) {
+
+ Object *obj = ObjectDB::get_instance(E->key());
+ Node *node = obj ? obj->cast_to<Node>() : NULL;
+ ERR_CONTINUE(!node);
+ if (!E->get().in_tree)
+ continue;
+
+ for(int i=0;i<E->get().shapes.size();i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->area_exit_shape,E->key(),node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape);
+ }
+
+ emit_signal(SceneStringNames::get_singleton()->area_exit,obj);
+
+ node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree);
+ }
}
}
@@ -276,8 +418,10 @@ void Area2D::set_enable_monitoring(bool p_enable) {
if (monitoring) {
Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),this,"_body_inout");
+ Physics2DServer::get_singleton()->area_set_area_monitor_callback(get_rid(),this,"_area_inout");
} else {
Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),NULL,StringName());
+ Physics2DServer::get_singleton()->area_set_area_monitor_callback(get_rid(),NULL,StringName());
_clear_monitoring();
}
@@ -288,6 +432,26 @@ bool Area2D::is_monitoring_enabled() const {
return monitoring;
}
+void Area2D::set_monitorable(bool p_enable) {
+
+ if (locked) {
+ ERR_EXPLAIN("This function can't be used during the in/out signal.");
+ }
+ ERR_FAIL_COND(locked);
+
+ if (p_enable==monitorable)
+ return;
+
+ monitorable=p_enable;
+
+ Physics2DServer::get_singleton()->area_set_monitorable(get_rid(),monitorable);
+}
+
+bool Area2D::is_monitorable() const {
+
+ return monitorable;
+}
+
Array Area2D::get_overlapping_bodies() const {
ERR_FAIL_COND_V(!monitoring,Array());
@@ -307,12 +471,33 @@ Array Area2D::get_overlapping_bodies() const {
return ret;
}
+Array Area2D::get_overlapping_areas() const {
+
+ ERR_FAIL_COND_V(!monitoring,Array());
+ Array ret;
+ ret.resize(area_map.size());
+ int idx=0;
+ for (const Map<ObjectID,AreaState>::Element *E=area_map.front();E;E=E->next()) {
+ Object *obj = ObjectDB::get_instance(E->key());
+ if (!obj) {
+ ret.resize( ret.size() -1 ); //ops
+ } else {
+ ret[idx++]=obj;
+ }
+
+ }
+
+ return ret;
+}
void Area2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_body_enter_tree","id"),&Area2D::_body_enter_tree);
ObjectTypeDB::bind_method(_MD("_body_exit_tree","id"),&Area2D::_body_exit_tree);
+ ObjectTypeDB::bind_method(_MD("_area_enter_tree","id"),&Area2D::_area_enter_tree);
+ ObjectTypeDB::bind_method(_MD("_area_exit_tree","id"),&Area2D::_area_exit_tree);
+
ObjectTypeDB::bind_method(_MD("set_space_override_mode","enable"),&Area2D::set_space_override_mode);
ObjectTypeDB::bind_method(_MD("get_space_override_mode"),&Area2D::get_space_override_mode);
@@ -337,15 +522,26 @@ void Area2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_enable_monitoring","enable"),&Area2D::set_enable_monitoring);
ObjectTypeDB::bind_method(_MD("is_monitoring_enabled"),&Area2D::is_monitoring_enabled);
+ ObjectTypeDB::bind_method(_MD("set_monitorable","enable"),&Area2D::set_monitorable);
+ ObjectTypeDB::bind_method(_MD("is_monitorable"),&Area2D::is_monitorable);
+
ObjectTypeDB::bind_method(_MD("get_overlapping_bodies"),&Area2D::get_overlapping_bodies);
+ ObjectTypeDB::bind_method(_MD("get_overlapping_areas"),&Area2D::get_overlapping_areas);
ObjectTypeDB::bind_method(_MD("_body_inout"),&Area2D::_body_inout);
+ ObjectTypeDB::bind_method(_MD("_area_inout"),&Area2D::_area_inout);
+
+
+ ADD_SIGNAL( MethodInfo("body_enter_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body",PROPERTY_HINT_RESOURCE_TYPE,"PhysicsBody2D"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"area_shape")));
+ ADD_SIGNAL( MethodInfo("body_exit_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body",PROPERTY_HINT_RESOURCE_TYPE,"PhysicsBody2D"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"area_shape")));
+ ADD_SIGNAL( MethodInfo("body_enter:",PropertyInfo(Variant::OBJECT,"body",PROPERTY_HINT_RESOURCE_TYPE,"PhysicsBody2D")));
+ ADD_SIGNAL( MethodInfo("body_exit",PropertyInfo(Variant::OBJECT,"body",PROPERTY_HINT_RESOURCE_TYPE,"PhysicsBody2D")));
+ ADD_SIGNAL( MethodInfo("area_enter_shape",PropertyInfo(Variant::INT,"area_id"),PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area2D"),PropertyInfo(Variant::INT,"area_shape"),PropertyInfo(Variant::INT,"area_shape")));
+ ADD_SIGNAL( MethodInfo("area_exit_shape",PropertyInfo(Variant::INT,"area_id"),PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area2D"),PropertyInfo(Variant::INT,"area_shape"),PropertyInfo(Variant::INT,"area_shape")));
+ ADD_SIGNAL( MethodInfo("area_enter",PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area2D")));
+ ADD_SIGNAL( MethodInfo("area_exit",PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area2D")));
- ADD_SIGNAL( MethodInfo("body_enter_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"area_shape")));
- ADD_SIGNAL( MethodInfo("body_exit_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"area_shape")));
- ADD_SIGNAL( MethodInfo("body_enter",PropertyInfo(Variant::OBJECT,"body")));
- ADD_SIGNAL( MethodInfo("body_exit",PropertyInfo(Variant::OBJECT,"body")));
ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"space_override",PROPERTY_HINT_ENUM,"Disabled,Combine,Replace"),_SCS("set_space_override_mode"),_SCS("get_space_override_mode"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"gravity_point"),_SCS("set_gravity_is_point"),_SCS("is_gravity_a_point"));
@@ -355,6 +551,7 @@ void Area2D::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::REAL,"angular_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_angular_damp"),_SCS("get_angular_damp"));
ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"priority",PROPERTY_HINT_RANGE,"0,128,1"),_SCS("set_priority"),_SCS("get_priority"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitorable"),_SCS("set_monitorable"),_SCS("is_monitorable"));
}
@@ -369,7 +566,9 @@ Area2D::Area2D() : CollisionObject2D(Physics2DServer::get_singleton()->area_crea
locked=false;
priority=0;
monitoring=false;
+ monitorable=false;
set_enable_monitoring(true);
+ set_monitorable(true);
}
diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h
index f770e88a19..bd00f56ae1 100644
--- a/scene/2d/area_2d.h
+++ b/scene/2d/area_2d.h
@@ -53,6 +53,7 @@ private:
real_t angular_damp;
int priority;
bool monitoring;
+ bool monitorable;
bool locked;
void _body_inout(int p_status,const RID& p_body, int p_instance, int p_body_shape,int p_area_shape);
@@ -84,6 +85,36 @@ private:
Map<ObjectID,BodyState> body_map;
+
+
+ void _area_inout(int p_status,const RID& p_area, int p_instance, int p_area_shape,int p_self_shape);
+
+ void _area_enter_tree(ObjectID p_id);
+ void _area_exit_tree(ObjectID p_id);
+
+ struct AreaShapePair {
+
+ int area_shape;
+ int self_shape;
+ bool operator<(const AreaShapePair& p_sp) const {
+ if (area_shape==p_sp.area_shape)
+ return self_shape < p_sp.self_shape;
+ else
+ return area_shape < p_sp.area_shape;
+ }
+
+ AreaShapePair() {}
+ AreaShapePair(int p_bs, int p_as) { area_shape=p_bs; self_shape=p_as; }
+ };
+
+ struct AreaState {
+
+ int rc;
+ bool in_tree;
+ VSet<AreaShapePair> shapes;
+ };
+
+ Map<ObjectID,AreaState> area_map;
void _clear_monitoring();
@@ -117,7 +148,11 @@ public:
void set_enable_monitoring(bool p_enable);
bool is_monitoring_enabled() const;
+ void set_monitorable(bool p_enable);
+ bool is_monitorable() const;
+
Array get_overlapping_bodies() const; //function for script
+ Array get_overlapping_areas() const; //function for script
Area2D();
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index c30ff0044e..d4159f0946 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -64,6 +64,9 @@ SceneStringNames::SceneStringNames() {
body_exit_shape = StaticCString::create("body_exit_shape");
body_exit = StaticCString::create("body_exit");
+ area_enter_shape = StaticCString::create("area_enter_shape");
+ area_exit_shape = StaticCString::create("area_exit_shape");
+
idle=StaticCString::create("idle");
iteration=StaticCString::create("iteration");
@@ -103,6 +106,9 @@ SceneStringNames::SceneStringNames() {
_body_enter_tree = StaticCString::create("_body_enter_tree");
_body_exit_tree = StaticCString::create("_body_exit_tree");
+ _area_enter_tree = StaticCString::create("_area_enter_tree");
+ _area_exit_tree = StaticCString::create("_area_exit_tree");
+
_input_event=StaticCString::create("_input_event");
changed=StaticCString::create("changed");
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index 184cbe347b..aa29ef57dc 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -83,6 +83,10 @@ public:
StringName body_exit_shape;
StringName body_exit;
+ StringName area_enter_shape;
+ StringName area_exit_shape;
+
+
StringName _get_gizmo_geometry;
StringName _can_gizmo_scale;
@@ -124,6 +128,9 @@ public:
StringName _body_enter_tree;
StringName _body_exit_tree;
+ StringName _area_enter_tree;
+ StringName _area_exit_tree;
+
StringName changed;
StringName _shader_changed;
diff --git a/servers/physics_2d/area_2d_sw.cpp b/servers/physics_2d/area_2d_sw.cpp
index 2e911288ae..65f3b80dd3 100644
--- a/servers/physics_2d/area_2d_sw.cpp
+++ b/servers/physics_2d/area_2d_sw.cpp
@@ -31,6 +31,7 @@
#include "body_2d_sw.h"
Area2DSW::BodyKey::BodyKey(Body2DSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape) { rid=p_body->get_self(); instance_id=p_body->get_instance_id(); body_shape=p_body_shape; area_shape=p_area_shape; }
+Area2DSW::BodyKey::BodyKey(Area2DSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape) { rid=p_body->get_self(); instance_id=p_body->get_instance_id(); body_shape=p_body_shape; area_shape=p_area_shape; }
void Area2DSW::_shapes_changed() {
@@ -57,6 +58,7 @@ void Area2DSW::set_space(Space2DSW *p_space) {
}
monitored_bodies.clear();
+ monitored_areas.clear();
_set_space(p_space);
}
@@ -76,11 +78,31 @@ void Area2DSW::set_monitor_callback(ObjectID p_id, const StringName& p_method) {
monitor_callback_method=p_method;
monitored_bodies.clear();
+ monitored_areas.clear();
_shape_changed();
}
+void Area2DSW::set_area_monitor_callback(ObjectID p_id, const StringName& p_method) {
+
+
+ if (p_id==area_monitor_callback_id) {
+ area_monitor_callback_method=p_method;
+ return;
+ }
+
+ _unregister_shapes();
+
+ area_monitor_callback_id=p_id;
+ area_monitor_callback_method=p_method;
+
+ monitored_bodies.clear();
+ monitored_areas.clear();
+
+ _shape_changed();
+
+}
void Area2DSW::set_space_override_mode(Physics2DServer::AreaSpaceOverrideMode p_mode) {
@@ -134,6 +156,15 @@ void Area2DSW::_queue_monitor_update() {
}
+void Area2DSW::set_monitorable(bool p_monitorable) {
+
+ if (monitorable==p_monitorable)
+ return;
+
+ monitorable=p_monitorable;
+ _set_static(!monitorable);
+}
+
void Area2DSW::call_queries() {
if (monitor_callback_id && !monitored_bodies.empty()) {
@@ -170,13 +201,49 @@ void Area2DSW::call_queries() {
monitored_bodies.clear();
+ if (area_monitor_callback_id && !monitored_areas.empty()) {
+
+
+ Variant res[5];
+ Variant *resptr[5];
+ for(int i=0;i<5;i++)
+ resptr[i]=&res[i];
+
+ Object *obj = ObjectDB::get_instance(area_monitor_callback_id);
+ if (!obj) {
+ monitored_areas.clear();
+ area_monitor_callback_id=0;
+ return;
+ }
+
+
+
+ for (Map<BodyKey,BodyState>::Element *E=monitored_areas.front();E;E=E->next()) {
+
+ if (E->get().state==0)
+ continue; //nothing happened
+
+ res[0]=E->get().state>0 ? Physics2DServer::AREA_BODY_ADDED : Physics2DServer::AREA_BODY_REMOVED;
+ res[1]=E->key().rid;
+ res[2]=E->key().instance_id;
+ res[3]=E->key().body_shape;
+ res[4]=E->key().area_shape;
+
+
+ Variant::CallError ce;
+ obj->call(area_monitor_callback_method,(const Variant**)resptr,5,ce);
+ }
+ }
+
+ monitored_areas.clear();
+
//get_space()->area_remove_from_monitor_query_list(&monitor_query_list);
}
Area2DSW::Area2DSW() : CollisionObject2DSW(TYPE_AREA), monitor_query_list(this), moved_list(this) {
- _set_static(true); //areas are never active
+ _set_static(true); //areas are not active by default
space_override_mode=Physics2DServer::AREA_SPACE_OVERRIDE_DISABLED;
gravity=9.80665;
gravity_vector=Vector2(0,-1);
@@ -187,6 +254,8 @@ Area2DSW::Area2DSW() : CollisionObject2DSW(TYPE_AREA), monitor_query_list(this),
linear_damp=0.1;
priority=0;
monitor_callback_id=0;
+ area_monitor_callback_id=0;
+ monitorable=false;
}
diff --git a/servers/physics_2d/area_2d_sw.h b/servers/physics_2d/area_2d_sw.h
index d94b2f9ccf..26b7b2516c 100644
--- a/servers/physics_2d/area_2d_sw.h
+++ b/servers/physics_2d/area_2d_sw.h
@@ -50,10 +50,14 @@ class Area2DSW : public CollisionObject2DSW{
float linear_damp;
float angular_damp;
int priority;
+ bool monitorable;
ObjectID monitor_callback_id;
StringName monitor_callback_method;
+ ObjectID area_monitor_callback_id;
+ StringName area_monitor_callback_method;
+
SelfList<Area2DSW> monitor_query_list;
SelfList<Area2DSW> moved_list;
@@ -80,6 +84,7 @@ class Area2DSW : public CollisionObject2DSW{
_FORCE_INLINE_ BodyKey() {}
BodyKey(Body2DSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
+ BodyKey(Area2DSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
};
struct BodyState {
@@ -91,6 +96,7 @@ class Area2DSW : public CollisionObject2DSW{
};
Map<BodyKey,BodyState> monitored_bodies;
+ Map<BodyKey,BodyState> monitored_areas;
//virtual void shape_changed_notify(Shape2DSW *p_shape);
//virtual void shape_deleted_notify(Shape2DSW *p_shape);
@@ -108,9 +114,16 @@ public:
void set_monitor_callback(ObjectID p_id, const StringName& p_method);
_FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id; }
+ void set_area_monitor_callback(ObjectID p_id, const StringName& p_method);
+ _FORCE_INLINE_ bool has_area_monitor_callback() const { return area_monitor_callback_id; }
+
+
_FORCE_INLINE_ void add_body_to_query(Body2DSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
_FORCE_INLINE_ void remove_body_from_query(Body2DSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
+ _FORCE_INLINE_ void add_area_to_query(Area2DSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape);
+ _FORCE_INLINE_ void remove_area_from_query(Area2DSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape);
+
void set_param(Physics2DServer::AreaParameter p_param, const Variant& p_value);
Variant get_param(Physics2DServer::AreaParameter p_param) const;
@@ -142,6 +155,9 @@ public:
_FORCE_INLINE_ void remove_constraint( Constraint2DSW* p_constraint) { constraints.erase(p_constraint); }
_FORCE_INLINE_ const Set<Constraint2DSW*>& get_constraints() const { return constraints; }
+ void set_monitorable(bool p_monitorable);
+ _FORCE_INLINE_ bool is_monitorable() const { return monitorable; }
+
void set_transform(const Matrix32& p_transform);
void set_space(Space2DSW *p_space);
@@ -168,6 +184,24 @@ void Area2DSW::remove_body_from_query(Body2DSW *p_body, uint32_t p_body_shape,ui
_queue_monitor_update();
}
+void Area2DSW::add_area_to_query(Area2DSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape) {
+
+
+ BodyKey bk(p_area,p_area_shape,p_self_shape);
+ monitored_areas[bk].inc();
+ if (!monitor_query_list.in_list())
+ _queue_monitor_update();
+
+
+}
+void Area2DSW::remove_area_from_query(Area2DSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape) {
+
+
+ BodyKey bk(p_area,p_area_shape,p_self_shape);
+ monitored_areas[bk].dec();
+ if (!monitor_query_list.in_list())
+ _queue_monitor_update();
+}
diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp
index 1c7f73db5e..ed2e34c972 100644
--- a/servers/physics_2d/area_pair_2d_sw.cpp
+++ b/servers/physics_2d/area_pair_2d_sw.cpp
@@ -94,3 +94,72 @@ AreaPair2DSW::~AreaPair2DSW() {
body->remove_constraint(this);
area->remove_constraint(this);
}
+
+
+//////////////////////////////////
+
+
+
+bool Area2Pair2DSW::setup(float p_step) {
+
+ bool result = CollisionSolver2DSW::solve(area_a->get_shape(shape_a),area_a->get_transform() * area_a->get_shape_transform(shape_a),Vector2(),area_b->get_shape(shape_b),area_b->get_transform() * area_b->get_shape_transform(shape_b),Vector2(),NULL,this);
+
+ if (result!=colliding) {
+
+ if (result) {
+
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+ area_b->add_area_to_query(area_a,shape_a,shape_b);
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+ area_a->add_area_to_query(area_b,shape_b,shape_a);
+
+ } else {
+
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+ area_b->remove_area_from_query(area_a,shape_a,shape_b);
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+ area_a->remove_area_from_query(area_b,shape_b,shape_a);
+ }
+
+ colliding=result;
+
+ }
+
+ return false; //never do any post solving
+}
+
+void Area2Pair2DSW::solve(float p_step) {
+
+
+}
+
+
+Area2Pair2DSW::Area2Pair2DSW(Area2DSW *p_area_a,int p_shape_a, Area2DSW *p_area_b,int p_shape_b) {
+
+
+ area_a=p_area_a;
+ area_b=p_area_b;
+ shape_a=p_shape_a;
+ shape_b=p_shape_b;
+ colliding=false;
+ area_a->add_constraint(this);
+ area_b->add_constraint(this);
+
+}
+
+Area2Pair2DSW::~Area2Pair2DSW() {
+
+ if (colliding) {
+
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+ area_b->remove_area_from_query(area_a,shape_a,shape_b);
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+ area_a->remove_area_from_query(area_b,shape_b,shape_a);
+ }
+
+ area_a->remove_constraint(this);
+ area_b->remove_constraint(this);
+}
diff --git a/servers/physics_2d/area_pair_2d_sw.h b/servers/physics_2d/area_pair_2d_sw.h
index 5dad8c7a12..575490b109 100644
--- a/servers/physics_2d/area_pair_2d_sw.h
+++ b/servers/physics_2d/area_pair_2d_sw.h
@@ -49,5 +49,23 @@ public:
~AreaPair2DSW();
};
+
+class Area2Pair2DSW : public Constraint2DSW {
+
+ Area2DSW *area_a;
+ Area2DSW *area_b;
+ int shape_a;
+ int shape_b;
+ bool colliding;
+public:
+
+ bool setup(float p_step);
+ void solve(float p_step);
+
+ Area2Pair2DSW(Area2DSW *p_area_a,int p_shape_a, Area2DSW *p_area_b,int p_shape_b);
+ ~Area2Pair2DSW();
+};
+
+
#endif // AREA_PAIR_2D_SW_H
diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp
index be49955055..0a02a9568a 100644
--- a/servers/physics_2d/physics_2d_server_sw.cpp
+++ b/servers/physics_2d/physics_2d_server_sw.cpp
@@ -463,6 +463,16 @@ Matrix32 Physics2DServerSW::area_get_transform(RID p_area) const {
return area->get_transform();
};
+void Physics2DServerSW::area_set_monitorable(RID p_area,bool p_monitorable) {
+
+ Area2DSW *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_monitorable(p_monitorable);
+
+}
+
+
void Physics2DServerSW::area_set_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method) {
Area2DSW *area = area_owner.get(p_area);
@@ -473,6 +483,14 @@ void Physics2DServerSW::area_set_monitor_callback(RID p_area,Object *p_receiver,
}
+void Physics2DServerSW::area_set_area_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method) {
+
+
+ Area2DSW *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_area_monitor_callback(p_receiver?p_receiver->get_instance_ID():0,p_method);
+}
/* BODY API */
diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h
index e9c499aaff..eba5845e5b 100644
--- a/servers/physics_2d/physics_2d_server_sw.h
+++ b/servers/physics_2d/physics_2d_server_sw.h
@@ -133,9 +133,10 @@ public:
virtual Variant area_get_param(RID p_parea,AreaParameter p_param) const;
virtual Matrix32 area_get_transform(RID p_area) const;
+ virtual void area_set_monitorable(RID p_area,bool p_monitorable);
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);
/* BODY API */
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index f2ed74ffbf..9523e8bf8a 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -527,13 +527,20 @@ void* Space2DSW::_broadphase_pair(CollisionObject2DSW *A,int p_subindex_A,Collis
if (type_A==CollisionObject2DSW::TYPE_AREA) {
- ERR_FAIL_COND_V(type_B!=CollisionObject2DSW::TYPE_BODY,NULL);
Area2DSW *area=static_cast<Area2DSW*>(A);
- Body2DSW *body=static_cast<Body2DSW*>(B);
+ if (type_B==CollisionObject2DSW::TYPE_AREA) {
+
+ Area2DSW *area_b=static_cast<Area2DSW*>(B);
+ Area2Pair2DSW *area2_pair = memnew(Area2Pair2DSW(area_b,p_subindex_B,area,p_subindex_A) );
+ return area2_pair;
+ } else {
+
+ Body2DSW *body=static_cast<Body2DSW*>(B);
+ AreaPair2DSW *area_pair = memnew(AreaPair2DSW(body,p_subindex_B,area,p_subindex_A) );
+ return area_pair;
+ }
- AreaPair2DSW *area_pair = memnew(AreaPair2DSW(body,p_subindex_B,area,p_subindex_A) );
- return area_pair;
} else {
diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h
index 765cebf45f..1fb47fc1d9 100644
--- a/servers/physics_2d_server.h
+++ b/servers/physics_2d_server.h
@@ -341,7 +341,10 @@ public:
virtual Variant area_get_param(RID p_parea,AreaParameter p_param) const=0;
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_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;
/* BODY API */
diff --git a/tools/editor/connections_dialog.cpp b/tools/editor/connections_dialog.cpp
index d7158eb7e9..cf4b21510a 100644
--- a/tools/editor/connections_dialog.cpp
+++ b/tools/editor/connections_dialog.cpp
@@ -607,6 +607,14 @@ void ConnectionsDialog::_remove_confirm() {
}
*/
+
+struct _ConnectionsDialogMethodInfoSort {
+
+ _FORCE_INLINE_ bool operator()(const MethodInfo& a, const MethodInfo& b) const {
+ return a.name < b.name;
+ }
+};
+
void ConnectionsDialog::update_tree() {
if (!is_visible())
@@ -623,7 +631,8 @@ void ConnectionsDialog::update_tree() {
node->get_signal_list(&node_signals);
-
+ //node_signals.sort_custom<_ConnectionsDialogMethodInfoSort>();
+
for(List<MethodInfo>::Element *E=node_signals.front();E;E=E->next()) {