From f7c3d6329cdc9c21c205f1522813090313a422d2 Mon Sep 17 00:00:00 2001 From: Bojidar Marinov Date: Sat, 9 Apr 2016 21:54:09 +0300 Subject: [PATCH] Port collision and layer masks to 3D, fixes #1759 Raycasts now have type_mask and layer_mask. Areas - collision_mask and layer_mask. PhysicsBodies needed only collision_mask. --- scene/3d/area.cpp | 70 ++++++++++++++++++++++++ scene/3d/area.h | 14 +++++ scene/3d/physics_body.cpp | 71 ++++++++++++++++++++++++- scene/3d/physics_body.h | 14 +++++ scene/3d/ray_cast.cpp | 32 ++++++++++- scene/3d/ray_cast.h | 9 ++++ servers/physics/area_pair_sw.cpp | 10 ++++ servers/physics/body_pair_sw.cpp | 2 +- servers/physics/collision_object_sw.cpp | 1 + servers/physics/collision_object_sw.h | 8 +++ servers/physics/physics_server_sw.cpp | 35 ++++++++++++ servers/physics/physics_server_sw.h | 6 +++ servers/physics_server.cpp | 8 +++ servers/physics_server.h | 6 +++ 14 files changed, 283 insertions(+), 3 deletions(-) diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp index 7d4235e0510..8527c4d60e7 100644 --- a/scene/3d/area.cpp +++ b/scene/3d/area.cpp @@ -519,6 +519,60 @@ bool Area::overlaps_body(Node* p_body) const{ return E->get().in_tree; } +void Area::set_collision_mask(uint32_t p_mask) { + + collision_mask=p_mask; + PhysicsServer::get_singleton()->area_set_collision_mask(get_rid(),p_mask); +} + +uint32_t Area::get_collision_mask() const { + + return collision_mask; +} +void Area::set_layer_mask(uint32_t p_mask) { + + layer_mask=p_mask; + PhysicsServer::get_singleton()->area_set_layer_mask(get_rid(),p_mask); +} + +uint32_t Area::get_layer_mask() const { + + return layer_mask; +} + +void Area::set_collision_mask_bit(int p_bit, bool p_value) { + + uint32_t mask = get_collision_mask(); + if (p_value) + mask|=1<area_create(),tru angular_damp=1; priority=0; monitoring=false; + collision_mask=1; + layer_mask=1; set_ray_pickable(false); set_enable_monitoring(true); set_monitorable(true); diff --git a/scene/3d/area.h b/scene/3d/area.h index c250d27fb1f..440a7d20303 100644 --- a/scene/3d/area.h +++ b/scene/3d/area.h @@ -54,6 +54,8 @@ private: real_t gravity_distance_scale; real_t angular_damp; real_t linear_damp; + uint32_t collision_mask; + uint32_t layer_mask; int priority; bool monitoring; bool monitorable; @@ -157,6 +159,18 @@ public: void set_monitorable(bool p_enable); bool is_monitorable() const; + void set_collision_mask(uint32_t p_mask); + uint32_t get_collision_mask() const; + + void set_layer_mask(uint32_t p_mask); + uint32_t get_layer_mask() const; + + void set_collision_mask_bit(int p_bit, bool p_value); + bool get_collision_mask_bit(int p_bit) const; + + void set_layer_mask_bit(int p_bit, bool p_value); + bool get_layer_mask_bit(int p_bit) const; + Array get_overlapping_bodies() const; Array get_overlapping_areas() const; //function for script diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index bc637eed44f..243cb31aca0 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -69,6 +69,50 @@ uint32_t PhysicsBody::get_layer_mask() const { return layer_mask; } +void PhysicsBody::set_collision_mask(uint32_t p_mask) { + + collision_mask=p_mask; + PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(),p_mask); +} + +uint32_t PhysicsBody::get_collision_mask() const { + + return collision_mask; +} + +void PhysicsBody::set_collision_mask_bit(int p_bit, bool p_value) { + + uint32_t mask = get_collision_mask(); + if (p_value) + mask|=1<body_remove_collision_exception(get_rid(),physics_body->get_rid()); } +void PhysicsBody::_set_layers(uint32_t p_mask) { + set_layer_mask(p_mask); + set_collision_mask(p_mask); +} + +uint32_t PhysicsBody::_get_layers() const{ + + return get_layer_mask(); +} void PhysicsBody::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_layer_mask","mask"),&PhysicsBody::set_layer_mask); ObjectTypeDB::bind_method(_MD("get_layer_mask"),&PhysicsBody::get_layer_mask); - ADD_PROPERTY(PropertyInfo(Variant::INT,"layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask")); + + ObjectTypeDB::bind_method(_MD("set_collision_mask","mask"),&PhysicsBody::set_collision_mask); + ObjectTypeDB::bind_method(_MD("get_collision_mask"),&PhysicsBody::get_collision_mask); + + ObjectTypeDB::bind_method(_MD("set_collision_mask_bit","bit","value"),&PhysicsBody::set_collision_mask_bit); + ObjectTypeDB::bind_method(_MD("get_collision_mask_bit","bit"),&PhysicsBody::get_collision_mask_bit); + + ObjectTypeDB::bind_method(_MD("set_layer_mask_bit","bit","value"),&PhysicsBody::set_layer_mask_bit); + ObjectTypeDB::bind_method(_MD("get_layer_mask_bit","bit"),&PhysicsBody::get_layer_mask_bit); + + ObjectTypeDB::bind_method(_MD("_set_layers","mask"),&PhysicsBody::_set_layers); + ObjectTypeDB::bind_method(_MD("_get_layers"),&PhysicsBody::_get_layers); + + ADD_PROPERTY(PropertyInfo(Variant::INT,"layers",PROPERTY_HINT_ALL_FLAGS,"",0),_SCS("_set_layers"),_SCS("_get_layers")); //for backwards compat + ADD_PROPERTY(PropertyInfo(Variant::INT,"collision/layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"collision/mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_mask"),_SCS("get_collision_mask")); } PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) : CollisionObject( PhysicsServer::get_singleton()->body_create(p_mode), false) { layer_mask=1; + collision_mask=1; } diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index da79d63f00e..f95b4f017fd 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -39,6 +39,11 @@ class PhysicsBody : public CollisionObject { OBJ_TYPE(PhysicsBody,CollisionObject); uint32_t layer_mask; + uint32_t collision_mask; + + void _set_layers(uint32_t p_mask); + uint32_t _get_layers() const; + protected: static void _bind_methods(); @@ -53,6 +58,15 @@ public: void set_layer_mask(uint32_t p_mask); uint32_t get_layer_mask() const; + void set_collision_mask(uint32_t p_mask); + uint32_t get_collision_mask() const; + + void set_layer_mask_bit(int p_bit, bool p_value); + bool get_layer_mask_bit(int p_bit) const; + + void set_collision_mask_bit(int p_bit, bool p_value); + bool get_collision_mask_bit(int p_bit) const; + void add_collision_exception_with(Node* p_node); //must be physicsbody void remove_collision_exception_with(Node* p_node); diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp index 29813597fa1..1acda8d1f8d 100644 --- a/scene/3d/ray_cast.cpp +++ b/scene/3d/ray_cast.cpp @@ -43,6 +43,26 @@ Vector3 RayCast::get_cast_to() const{ return cast_to; } +void RayCast::set_layer_mask(uint32_t p_mask) { + + layer_mask=p_mask; +} + +uint32_t RayCast::get_layer_mask() const { + + return layer_mask; +} + +void RayCast::set_type_mask(uint32_t p_mask) { + + type_mask=p_mask; +} + +uint32_t RayCast::get_type_mask() const { + + return type_mask; +} + bool RayCast::is_colliding() const{ return collided; @@ -130,7 +150,7 @@ void RayCast::_notification(int p_what) { PhysicsDirectSpaceState::RayResult rr; - if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exclude)) { + if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exclude, layer_mask, type_mask)) { collided=true; against=rr.collider_id; @@ -206,8 +226,16 @@ void RayCast::_bind_methods() { ObjectTypeDB::bind_method(_MD("clear_exceptions"),&RayCast::clear_exceptions); + ObjectTypeDB::bind_method(_MD("set_layer_mask","mask"),&RayCast::set_layer_mask); + ObjectTypeDB::bind_method(_MD("get_layer_mask"),&RayCast::get_layer_mask); + + ObjectTypeDB::bind_method(_MD("set_type_mask","mask"),&RayCast::set_type_mask); + ObjectTypeDB::bind_method(_MD("get_type_mask"),&RayCast::get_type_mask); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled")); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"layer_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"type_mask",PROPERTY_HINT_FLAGS,"Static,Kinematic,Rigid,Character,Area"),_SCS("set_type_mask"),_SCS("get_type_mask")); } RayCast::RayCast() { @@ -216,5 +244,7 @@ RayCast::RayCast() { against=0; collided=false; against_shape=0; + layer_mask=1; + type_mask=PhysicsDirectSpaceState::TYPE_MASK_COLLISION; cast_to=Vector3(0,-1,0); } diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h index 520b4d53131..4f6514e61b2 100644 --- a/scene/3d/ray_cast.h +++ b/scene/3d/ray_cast.h @@ -47,6 +47,9 @@ class RayCast : public Spatial { Set exclude; + uint32_t layer_mask; + uint32_t type_mask; + protected: void _notification(int p_what); @@ -59,6 +62,12 @@ public: void set_cast_to(const Vector3& p_point); Vector3 get_cast_to() const; + void set_layer_mask(uint32_t p_mask); + uint32_t get_layer_mask() const; + + void set_type_mask(uint32_t p_mask); + uint32_t get_type_mask() const; + bool is_colliding() const; Object *get_collider() const; int get_collider_shape() const; diff --git a/servers/physics/area_pair_sw.cpp b/servers/physics/area_pair_sw.cpp index c6bf6114a00..24f3b75ca56 100644 --- a/servers/physics/area_pair_sw.cpp +++ b/servers/physics/area_pair_sw.cpp @@ -32,6 +32,11 @@ bool AreaPairSW::setup(float p_step) { + if (!area->test_collision_mask(body)) { + colliding = false; + return false; + } + bool result = CollisionSolverSW::solve_static(body->get_shape(body_shape),body->get_transform() * body->get_shape_transform(body_shape),area->get_shape(area_shape),area->get_transform() * area->get_shape_transform(area_shape),NULL,this); if (result!=colliding) { @@ -100,6 +105,11 @@ AreaPairSW::~AreaPairSW() { bool Area2PairSW::setup(float p_step) { + if (!area_a->test_collision_mask(area_b)) { + colliding = false; + return false; + } + // 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); diff --git a/servers/physics/body_pair_sw.cpp b/servers/physics/body_pair_sw.cpp index a971cdaad82..40e906c36c3 100644 --- a/servers/physics/body_pair_sw.cpp +++ b/servers/physics/body_pair_sw.cpp @@ -221,7 +221,7 @@ bool BodyPairSW::_test_ccd(float p_step,BodySW *p_A, int p_shape_A,const Transfo bool BodyPairSW::setup(float p_step) { //cannot collide - if ((A->get_layer_mask()&B->get_layer_mask())==0 || A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC && B->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC && A->get_max_contacts_reported()==0 && B->get_max_contacts_reported()==0)) { + if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC && B->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC && A->get_max_contacts_reported()==0 && B->get_max_contacts_reported()==0)) { collided=false; return false; } diff --git a/servers/physics/collision_object_sw.cpp b/servers/physics/collision_object_sw.cpp index 55c8c1b955b..f2864ee95e0 100644 --- a/servers/physics/collision_object_sw.cpp +++ b/servers/physics/collision_object_sw.cpp @@ -217,5 +217,6 @@ CollisionObjectSW::CollisionObjectSW(Type p_type) { space=NULL; instance_id=0; layer_mask=1; + collision_mask=1; ray_pickable=true; } diff --git a/servers/physics/collision_object_sw.h b/servers/physics/collision_object_sw.h index 592c84e6679..bc71c2709b2 100644 --- a/servers/physics/collision_object_sw.h +++ b/servers/physics/collision_object_sw.h @@ -53,6 +53,7 @@ private: RID self; ObjectID instance_id; uint32_t layer_mask; + uint32_t collision_mask; struct Shape { @@ -136,6 +137,13 @@ public: _FORCE_INLINE_ void set_layer_mask(uint32_t p_mask) { layer_mask=p_mask; } _FORCE_INLINE_ uint32_t get_layer_mask() const { return layer_mask; } + _FORCE_INLINE_ void set_collision_mask(uint32_t p_mask) { collision_mask=p_mask; } + _FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; } + + _FORCE_INLINE_ bool test_collision_mask(CollisionObjectSW* p_other) const { + return layer_mask&p_other->collision_mask || p_other->layer_mask&collision_mask; + } + void remove_shape(ShapeSW *p_shape); void remove_shape(int p_index); diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index 5eb14d80dc1..5307f1ce88f 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -418,6 +418,22 @@ Transform PhysicsServerSW::area_get_transform(RID p_area) const { return area->get_transform(); }; +void PhysicsServerSW::area_set_layer_mask(RID p_area,uint32_t p_mask) { + + AreaSW *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + + area->set_layer_mask(p_mask); +} + +void PhysicsServerSW::area_set_collision_mask(RID p_area,uint32_t p_mask) { + + AreaSW *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + + area->set_collision_mask(p_mask); +} + void PhysicsServerSW::area_set_monitorable(RID p_area,bool p_monitorable) { AreaSW *area = area_owner.get(p_area); @@ -657,6 +673,25 @@ uint32_t PhysicsServerSW::body_get_layer_mask(RID p_body, uint32_t p_mask) const } +void PhysicsServerSW::body_set_collision_mask(RID p_body, uint32_t p_mask) { + + BodySW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_collision_mask(p_mask); + body->wakeup(); + +} + +uint32_t PhysicsServerSW::body_get_collision_mask(RID p_body, uint32_t p_mask) const{ + + const BodySW *body = body_owner.get(p_body); + ERR_FAIL_COND_V(!body,0); + + return body->get_collision_mask(); + +} + void PhysicsServerSW::body_attach_object_instance_ID(RID p_body,uint32_t p_ID) { diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h index 2aadac22162..59eeeb42a70 100644 --- a/servers/physics/physics_server_sw.h +++ b/servers/physics/physics_server_sw.h @@ -131,6 +131,9 @@ 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_collision_mask(RID p_area,uint32_t p_mask); + virtual void area_set_layer_mask(RID p_area,uint32_t p_mask); + 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); @@ -171,6 +174,9 @@ public: virtual void body_set_layer_mask(RID p_body, uint32_t p_mask); virtual uint32_t body_get_layer_mask(RID p_body, uint32_t p_mask) const; + virtual void body_set_collision_mask(RID p_body, uint32_t p_mask); + virtual uint32_t body_get_collision_mask(RID p_body, uint32_t p_mask) const; + virtual void body_set_user_flags(RID p_body, uint32_t p_flags); virtual uint32_t body_get_user_flags(RID p_body, uint32_t p_flags) const; diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp index 89fcffe7ed1..685477ed795 100644 --- a/servers/physics_server.cpp +++ b/servers/physics_server.cpp @@ -457,6 +457,8 @@ void PhysicsServer::_bind_methods() { ObjectTypeDB::bind_method(_MD("area_remove_shape","area","shape_idx"),&PhysicsServer::area_remove_shape); ObjectTypeDB::bind_method(_MD("area_clear_shapes","area"),&PhysicsServer::area_clear_shapes); + ObjectTypeDB::bind_method(_MD("area_set_layer_mask","area","mask"),&PhysicsServer::area_set_layer_mask); + ObjectTypeDB::bind_method(_MD("area_set_collision_mask","area","mask"),&PhysicsServer::area_set_collision_mask); ObjectTypeDB::bind_method(_MD("area_set_param","area","param","value"),&PhysicsServer::area_set_param); ObjectTypeDB::bind_method(_MD("area_set_transform","area","transform"),&PhysicsServer::area_set_transform); @@ -480,6 +482,12 @@ void PhysicsServer::_bind_methods() { ObjectTypeDB::bind_method(_MD("body_set_mode","body","mode"),&PhysicsServer::body_set_mode); ObjectTypeDB::bind_method(_MD("body_get_mode","body"),&PhysicsServer::body_get_mode); + ObjectTypeDB::bind_method(_MD("body_set_layer_mask","body","mask"),&PhysicsServer::body_set_layer_mask); + ObjectTypeDB::bind_method(_MD("body_get_layer_mask","body"),&PhysicsServer::body_get_layer_mask); + + ObjectTypeDB::bind_method(_MD("body_set_collision_mask","body","mask"),&PhysicsServer::body_set_collision_mask); + ObjectTypeDB::bind_method(_MD("body_get_collision_mask","body"),&PhysicsServer::body_get_collision_mask); + ObjectTypeDB::bind_method(_MD("body_add_shape","body","shape","transform"),&PhysicsServer::body_add_shape,DEFVAL(Transform())); ObjectTypeDB::bind_method(_MD("body_set_shape","body","shape_idx","shape"),&PhysicsServer::body_set_shape); ObjectTypeDB::bind_method(_MD("body_set_shape_transform","body","shape_idx","transform"),&PhysicsServer::body_set_shape_transform); diff --git a/servers/physics_server.h b/servers/physics_server.h index 9b00825d929..5221b38ccbb 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -346,6 +346,9 @@ 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_collision_mask(RID p_area,uint32_t p_mask)=0; + virtual void area_set_layer_mask(RID p_area,uint32_t p_mask)=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; @@ -397,6 +400,9 @@ public: virtual void body_set_layer_mask(RID p_body, uint32_t p_mask)=0; virtual uint32_t body_get_layer_mask(RID p_body, uint32_t p_mask) const=0; + virtual void body_set_collision_mask(RID p_body, uint32_t p_mask)=0; + virtual uint32_t body_get_collision_mask(RID p_body, uint32_t p_mask) const=0; + virtual void body_set_user_flags(RID p_body, uint32_t p_flags)=0; virtual uint32_t body_get_user_flags(RID p_body, uint32_t p_flags) const=0;