From 89300b70e7217feaf0be15cfe395763f555bbafa Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Fri, 12 Jun 2015 15:52:21 -0300 Subject: [PATCH] added ability for Area (3D) to detect other areas --- scene/3d/area.cpp | 254 ++++++++++++++++++++++++-- scene/3d/area.h | 38 ++++ servers/physics/area_pair_sw.cpp | 69 +++++++ servers/physics/area_pair_sw.h | 18 ++ servers/physics/area_sw.cpp | 69 +++++++ servers/physics/area_sw.h | 37 +++- servers/physics/physics_server_sw.cpp | 16 ++ servers/physics/physics_server_sw.h | 3 + servers/physics/space_sw.cpp | 15 +- servers/physics_server.h | 3 + 10 files changed, 500 insertions(+), 22 deletions(-) diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp index 76527c72e65..a00946a07a5 100644 --- a/scene/3d/area.cpp +++ b/scene/3d/area.cpp @@ -225,27 +225,56 @@ void Area::_clear_monitoring() { } ERR_FAIL_COND(locked); - Map bmcopy = body_map; - body_map.clear(); - //disconnect all monitored stuff + { + Map bmcopy = body_map; + body_map.clear(); + //disconnect all monitored stuff - for (Map::Element *E=bmcopy.front();E;E=E->next()) { + for (Map::Element *E=bmcopy.front();E;E=E->next()) { - Object *obj = ObjectDB::get_instance(E->key()); - Node *node = obj ? obj->cast_to() : NULL; - ERR_CONTINUE(!node); - if (!E->get().in_tree) - continue; + Object *obj = ObjectDB::get_instance(E->key()); + Node *node = obj ? obj->cast_to() : NULL; + ERR_CONTINUE(!node); + if (!E->get().in_tree) + continue; - for(int i=0;iget().shapes.size();i++) { + for(int i=0;iget().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 bmcopy = area_map; + area_map.clear(); + //disconnect all monitored stuff + + for (Map::Element *E=bmcopy.front();E;E=E->next()) { + + Object *obj = ObjectDB::get_instance(E->key()); + Node *node = obj ? obj->cast_to() : NULL; + ERR_CONTINUE(!node); + if (!E->get().in_tree) + continue; + + for(int i=0;iget().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); + } } } @@ -271,12 +300,129 @@ void Area::set_enable_monitoring(bool p_enable) { if (monitoring) { PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),this,"_body_inout"); + PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(),this,"_area_inout"); } else { PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),NULL,StringName()); + PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(),NULL,StringName()); _clear_monitoring(); + } } + +void Area::_area_enter_tree(ObjectID p_id) { + + Object *obj = ObjectDB::get_instance(p_id); + Node *node = obj ? obj->cast_to() : NULL; + ERR_FAIL_COND(!node); + + Map::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;iget().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 Area::_area_exit_tree(ObjectID p_id) { + + Object *obj = ObjectDB::get_instance(p_id); + Node *node = obj ? obj->cast_to() : NULL; + ERR_FAIL_COND(!node); + Map::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;iget().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 Area::_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==PhysicsServer::AREA_BODY_ADDED; + ObjectID objid=p_instance; + + Object *obj = ObjectDB::get_instance(objid); + Node *node = obj ? obj->cast_to() : NULL; + + Map::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; + + +} + bool Area::is_monitoring_enabled() const { return monitoring; @@ -302,11 +448,76 @@ Array Area::get_overlapping_bodies() const { return ret; } +void Area::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; + + PhysicsServer::get_singleton()->area_set_monitorable(get_rid(),monitorable); +} + +bool Area::is_monitorable() const { + + return monitorable; +} + + +Array Area::get_overlapping_areas() const { + + ERR_FAIL_COND_V(!monitoring,Array()); + Array ret; + ret.resize(area_map.size()); + int idx=0; + for (const Map::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; +} + +bool Area::overlaps_area(Node* p_area) const { + + ERR_FAIL_NULL_V(p_area,false); + const Map::Element *E=area_map.find(p_area->get_instance_ID()); + if (!E) + return false; + return E->get().in_tree; + + + +} + +bool Area::overlaps_body(Node* p_body) const{ + + ERR_FAIL_NULL_V(p_body,false); + const Map::Element *E=body_map.find(p_body->get_instance_ID()); + if (!E) + return false; + return E->get().in_tree; + +} + void Area::_bind_methods() { ObjectTypeDB::bind_method(_MD("_body_enter_tree","id"),&Area::_body_enter_tree); ObjectTypeDB::bind_method(_MD("_body_exit_tree","id"),&Area::_body_exit_tree); + ObjectTypeDB::bind_method(_MD("_area_enter_tree","id"),&Area::_area_enter_tree); + ObjectTypeDB::bind_method(_MD("_area_exit_tree","id"),&Area::_area_exit_tree); + ObjectTypeDB::bind_method(_MD("set_space_override_mode","enable"),&Area::set_space_override_mode); ObjectTypeDB::bind_method(_MD("get_space_override_mode"),&Area::get_space_override_mode); @@ -328,13 +539,21 @@ void Area::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_priority","priority"),&Area::set_priority); ObjectTypeDB::bind_method(_MD("get_priority"),&Area::get_priority); + ObjectTypeDB::bind_method(_MD("set_monitorable","enable"),&Area::set_monitorable); + ObjectTypeDB::bind_method(_MD("is_monitorable"),&Area::is_monitorable); + ObjectTypeDB::bind_method(_MD("set_enable_monitoring","enable"),&Area::set_enable_monitoring); ObjectTypeDB::bind_method(_MD("is_monitoring_enabled"),&Area::is_monitoring_enabled); ObjectTypeDB::bind_method(_MD("get_overlapping_bodies"),&Area::get_overlapping_bodies); + ObjectTypeDB::bind_method(_MD("get_overlapping_areas"),&Area::get_overlapping_areas); + + ObjectTypeDB::bind_method(_MD("overlaps_body:PhysicsBody","body"),&Area::overlaps_body); + ObjectTypeDB::bind_method(_MD("overlaps_area:Area","area"),&Area::overlaps_area); ObjectTypeDB::bind_method(_MD("_body_inout"),&Area::_body_inout); + ObjectTypeDB::bind_method(_MD("_area_inout"),&Area::_area_inout); 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"))); @@ -342,6 +561,11 @@ void Area::_bind_methods() { ADD_SIGNAL( MethodInfo("body_enter",PropertyInfo(Variant::OBJECT,"body"))); ADD_SIGNAL( MethodInfo("body_exit",PropertyInfo(Variant::OBJECT,"body"))); + ADD_SIGNAL( MethodInfo("area_enter_shape",PropertyInfo(Variant::INT,"area_id"),PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area"),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,"Area"),PropertyInfo(Variant::INT,"area_shape"),PropertyInfo(Variant::INT,"area_shape"))); + ADD_SIGNAL( MethodInfo("area_enter",PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area"))); + ADD_SIGNAL( MethodInfo("area_exit",PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area"))); + ADD_PROPERTY( 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")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity_distance_scale", PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_gravity_distance_scale"),_SCS("get_gravity_distance_scale")); @@ -350,6 +574,7 @@ void Area::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::REAL,"density",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_density"),_SCS("get_density")); ADD_PROPERTY( 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")); } @@ -366,6 +591,7 @@ Area::Area() : CollisionObject(PhysicsServer::get_singleton()->area_create(),tru monitoring=false; set_ray_pickable(false); set_enable_monitoring(true); + set_monitorable(true); } diff --git a/scene/3d/area.h b/scene/3d/area.h index fb853092f36..fa7500c47c8 100644 --- a/scene/3d/area.h +++ b/scene/3d/area.h @@ -53,6 +53,7 @@ private: real_t density; int priority; bool monitoring; + bool monitorable; bool locked; @@ -84,6 +85,36 @@ private: }; Map 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 shapes; + }; + + Map area_map; void _clear_monitoring(); @@ -117,7 +148,14 @@ 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; + Array get_overlapping_areas() const; //function for script + + bool overlaps_area(Node* p_area) const; + bool overlaps_body(Node* p_body) const; Area(); diff --git a/servers/physics/area_pair_sw.cpp b/servers/physics/area_pair_sw.cpp index e009bd52cb9..3eb96fb6817 100644 --- a/servers/physics/area_pair_sw.cpp +++ b/servers/physics/area_pair_sw.cpp @@ -93,3 +93,72 @@ AreaPairSW::~AreaPairSW() { body->remove_constraint(this); area->remove_constraint(this); } + +//////////////////////////////////////////////////// + + + +bool Area2PairSW::setup(float p_step) { + +// bool result = area_a->test_collision_mask(area_b) && CollisionSolverSW::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); + bool result = CollisionSolverSW::solve_static(area_a->get_shape(shape_a),area_a->get_transform() * area_a->get_shape_transform(shape_a),area_b->get_shape(shape_b),area_b->get_transform() * area_b->get_shape_transform(shape_b),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 Area2PairSW::solve(float p_step) { + + +} + + +Area2PairSW::Area2PairSW(AreaSW *p_area_a,int p_shape_a, AreaSW *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); + +} + +Area2PairSW::~Area2PairSW() { + + 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/area_pair_sw.h b/servers/physics/area_pair_sw.h index 1c219a05fdf..4f8087280a3 100644 --- a/servers/physics/area_pair_sw.h +++ b/servers/physics/area_pair_sw.h @@ -49,5 +49,23 @@ public: ~AreaPairSW(); }; + +class Area2PairSW : public ConstraintSW { + + AreaSW *area_a; + AreaSW *area_b; + int shape_a; + int shape_b; + bool colliding; +public: + + bool setup(float p_step); + void solve(float p_step); + + Area2PairSW(AreaSW *p_area_a,int p_shape_a, AreaSW *p_area_b,int p_shape_b); + ~Area2PairSW(); +}; + + #endif // AREA_PAIR__SW_H diff --git a/servers/physics/area_sw.cpp b/servers/physics/area_sw.cpp index aa1c530221b..83be80f8160 100644 --- a/servers/physics/area_sw.cpp +++ b/servers/physics/area_sw.cpp @@ -31,6 +31,7 @@ #include "body_sw.h" AreaSW::BodyKey::BodyKey(BodySW *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; } +AreaSW::BodyKey::BodyKey(AreaSW *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 AreaSW::_shapes_changed() { @@ -57,6 +58,7 @@ void AreaSW::set_space(SpaceSW *p_space) { } monitored_bodies.clear(); + monitored_areas.clear(); _set_space(p_space); } @@ -76,11 +78,32 @@ void AreaSW::set_monitor_callback(ObjectID p_id, const StringName& p_method) { monitor_callback_method=p_method; monitored_bodies.clear(); + monitored_areas.clear(); + _shape_changed(); } +void AreaSW::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 AreaSW::set_space_override_mode(PhysicsServer::AreaSpaceOverrideMode p_mode) { @@ -134,6 +157,15 @@ void AreaSW::_queue_monitor_update() { } +void AreaSW::set_monitorable(bool p_monitorable) { + + if (monitorable==p_monitorable) + return; + + monitorable=p_monitorable; + _set_static(!monitorable); +} + void AreaSW::call_queries() { if (monitor_callback_id && !monitored_bodies.empty()) { @@ -168,6 +200,41 @@ void AreaSW::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::Element *E=monitored_areas.front();E;E=E->next()) { + + if (E->get().state==0) + continue; //nothing happened + + res[0]=E->get().state>0 ? PhysicsServer::AREA_BODY_ADDED : PhysicsServer::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); } @@ -185,6 +252,8 @@ AreaSW::AreaSW() : CollisionObjectSW(TYPE_AREA), monitor_query_list(this), move priority=0; set_ray_pickable(false); monitor_callback_id=0; + area_monitor_callback_id=0; + monitorable=false; } diff --git a/servers/physics/area_sw.h b/servers/physics/area_sw.h index a875472f6ba..26d6a177db8 100644 --- a/servers/physics/area_sw.h +++ b/servers/physics/area_sw.h @@ -49,10 +49,14 @@ class AreaSW : public CollisionObjectSW{ float point_attenuation; float density; int priority; + bool monitorable; ObjectID monitor_callback_id; StringName monitor_callback_method; + ObjectID area_monitor_callback_id; + StringName area_monitor_callback_method; + SelfList monitor_query_list; SelfList moved_list; @@ -79,6 +83,8 @@ class AreaSW : public CollisionObjectSW{ _FORCE_INLINE_ BodyKey() {} BodyKey(BodySW *p_body, uint32_t p_body_shape,uint32_t p_area_shape); + BodyKey(AreaSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape); + }; struct BodyState { @@ -90,6 +96,7 @@ class AreaSW : public CollisionObjectSW{ }; Map monitored_bodies; + Map monitored_areas; //virtual void shape_changed_notify(ShapeSW *p_shape); //virtual void shape_deleted_notify(ShapeSW *p_shape); @@ -108,9 +115,15 @@ 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(BodySW *p_body, uint32_t p_body_shape,uint32_t p_area_shape); _FORCE_INLINE_ void remove_body_from_query(BodySW *p_body, uint32_t p_body_shape,uint32_t p_area_shape); + _FORCE_INLINE_ void add_area_to_query(AreaSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape); + _FORCE_INLINE_ void remove_area_from_query(AreaSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape); + void set_param(PhysicsServer::AreaParameter p_param, const Variant& p_value); Variant get_param(PhysicsServer::AreaParameter p_param) const; @@ -142,8 +155,8 @@ public: _FORCE_INLINE_ void remove_constraint( ConstraintSW* p_constraint) { constraints.erase(p_constraint); } _FORCE_INLINE_ const Set& get_constraints() const { return constraints; } - - + void set_monitorable(bool p_monitorable); + _FORCE_INLINE_ bool is_monitorable() const { return monitorable; } void set_transform(const Transform& p_transform); @@ -172,6 +185,26 @@ void AreaSW::remove_body_from_query(BodySW *p_body, uint32_t p_body_shape,uint32 } +void AreaSW::add_area_to_query(AreaSW *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 AreaSW::remove_area_from_query(AreaSW *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/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index 03d5b7afa16..521ffae0eab 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -394,6 +394,14 @@ Transform PhysicsServerSW::area_get_transform(RID p_area) const { return area->get_transform(); }; +void PhysicsServerSW::area_set_monitorable(RID p_area,bool p_monitorable) { + + AreaSW *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + + area->set_monitorable(p_monitorable); +} + void PhysicsServerSW::area_set_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method) { AreaSW *area = area_owner.get(p_area); @@ -423,6 +431,14 @@ bool PhysicsServerSW::area_is_ray_pickable(RID p_area) const{ } +void PhysicsServerSW::area_set_area_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method) { + + + AreaSW *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/physics_server_sw.h b/servers/physics/physics_server_sw.h index de2a24a3781..80007b84998 100644 --- a/servers/physics/physics_server_sw.h +++ b/servers/physics/physics_server_sw.h @@ -128,7 +128,10 @@ public: virtual void area_set_ray_pickable(RID p_area,bool p_enable); virtual bool area_is_ray_pickable(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/space_sw.cpp b/servers/physics/space_sw.cpp index a7465c57b9f..d329a10f049 100644 --- a/servers/physics/space_sw.cpp +++ b/servers/physics/space_sw.cpp @@ -503,15 +503,18 @@ void* SpaceSW::_broadphase_pair(CollisionObjectSW *A,int p_subindex_A,CollisionO if (type_A==CollisionObjectSW::TYPE_AREA) { - - ERR_FAIL_COND_V(type_B!=CollisionObjectSW::TYPE_BODY,NULL); AreaSW *area=static_cast(A); - BodySW *body=static_cast(B); + if (type_B==CollisionObjectSW::TYPE_AREA) { + AreaSW *area_b=static_cast(B); + Area2PairSW *area2_pair = memnew(Area2PairSW(area_b,p_subindex_B,area,p_subindex_A) ); + return area2_pair; + } else { - AreaPairSW *area_pair = memnew(AreaPairSW(body,p_subindex_B,area,p_subindex_A) ); - - return area_pair; + BodySW *body=static_cast(B); + AreaPairSW *area_pair = memnew(AreaPairSW(body,p_subindex_B,area,p_subindex_A) ); + return area_pair; + } } else { diff --git a/servers/physics_server.h b/servers/physics_server.h index 05b64da8048..f66ea590b82 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -339,7 +339,10 @@ public: virtual Variant area_get_param(RID p_parea,AreaParameter p_param) const=0; virtual Transform 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; virtual void area_set_ray_pickable(RID p_area,bool p_enable)=0; virtual bool area_is_ray_pickable(RID p_area) const=0;