R-Type 0.1
Loading...
Searching...
No Matches
DebugCollisionSystem.hpp
1#pragma once
2
3#include <algorithm>
4#include <cstddef>
5#include <unordered_set>
6#include <vector>
7
8#include <ISystem.hpp>
9
10#include "collision/collisionBuffer.hpp"
11
12#include "components/AABBCollider.hpp"
13#include "components/Transform.hpp"
14
15namespace rtk::systems {
26class DebugCollisionSystem final : public rtk::ecs::ISystem {
27public:
35 const rtk::collision::CollisionBuffer &collisionBuffer,
36 rtk::RenderWindow &window, const rtk::InputState &inputState)
37 : _collisionBuffer(collisionBuffer), _window(window),
38 _inputState(inputState) {}
39 ~DebugCollisionSystem() override = default;
40
44 void onStart(rtk::ecs::Registry &) override {
45 constexpr std::array<std::uint8_t, 4> whitePixel{255, 255, 255, 255};
46 const std::span<const std::uint8_t> pixels{whitePixel};
47
48 _debugTextureId = _window.loadTextureFromMemory(pixels, 1, 1).getHandle();
49 }
50
55 void update(rtk::ecs::Registry &registry, float) override {
56 _collidingEntities.clear();
57
58 for (const auto &collision : _collisionBuffer.collisions()) {
59 _collidingEntities.insert(collision.firstEntity);
60 _collidingEntities.insert(collision.secondEntity);
61 }
62
63 std::vector<DebugLine> lines;
64
65 {
66 auto view =
68 auto &transforms = registry.get_components<component::Transform>();
69 auto &colliders = registry.get_components<component::AABBCollider>();
70
71 constexpr float thickness = 2.f;
72
73 for (const auto entity : view) {
74 const auto *transform = transforms.get(entity);
75 const auto *collider = colliders.get(entity);
76
77 if (!transform || !collider)
78 continue;
79
80 const float firstX =
81 transform->position.x + collider->offsetX * transform->scale.x;
82 const float secondX = firstX + collider->width * transform->scale.x;
83 const float firstY =
84 transform->position.y + collider->offsetY * transform->scale.y;
85 const float secondY = firstY + collider->height * transform->scale.y;
86
87 const float left = std::min(firstX, secondX);
88 const float top = std::min(firstY, secondY);
89 const float right = std::max(firstX, secondX);
90 const float bottom = std::max(firstY, secondY);
91 const float width = right - left;
92 const float height = bottom - top;
93 const bool colliding = _collidingEntities.contains(entity);
94
95 lines.push_back({left, top, width, thickness, colliding});
96 lines.push_back(
97 {left, bottom - thickness, width, thickness, colliding});
98 lines.push_back({left, top, thickness, height, colliding});
99 lines.push_back({right - thickness, top, thickness, height, colliding});
100 }
101 }
102
103 resizeDebugEntities(registry, lines.size());
104
105 for (std::size_t index = 0; index < lines.size(); ++index)
106 updateDebugLine(registry, _debugEntities[index], lines[index]);
107 }
108
113 void onStop(rtk::ecs::Registry &registry) override {
114 for (const auto entity : _debugEntities)
115 registry.kill_entity(entity);
116
117 registry.flush();
118
119 _debugEntities.clear();
120 _collidingEntities.clear();
121 }
122
123private:
124 void clearDebugEntities(rtk::ecs::Registry &registry) {
125 for (const auto entity : _debugEntities)
126 registry.kill_entity(entity);
127
128 _debugEntities.clear();
129 }
130
131 struct DebugLine {
132 float x;
133 float y;
134 float width;
135 float height;
136 bool colliding;
137 };
138
139 void resizeDebugEntities(rtk::ecs::Registry &registry, std::size_t count) {
140 while (_debugEntities.size() < count) {
141 const auto entity = registry.spawn_entity();
142
143 registry.get_components<component::Transform>().insert_at(
144 entity, component::Transform{});
145 registry.get_components<ecs::concepts::SpriteData>().insert_at(
146 entity, ecs::concepts::SpriteData{});
147
148 _debugEntities.push_back(entity);
149 }
150
151 while (_debugEntities.size() > count) {
152 registry.kill_entity(_debugEntities.back());
153 _debugEntities.pop_back();
154 }
155 }
156
157 void updateDebugLine(rtk::ecs::Registry &registry, std::size_t entity,
158 const DebugLine &line) {
159 auto *transform =
160 registry.get_components<component::Transform>().get(entity);
161 auto *sprite =
162 registry.get_components<ecs::concepts::SpriteData>().get(entity);
163
164 if (!transform || !sprite)
165 return;
166
167 transform->position = {line.x, line.y};
168 transform->rotation = 0.f;
169 transform->scale = {1.f, 1.f};
170
171 if (!_inputState.debug)
172 sprite->size = {0, 0};
173 else
174 sprite->size = {line.width, line.height};
175 sprite->origin = {0.f, 0.f};
176 sprite->textureRect = {0, 0, 1, 1};
177 sprite->color = line.colliding ? ecs::concepts::ColorRGBA8{255, 0, 0, 255}
178 : ecs::concepts::ColorRGBA8{0, 255, 0, 255};
179 sprite->textureId = _debugTextureId;
180 }
181
182 const rtk::collision::CollisionBuffer &_collisionBuffer;
183 rtk::RenderWindow &_window;
184 const rtk::InputState &_inputState;
185
186 std::uint32_t _debugTextureId = 0;
187
188 std::vector<std::size_t> _debugEntities;
189 std::unordered_set<std::size_t> _collidingEntities;
190};
191
193} // namespace rtk::systems
Collisions detected during the current frame.
Definition collisionBuffer.hpp:24
const std::vector< Collision > & collisions() const
Returns the stored collisions.
Definition collisionBuffer.hpp:41
Draws collider outlines while the debug overlay is enabled.
Definition DebugCollisionSystem.hpp:26
void onStart(rtk::ecs::Registry &) override
Creates the 1x1 white texture used to draw outlines.
Definition DebugCollisionSystem.hpp:44
DebugCollisionSystem(const rtk::collision::CollisionBuffer &collisionBuffer, rtk::RenderWindow &window, const rtk::InputState &inputState)
Creates the system.
Definition DebugCollisionSystem.hpp:34
void update(rtk::ecs::Registry &registry, float) override
Updates one outline entity per collider edge.
Definition DebugCollisionSystem.hpp:55
void onStop(rtk::ecs::Registry &registry) override
Destroys the outline entities.
Definition DebugCollisionSystem.hpp:113
Axis aligned bounding box used for collision detection.
Definition AABBCollider.hpp:40
Position, rotation and scale of an entity in world space.
Definition Transform.hpp:22
utils::vec2 position
Top left corner, in pixels.
Definition Transform.hpp:24
Player input sampled during the current frame.
Definition InputAction.hpp:14
bool debug
True while the debug overlay is enabled.
Definition InputAction.hpp:17
float x
Horizontal component.
Definition vec2.hpp:13