Skip to content

Commit

Permalink
refactor(collisions): replace broadphase resource with relations to i…
Browse files Browse the repository at this point in the history
…dentify a pair of potentially colliding entities
  • Loading branch information
fallenatlas committed Jan 29, 2024
1 parent c7d9aeb commit a7827b6
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 180 deletions.
2 changes: 1 addition & 1 deletion engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ set(CUBOS_ENGINE_SOURCE
"src/cubos/engine/collisions/shapes/capsule.cpp"
"src/cubos/engine/collisions/broad_phase/plugin.cpp"
"src/cubos/engine/collisions/broad_phase/sweep_and_prune.cpp"
"src/cubos/engine/collisions/broad_phase/candidates.cpp"
"src/cubos/engine/collisions/broad_phase/potentially_colliding_with.cpp"

"src/cubos/engine/physics/plugin.cpp"
"src/cubos/engine/physics/gravity.cpp"
Expand Down
61 changes: 0 additions & 61 deletions engine/include/cubos/engine/collisions/broad_phase/candidates.hpp

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/// @file
/// @brief Component @ref cubos::engine::PotentiallyCollidingWith.
/// @ingroup collisions-plugin

// FIXME: This should be private, but it's used in the sample.

#pragma once

#include <cubos/core/reflection/reflect.hpp>

namespace cubos::engine
{
/// @brief Component which represents a potential collisions.
/// @ingroup collisions-plugin
struct PotentiallyCollidingWith
{
CUBOS_REFLECT;
};
} // namespace cubos::engine
15 changes: 5 additions & 10 deletions engine/samples/collisions/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <cubos/core/gl/debug.hpp>
#include <cubos/core/log.hpp>

#include <cubos/engine/collisions/broad_phase/candidates.hpp>
#include <cubos/engine/collisions/broad_phase/potentially_colliding_with.hpp>
#include <cubos/engine/collisions/collider.hpp>
#include <cubos/engine/collisions/plugin.hpp>
#include <cubos/engine/collisions/shapes/box.hpp>
Expand Down Expand Up @@ -103,18 +103,13 @@ static void updateTransform(State& state, const Input& input, Query<Position&, R
bPos.vec += glm::vec3{0.0F, 0.0F, -0.01F};
}

static void updateCollided(Query<Entity, const Collider&> query, State& state, const BroadPhaseCandidates& candidates)
static void updateCollided(Query<Entity, PotentiallyCollidingWith&, Entity> query, State& state)
{
for (auto [entity, collider] : query)
for (auto [ent, colliding, ent1] : query)
{
for (const auto& [collider1, collider2] :
candidates.candidates(BroadPhaseCandidates::CollisionType::BoxCapsule))
if ((ent == state.a && ent1 == state.b) || (ent == state.b && ent1 == state.a))
{
if (collider1 == entity || collider2 == entity)
{
state.collided = true;
break;
}
state.collided = true;
}
}
}
Expand Down
24 changes: 0 additions & 24 deletions engine/src/cubos/engine/collisions/broad_phase/candidates.cpp

This file was deleted.

54 changes: 20 additions & 34 deletions engine/src/cubos/engine/collisions/broad_phase/plugin.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@

#include "plugin.hpp"

#include <cubos/engine/collisions/broad_phase/candidates.hpp>
#include <cubos/engine/collisions/collider.hpp>
#include <cubos/engine/collisions/shapes/box.hpp>
#include <cubos/engine/collisions/shapes/capsule.hpp>
Expand Down Expand Up @@ -108,64 +106,40 @@ static void sweepSystem(BroadPhaseSweepAndPrune& sweepAndPrune)
}
}

BroadPhaseCandidates::CollisionType getCollisionType(bool box, bool capsule)
{
if (box && capsule)
{
return BroadPhaseCandidates::CollisionType::BoxCapsule;
}

if (box)
{
return BroadPhaseCandidates::CollisionType::BoxBox;
}

return BroadPhaseCandidates::CollisionType::CapsuleCapsule;
}

/// @brief Finds all pairs of colliders which may be colliding.
///
/// @details
/// TODO: This query is disgusting. We need a way to find if a component is present without reading it.
static void findPairsSystem(
Query<Entity, Opt<const BoxCollisionShape&>, Opt<const CapsuleCollisionShape&>, const Collider&> query,
const BroadPhaseSweepAndPrune& sweepAndPrune, BroadPhaseCandidates& candidates)
static void findPairsSystem(Commands cmds, Query<Entity, const Collider&> query,
const BroadPhaseSweepAndPrune& sweepAndPrune)
{
candidates.clearCandidates();

for (glm::length_t axis = 0; axis < 3; axis++)
{
for (const auto& [entity, overlaps] : sweepAndPrune.sweepOverlapMaps[axis])
{
auto [_entity, box, capsule, collider] = *query.at(entity);
auto [_entity, collider] = *query.at(entity);
for (const auto& other : overlaps)
{
auto [_other, otherBox, otherCapsule, otherCollider] = *query.at(other);

// TODO: Should this be inside the if statement?
auto type = getCollisionType(box || otherBox, capsule || otherCapsule);
auto [_other, otherCollider] = *query.at(other);

switch (axis)
{
case 0: // X
if (collider.worldAABB.overlapsY(otherCollider.worldAABB) &&
collider.worldAABB.overlapsZ(otherCollider.worldAABB))
{
candidates.addCandidate(type, {entity, other});
cmds.relate(entity, other, PotentiallyCollidingWith{});
}
break;
case 1: // Y
if (collider.worldAABB.overlapsX(otherCollider.worldAABB) &&
collider.worldAABB.overlapsZ(otherCollider.worldAABB))
{
candidates.addCandidate(type, {entity, other});
cmds.relate(entity, other, PotentiallyCollidingWith{});
}
break;
case 2: // Z
if (collider.worldAABB.overlapsX(otherCollider.worldAABB) &&
collider.worldAABB.overlapsY(otherCollider.worldAABB))
{
candidates.addCandidate(type, {entity, other});
cmds.relate(entity, other, PotentiallyCollidingWith{});
}
break;
}
Expand All @@ -174,10 +148,19 @@ static void findPairsSystem(
}
}

/// @brief Removes all pairs of entities found to be potentially colliding.
static void cleanPotentiallyCollidingPairs(Commands cmds, Query<Entity, PotentiallyCollidingWith&, Entity> query)
{
for (auto [entity, collidingWith, other] : query)
{
cmds.unrelate<PotentiallyCollidingWith>(entity, other);
}
}

void cubos::engine::broadPhaseCollisionsPlugin(Cubos& cubos)
{
cubos.addResource<BroadPhaseCandidates>();
cubos.addResource<BroadPhaseSweepAndPrune>();
cubos.addRelation<PotentiallyCollidingWith>();

cubos.system(trackNewCollidersSystem).tagged("cubos.collisions.aabb.setup");

Expand All @@ -189,5 +172,8 @@ void cubos::engine::broadPhaseCollisionsPlugin(Cubos& cubos)

cubos.system(updateMarkersSystem).tagged("cubos.collisions.broad.markers").after("cubos.collisions.aabb.update");
cubos.system(sweepSystem).tagged("cubos.collisions.broad.sweep").after("cubos.collisions.broad.markers");
cubos.system(cleanPotentiallyCollidingPairs)
.tagged("cubos.collisions.broad.clean")
.before("cubos.collisions.broad");
cubos.system(findPairsSystem).tagged("cubos.collisions.broad").after("cubos.collisions.broad.sweep");
}
5 changes: 4 additions & 1 deletion engine/src/cubos/engine/collisions/broad_phase/plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#pragma once

#include <cubos/engine/collisions/broad_phase/potentially_colliding_with.hpp>
#include <cubos/engine/cubos.hpp>

namespace cubos::engine
Expand All @@ -15,8 +16,10 @@ namespace cubos::engine
/// @ingroup engine
/// @brief Adds broad-phase collision detection to @b CUBOS.
///
/// ## Relations
/// - @ref PotentiallyCollidingWith - relates two entities that may be colliding
///
/// ## Resources
/// - @ref BroadPhaseCandidates - stores broad phase collision data.
/// - @ref BroadPhaseSweepAndPrune - stores sweep and prune markers.

/// @brief Plugin entry function.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <cubos/core/ecs/reflection.hpp>
#include <cubos/core/reflection/type.hpp>

#include <cubos/engine/collisions/broad_phase/potentially_colliding_with.hpp>

CUBOS_REFLECT_IMPL(cubos::engine::PotentiallyCollidingWith)
{
return core::ecs::TypeBuilder<PotentiallyCollidingWith>("cubos::engine::PotentiallyCollidingWith")
.symmetric()
.build();
}
49 changes: 0 additions & 49 deletions engine/src/cubos/engine/collisions/plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <cubos/core/ecs/system/event/writer.hpp>
#include <cubos/core/ecs/system/query.hpp>

#include <cubos/engine/collisions/broad_phase/candidates.hpp>
#include <cubos/engine/collisions/collider.hpp>
#include <cubos/engine/collisions/collision_event.hpp>
#include <cubos/engine/collisions/plugin.hpp>
Expand Down Expand Up @@ -51,53 +50,6 @@ static void setupNewCapsulesSystem(Query<const CapsuleCollisionShape&, Collider&
}
}

/// TODO: This is a temporary system should be removed once narrow phase is implemented.
static void emitCollisionEventSystem(Query<const Collider&> query, const BroadPhaseCandidates& candidates,
EventWriter<CollisionEvent> events)
{
for (const auto& [ent1, ent2] : candidates.candidates(BroadPhaseCandidates::CollisionType::BoxBox))
{
auto [collider1] = *query.at(ent1);
auto [collider2] = *query.at(ent2);

auto c1 = collider1.worldAABB.center();
auto b1 = collider1.worldAABB.box();

auto c2 = collider2.worldAABB.center();
auto b2 = collider2.worldAABB.box();

auto d = c2 - c1;
auto p = (b2.halfSize + b1.halfSize) - glm::abs(d);

auto s = glm::sign(d);

float penetration = 0.0F;
glm::vec3 normal{0.0F};
glm::vec3 pos{0.0F};

if (p.x < p.y && p.x < p.z)
{
penetration = p.x;
normal.x = s.x;
pos.x = c1.x + (b1.halfSize.x * s.x);
}
else if (p.y < p.x && p.y < p.z)
{
penetration = p.y;
normal.y = s.y;
pos.y = c1.y + (b1.halfSize.y * s.y);
}
else
{
penetration = p.z;
normal.z = s.z;
pos.z = c1.z + (b1.halfSize.z * s.z);
}

events.push(CollisionEvent{ent1, ent2, penetration, normal, pos});
}
}

void cubos::engine::collisionsPlugin(Cubos& cubos)
{
cubos.addPlugin(transformPlugin);
Expand All @@ -112,5 +64,4 @@ void cubos::engine::collisionsPlugin(Cubos& cubos)

cubos.system(setupNewBoxesSystem).tagged("cubos.collisions.setup");
cubos.system(setupNewCapsulesSystem).tagged("cubos.collisions.setup");
cubos.system(emitCollisionEventSystem).tagged("cubos.collisions").after("cubos.collisions.setup");
}

0 comments on commit a7827b6

Please sign in to comment.