From dae6a57dd03499e13621f6cd45124617510d1b85 Mon Sep 17 00:00:00 2001 From: Marcel Admiraal Date: Wed, 23 Sep 2020 10:14:59 +0100 Subject: [PATCH] Ensure Areas and Bodies only interact with Areas with layers in their mask. --- modules/bullet/collision_object_bullet.h | 4 -- modules/bullet/space_bullet.cpp | 4 ++ servers/physics_2d/area_pair_2d_sw.cpp | 78 ++++++++++----------- servers/physics_2d/area_pair_2d_sw.h | 6 +- servers/physics_2d/collision_object_2d_sw.h | 4 +- servers/physics_2d/space_2d_sw.cpp | 2 +- servers/physics_3d/area_pair_3d_sw.cpp | 78 ++++++++++----------- servers/physics_3d/area_pair_3d_sw.h | 6 +- servers/physics_3d/collision_object_3d_sw.h | 4 +- servers/physics_3d/space_3d_sw.cpp | 2 +- 10 files changed, 96 insertions(+), 92 deletions(-) diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h index 944ab89b8721..d7a5cf27387c 100644 --- a/modules/bullet/collision_object_bullet.h +++ b/modules/bullet/collision_object_bullet.h @@ -179,10 +179,6 @@ class CollisionObjectBullet : public RIDBullet { virtual void on_collision_filters_change() = 0; - _FORCE_INLINE_ bool test_collision_mask(CollisionObjectBullet *p_other) const { - return collisionLayer & p_other->collisionMask || p_other->collisionLayer & collisionMask; - } - virtual void reload_body() = 0; virtual void set_space(SpaceBullet *p_space) = 0; _FORCE_INLINE_ SpaceBullet *get_space() const { return space; } diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 8c286a8629bd..a890aa4fb0a3 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -705,6 +705,10 @@ void SpaceBullet::check_ghost_overlaps() { goto collision_found; } + if (!(area->get_collision_layer() & otherObject->get_collision_mask())) { + continue; + } + if (overlapped_bt_co->getUserIndex() == CollisionObjectBullet::TYPE_AREA) { if (!static_cast(overlapped_bt_co->getUserPointer())->is_monitorable()) { continue; diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp index 5ca16cb6fc96..541b75666a2f 100644 --- a/servers/physics_2d/area_pair_2d_sw.cpp +++ b/servers/physics_2d/area_pair_2d_sw.cpp @@ -29,23 +29,23 @@ /*************************************************************************/ #include "area_pair_2d_sw.h" + #include "collision_solver_2d_sw.h" bool AreaPair2DSW::setup(real_t p_step) { - bool result = false; - if (area->interacts_with(body) && CollisionSolver2DSW::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), nullptr, this)) { - result = true; + bool overlap = false; + if (body->mask_has_layer(area) && CollisionSolver2DSW::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), nullptr, this)) { + overlap = true; } process_collision = false; - if (result != colliding) { + if (overlap != colliding) { + colliding = overlap; if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { process_collision = true; } else if (area->has_monitor_callback()) { process_collision = true; } - - colliding = result; } return process_collision; @@ -109,46 +109,48 @@ AreaPair2DSW::~AreaPair2DSW() { ////////////////////////////////// bool Area2Pair2DSW::setup(real_t p_step) { - bool result = false; - if (area_a->interacts_with(area_b) && 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(), nullptr, this)) { - result = true; + bool overlap = false; + if (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(), nullptr, this)) { + overlap = true; } - process_collision = false; - if (result != colliding) { - if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { - process_collision = true; - } else if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { - process_collision = true; + bool b_collides_with_a = overlap && area_b->mask_has_layer(area_a); + bool a_collides_with_b = overlap && area_a->mask_has_layer(area_b); + process_collision_with_a = false; + process_collision_with_b = false; + + if (b_collides_with_a != b_colliding_with_a) { + b_colliding_with_a = b_collides_with_a; + if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { + process_collision_with_a = true; } + } - colliding = result; + if (a_collides_with_b != a_colliding_with_b) { + a_colliding_with_b = a_collides_with_b; + if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { + process_collision_with_b = true; + } } - return process_collision; + return process_collision_with_a || process_collision_with_b; } bool Area2Pair2DSW::pre_solve(real_t p_step) { - if (!process_collision) { - return false; + if (process_collision_with_a) { + if (b_colliding_with_a) { + area_a->add_area_to_query(area_b, shape_b, shape_a); + } else { // b no longer colliding with a + area_a->remove_area_from_query(area_b, shape_b, shape_a); + } } - if (colliding) { - if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { + if (process_collision_with_b) { + if (a_colliding_with_b) { 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()) { + } else { // a no longer colliding with b 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); - } } return false; // Never do any post solving. @@ -168,14 +170,12 @@ Area2Pair2DSW::Area2Pair2DSW(Area2DSW *p_area_a, int p_shape_a, Area2DSW *p_area } Area2Pair2DSW::~Area2Pair2DSW() { - if (colliding) { - if (area_b->has_area_monitor_callback()) { - area_b->remove_area_from_query(area_a, shape_a, shape_b); - } + if (a_colliding_with_b && area_b->has_area_monitor_callback()) { + area_b->remove_area_from_query(area_a, shape_a, shape_b); + } - if (area_a->has_area_monitor_callback()) { - area_a->remove_area_from_query(area_b, shape_b, shape_a); - } + if (b_colliding_with_a && area_a->has_area_monitor_callback()) { + area_a->remove_area_from_query(area_b, shape_b, shape_a); } area_a->remove_constraint(this); diff --git a/servers/physics_2d/area_pair_2d_sw.h b/servers/physics_2d/area_pair_2d_sw.h index 4632a307d9ee..e219b714a9ff 100644 --- a/servers/physics_2d/area_pair_2d_sw.h +++ b/servers/physics_2d/area_pair_2d_sw.h @@ -57,8 +57,10 @@ class Area2Pair2DSW : public Constraint2DSW { Area2DSW *area_b = nullptr; int shape_a = 0; int shape_b = 0; - bool colliding = false; - bool process_collision = false; + bool b_colliding_with_a = false; + bool a_colliding_with_b = false; + bool process_collision_with_a = false; + bool process_collision_with_b = false; public: virtual bool setup(real_t p_step) override; diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h index 14adb0bb1801..cc4e570804dd 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/collision_object_2d_sw.h @@ -186,8 +186,8 @@ class CollisionObject2DSW : public ShapeOwner2DSW { void set_pickable(bool p_pickable) { pickable = p_pickable; } _FORCE_INLINE_ bool is_pickable() const { return pickable; } - _FORCE_INLINE_ bool layer_in_mask(CollisionObject2DSW *p_other) const { - return collision_layer & p_other->collision_mask; + _FORCE_INLINE_ bool mask_has_layer(CollisionObject2DSW *p_other) const { + return collision_mask & p_other->collision_layer; } _FORCE_INLINE_ bool interacts_with(CollisionObject2DSW *p_other) const { diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 43329fed2f32..e7bd908c6198 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -508,7 +508,7 @@ int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb) { keep = false; } else if (intersection_query_results[i]->get_type() == CollisionObject2DSW::TYPE_AREA) { keep = false; - } else if (!p_body->layer_in_mask(static_cast(intersection_query_results[i]))) { + } else if (!p_body->mask_has_layer(static_cast(intersection_query_results[i]))) { keep = false; } else if (static_cast(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) { keep = false; diff --git a/servers/physics_3d/area_pair_3d_sw.cpp b/servers/physics_3d/area_pair_3d_sw.cpp index f43c2c965e94..d23ea5074ad4 100644 --- a/servers/physics_3d/area_pair_3d_sw.cpp +++ b/servers/physics_3d/area_pair_3d_sw.cpp @@ -29,23 +29,23 @@ /*************************************************************************/ #include "area_pair_3d_sw.h" + #include "collision_solver_3d_sw.h" bool AreaPair3DSW::setup(real_t p_step) { - bool result = false; - if (area->interacts_with(body) && CollisionSolver3DSW::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), nullptr, this)) { - result = true; + bool overlap = false; + if (body->mask_has_layer(area) && CollisionSolver3DSW::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), nullptr, this)) { + overlap = true; } process_collision = false; - if (result != colliding) { + if (overlap != colliding) { + colliding = overlap; if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { process_collision = true; } else if (area->has_monitor_callback()) { process_collision = true; } - - colliding = result; } return process_collision; @@ -109,46 +109,48 @@ AreaPair3DSW::~AreaPair3DSW() { //////////////////////////////////////////////////// bool Area2Pair3DSW::setup(real_t p_step) { - bool result = false; - if (area_a->interacts_with(area_b) && CollisionSolver3DSW::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), nullptr, this)) { - result = true; + bool overlap = false; + if (CollisionSolver3DSW::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), nullptr, this)) { + overlap = true; } - process_collision = false; - if (result != colliding) { - if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { - process_collision = true; - } else if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { - process_collision = true; + bool b_collides_with_a = overlap && area_b->mask_has_layer(area_a); + bool a_collides_with_b = overlap && area_a->mask_has_layer(area_b); + process_collision_with_a = false; + process_collision_with_b = false; + + if (b_collides_with_a != b_colliding_with_a) { + b_colliding_with_a = b_collides_with_a; + if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { + process_collision_with_a = true; } + } - colliding = result; + if (a_collides_with_b != a_colliding_with_b) { + a_colliding_with_b = a_collides_with_b; + if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { + process_collision_with_b = true; + } } - return process_collision; + return process_collision_with_a || process_collision_with_b; } bool Area2Pair3DSW::pre_solve(real_t p_step) { - if (!process_collision) { - return false; + if (process_collision_with_a) { + if (b_colliding_with_a) { + area_a->add_area_to_query(area_b, shape_b, shape_a); + } else { // b no longer colliding with a + area_a->remove_area_from_query(area_b, shape_b, shape_a); + } } - if (colliding) { - if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { + if (process_collision_with_b) { + if (a_colliding_with_b) { 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()) { + } else { // a no longer colliding with b 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); - } } return false; // Never do any post solving. @@ -168,14 +170,12 @@ Area2Pair3DSW::Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area } Area2Pair3DSW::~Area2Pair3DSW() { - if (colliding) { - if (area_b->has_area_monitor_callback()) { - area_b->remove_area_from_query(area_a, shape_a, shape_b); - } + if (a_colliding_with_b && area_b->has_area_monitor_callback()) { + area_b->remove_area_from_query(area_a, shape_a, shape_b); + } - if (area_a->has_area_monitor_callback()) { - area_a->remove_area_from_query(area_b, shape_b, shape_a); - } + if (b_colliding_with_a && area_a->has_area_monitor_callback()) { + area_a->remove_area_from_query(area_b, shape_b, shape_a); } area_a->remove_constraint(this); diff --git a/servers/physics_3d/area_pair_3d_sw.h b/servers/physics_3d/area_pair_3d_sw.h index 596d8930828f..e38d97177921 100644 --- a/servers/physics_3d/area_pair_3d_sw.h +++ b/servers/physics_3d/area_pair_3d_sw.h @@ -57,8 +57,10 @@ class Area2Pair3DSW : public Constraint3DSW { Area3DSW *area_b; int shape_a; int shape_b; - bool colliding = false; - bool process_collision = false; + bool b_colliding_with_a = false; + bool a_colliding_with_b = false; + bool process_collision_with_a = false; + bool process_collision_with_b = false; public: virtual bool setup(real_t p_step) override; diff --git a/servers/physics_3d/collision_object_3d_sw.h b/servers/physics_3d/collision_object_3d_sw.h index fb8dca8bb42c..89f244af63ae 100644 --- a/servers/physics_3d/collision_object_3d_sw.h +++ b/servers/physics_3d/collision_object_3d_sw.h @@ -166,8 +166,8 @@ class CollisionObject3DSW : public ShapeOwner3DSW { } _FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; } - _FORCE_INLINE_ bool layer_in_mask(CollisionObject3DSW *p_other) const { - return collision_layer & p_other->collision_mask; + _FORCE_INLINE_ bool mask_has_layer(CollisionObject3DSW *p_other) const { + return collision_mask & p_other->collision_layer; } _FORCE_INLINE_ bool interacts_with(CollisionObject3DSW *p_other) const { diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp index bc149648d7ae..39b56a84b398 100644 --- a/servers/physics_3d/space_3d_sw.cpp +++ b/servers/physics_3d/space_3d_sw.cpp @@ -549,7 +549,7 @@ int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) { keep = false; } else if (intersection_query_results[i]->get_type() == CollisionObject3DSW::TYPE_SOFT_BODY) { keep = false; - } else if (!p_body->layer_in_mask(static_cast(intersection_query_results[i]))) { + } else if (!p_body->mask_has_layer(static_cast(intersection_query_results[i]))) { keep = false; } else if (static_cast(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) { keep = false;