diff --git a/engine/include/cubos/engine/collisions/collision_event.hpp b/engine/include/cubos/engine/collisions/collision_event.hpp new file mode 100644 index 000000000..7f5634a5a --- /dev/null +++ b/engine/include/cubos/engine/collisions/collision_event.hpp @@ -0,0 +1,23 @@ +/// @file +/// @brief Event @ref cubos::engine::CollisionEvent. +/// @ingroup collisions-plugin + +#pragma once + +#include + +#include + +namespace cubos::engine +{ + /// @brief Represents a collision event. + /// @ingroup collisions-plugin + struct CollisionEvent + { + cubos::core::ecs::Entity entity; ///< Entity involved in the collision. + cubos::core::ecs::Entity other; ///< Other entity involved in the collision. + float penetration; ///< Penetration depth of the collision. + glm::vec3 position; ///< Position of contact on the surface of the entity. + glm::vec3 normal; ///< Normal of contact on the surface of the entity. + }; +}; // namespace cubos::engine diff --git a/engine/src/cubos/engine/collisions/plugin.cpp b/engine/src/cubos/engine/collisions/plugin.cpp index 08dbf9912..0e1b0b503 100644 --- a/engine/src/cubos/engine/collisions/plugin.cpp +++ b/engine/src/cubos/engine/collisions/plugin.cpp @@ -1,13 +1,17 @@ #include "broad_phase/plugin.hpp" +#include #include +#include #include +#include #include #include #include #include +using cubos::core::ecs::EventWriter; using cubos::core::ecs::Query; using cubos::core::ecs::Read; using cubos::core::ecs::Write; @@ -51,16 +55,66 @@ static void setupNewCapsulesSystem(Query, Write> query, Read candidates, + EventWriter events) +{ + for (const auto& [ent1, ent2] : candidates->candidates(BroadPhaseCandidates::CollisionType::BoxBox)) + { + auto [collider1] = query[ent1].value(); + auto [collider2] = query[ent2].value(); + + 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); cubos.addPlugin(broadPhaseCollisionsPlugin); + cubos.addEvent(); + cubos.addComponent(); cubos.addComponent(); cubos.addComponent(); cubos.system(setupNewBoxesSystem).tagged("cubos.collisions.setup"); cubos.system(setupNewCapsulesSystem).tagged("cubos.collisions.setup"); + cubos.system(emitCollisionEventSystem).tagged("cubos.collisions").after("cubos.collisions.setup"); }