5#include <unordered_map>
10#include "../events/busEvents.hpp"
11#include "collision/collisionBuffer.hpp"
12#include "components/AABBCollider.hpp"
13#include "components/Transform.hpp"
15namespace rtk::systems {
34 bool operator==(
const Cell &)
const =
default;
38 std::size_t operator()(
const Cell &cell)
const {
40 static_cast<std::size_t
>(
static_cast<std::uint32_t
>(cell.x));
42 static_cast<std::size_t
>(
static_cast<std::uint32_t
>(cell.y));
59 const float secondX = firstX + collider.
width * transform.
scale.
x;
62 const float secondY = firstY + collider.
height * transform.
scale.
y;
64 return {.left = std::min(firstX, secondX),
65 .top = std::min(firstY, secondY),
66 .right = std::max(firstX, secondX),
67 .bottom = std::max(firstY, secondY)};
69 bool intersects(
const WorldAABB &first,
const WorldAABB &second)
const {
70 return first.left < second.right && first.right > second.left &&
71 first.top < second.bottom && first.bottom > second.top;
77 std::unordered_map<Cell, std::vector<std::size_t>, CellHash> _grid;
88 : _collisionBuffer(collisionBuffer), _cellSize(cellSize),
89 _eventBus(eventBus) {}
94 void onStart(rtk::ecs::Registry &)
override {
95 LOG_INFO(
"Load Collider System");
102 void update(rtk::ecs::Registry ®istry,
float)
override {
104 _collisionBuffer.
clear();
110 std::unordered_map<std::size_t, WorldAABB> worldAABBs;
112 for (
const auto entity : view) {
113 const auto *transform = transforms.get(entity);
114 const auto *collider = colliders.get(entity);
116 if (!transform || !collider || collider->
width <= 0.f ||
120 const auto aabb = getWorldAABB(*transform, *collider);
122 worldAABBs.emplace(entity, aabb);
124 const int minCellX =
static_cast<int>(std::floor(aabb.left / _cellSize));
125 const int maxCellX =
static_cast<int>(
126 std::floor(std::nextafter(aabb.right, aabb.left) / _cellSize));
127 const int minCellY =
static_cast<int>(std::floor(aabb.top / _cellSize));
128 const int maxCellY =
static_cast<int>(
129 std::floor(std::nextafter(aabb.bottom, aabb.top) / _cellSize));
131 for (
int y = minCellY; y <= maxCellY; ++y) {
132 for (
int x = minCellX; x <= maxCellX; ++x)
133 _grid[{x, y}].push_back(entity);
137 std::set<std::pair<std::size_t, std::size_t>> testedPairs;
139 for (
const auto &[cell, entities] : _grid) {
140 static_cast<void>(cell);
142 for (std::size_t firstIndex = 0; firstIndex < entities.size();
144 for (std::size_t secondIndex = firstIndex + 1;
145 secondIndex < entities.size(); ++secondIndex) {
146 const auto firstEntity =
147 std::min(entities[firstIndex], entities[secondIndex]);
148 const auto secondEntity =
149 std::max(entities[firstIndex], entities[secondIndex]);
151 if (!testedPairs.emplace(firstEntity, secondEntity).second)
154 const auto *firstCollider = colliders.get(firstEntity);
155 const auto *secondCollider = colliders.get(secondEntity);
157 if (!firstCollider || !secondCollider)
160 if ((firstCollider->mask & secondCollider->layer) == 0)
163 if ((secondCollider->mask & firstCollider->layer) == 0)
166 const auto firstAABB = worldAABBs.find(firstEntity);
167 const auto secondAABB = worldAABBs.find(secondEntity);
169 if (firstAABB == worldAABBs.end() || secondAABB == worldAABBs.end())
172 if (!intersects(firstAABB->second, secondAABB->second))
175 _collisionBuffer.
push({firstEntity, secondEntity});
186 void onStop(rtk::ecs::Registry &)
override {
188 _collisionBuffer.
clear();
Type indexed publish and subscribe event bus.
Definition busEvents.hpp:20
void publish(const E &event)
Calls every handler registered for the event type.
Definition busEvents.hpp:52
Collisions detected during the current frame.
Definition collisionBuffer.hpp:24
void clear()
Removes every stored collision.
Definition collisionBuffer.hpp:29
void push(const Collision &collision)
Stores a collision.
Definition collisionBuffer.hpp:35
Detects overlapping colliders with a uniform spatial hash grid.
Definition ColliderSystem.hpp:28
ColliderSystem(rtk::collision::CollisionBuffer &collisionBuffer, float cellSize, busEvent &eventBus)
Creates the system.
Definition ColliderSystem.hpp:86
void onStop(rtk::ecs::Registry &) override
Clears the grid and the collision buffer.
Definition ColliderSystem.hpp:186
void onStart(rtk::ecs::Registry &) override
Logs that the system is loaded.
Definition ColliderSystem.hpp:94
void update(rtk::ecs::Registry ®istry, float) override
Rebuilds the grid and reports every overlapping pair.
Definition ColliderSystem.hpp:102
Axis aligned bounding box used for collision detection.
Definition AABBCollider.hpp:40
float offsetY
Box offset from the entity position on y.
Definition AABBCollider.hpp:42
float height
Box height before scaling.
Definition AABBCollider.hpp:44
float width
Box width before scaling.
Definition AABBCollider.hpp:43
float offsetX
Box offset from the entity position on x.
Definition AABBCollider.hpp:41
Pair of entities whose colliders overlap.
Definition collisionBuffer.hpp:16
float y
Vertical component.
Definition vec2.hpp:14
float x
Horizontal component.
Definition vec2.hpp:13