-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCollisionSystem.h
More file actions
169 lines (129 loc) · 4.35 KB
/
Copy pathCollisionSystem.h
File metadata and controls
169 lines (129 loc) · 4.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#pragma once
#include <vector>
#include "Collider.h"
struct OBB {
vec2 center;
vec2 axes[2]; // normalized world axes
float extents[2]; // half width/height (from transform scale)
};
inline OBB getOBB(Collider2D& c) {
const mat3& M = c.getWorldMatrix();
OBB o;
// World position
o.center = vec2(M[2].x, M[2].y);
// Extract orientation from matrix columns
vec2 axisX = vec2(M[0].x, M[1].x);
vec2 axisY = vec2(M[0].y, M[1].y);
float lenX = glm::length(axisX);
float lenY = glm::length(axisY);
o.axes[0] = axisX / lenX; // normalized X axis
o.axes[1] = axisY / lenY; // normalized Y axis
// Use world-scale directly as extents
vec2 worldScale = c.getWorldScale();
o.extents[0] = worldScale.x * 0.5f;
o.extents[1] = worldScale.y * 0.5f;
return o;
}
inline bool overlapOnAxis(const OBB& A, const OBB& B, const vec2& axis)
{
float projA =
fabs(dot(A.axes[0], axis)) * A.extents[0] +
fabs(dot(A.axes[1], axis)) * A.extents[1];
float projB =
fabs(dot(B.axes[0], axis)) * B.extents[0] +
fabs(dot(B.axes[1], axis)) * B.extents[1];
float distance = fabs(dot(B.center - A.center, axis));
return distance <= projA + projB;
}
bool obbVsObb(Collider2D& A_c, Collider2D& B_c)
{
OBB A = getOBB(A_c);
OBB B = getOBB(B_c);
vec2 axes[] = { A.axes[0], A.axes[1], B.axes[0], B.axes[1] };
for (const auto& axis : axes)
if (!overlapOnAxis(A, B, axis))
return false;
return true;
}
bool circleVsObb(Collider2D& C, Collider2D& B_c)
{
OBB B = getOBB(B_c);
vec2 pc = C.getWorldPosition();
float rc = C.scale.x * C.getWorldScale().x;
vec2 d = pc - B.center;
float localX = dot(d, B.axes[0]);
float localY = dot(d, B.axes[1]);
float clampedX = glm::clamp(localX, -B.extents[0], B.extents[0]);
float clampedY = glm::clamp(localY, -B.extents[1], B.extents[1]);
vec2 closest =
B.center +
B.axes[0] * clampedX +
B.axes[1] * clampedY;
vec2 delta = pc - closest;
float dist2 = glm::dot(delta, delta);
return dist2 <= rc * rc;
}
inline void testCollision(std::shared_ptr<Collider2D> A, std::shared_ptr<Collider2D> B)
{
if (!A || !B) return;
if ((A->mask & B->layer) == 0 || (B->mask & A->layer) == 0)
return;
bool collision = false;
// Determine collision type based on shape
if (A->shapeType == Collider2D::ShapeType::Rectangle && B->shapeType == Collider2D::ShapeType::Rectangle) {
// OBB vs OBB
collision = obbVsObb(*A, *B);
}
else if (A->shapeType == Collider2D::ShapeType::Circle && B->shapeType == Collider2D::ShapeType::Circle) {
// Circle vs Circle
vec2 posA = A->getWorldPosition();
vec2 posB = B->getWorldPosition();
float rA = A->scale.x * A->getWorldScale().x;
float rB = B->scale.x * B->getWorldScale().x;
vec2 delta = posB - posA;
float dist2 = dot(delta, delta);
float radiusSum = rA + rB;
collision = dist2 <= radiusSum * radiusSum;
}
else {
// Circle vs OBB: make sure circle is first
if (A->shapeType != Collider2D::ShapeType::Circle) std::swap(A, B);
collision = circleVsObb(*A, *B);
}
if (collision) {
// Optional: call collision callbacks if you have them
A->handleCollision(B.get());
B->handleCollision(A.get());
}
}
class CollisionSystem {
public:
std::vector<std::weak_ptr<Collider2D>> colliders;
void addCollider(const std::shared_ptr<Collider2D>& c) {
colliders.push_back(c);
}
void update() {
colliders.erase(
std::remove_if(colliders.begin(), colliders.end(),
[](const std::weak_ptr<Collider2D>& w) {
return w.expired();
}
),
colliders.end()
);
// pairwise collision test
for (int i = 0; i < colliders.size(); i++) {
auto a = colliders[i].lock();
if (!a) continue;
for (int j = i + 1; j < colliders.size(); j++) {
auto b = colliders[j].lock();
if (!b) continue;
testCollision(a, b);
}
}
for (int i = 0; i < colliders.size(); i++) {
auto a = colliders[i].lock();
a->finalizeCollisions();
}
}
};