casse-brick
Loading...
Searching...
No Matches
CollidingObject.cpp
Go to the documentation of this file.
1//
2// Created by nicolas elfering on 08.05.24.
3//
4
5#include "CollidingObject.h"
6
7
8void Collider::move(point newPoint) {
9 p += newPoint;
10}
11
12void Collider::moveTo(point newPoint) {
13 p = newPoint;
14}
15
16std::shared_ptr<Collider> CollidingObject::getCollider() {
17 return collider;
18}
19
20float distance(const point& p1, const point& p2) {
21 return std::sqrt(std::pow(p2.x - p1.x, 2) + std::pow(p2.y - p1.y, 2));
22}
23
25 float dbp_ad = distance(s1,s2); // dbp =distance between point
26 float dbp_ed = distance({s2.x,s1.y},s2);
27 float dbp_ae = distance(s1,{s2.x,s1.y});
28
29 float dbp_ac = (k*dbp_ae)/dbp_ad;
30 float dbp_cb = (k*dbp_ed)/dbp_ad;
31
32 if (s1.x>s2.x)
33 return {s1.x - dbp_ac, s1.y+dbp_cb};
34 return {s1.x + dbp_ac, s1.y+dbp_cb};
35}
36
37std::tuple<bool, float, float> CircleCollider::collided(const Collider &other) const {
38 if (const RectCollider* otherRect = dynamic_cast<const RectCollider*>(&other)) {
39 float closestX = std::clamp(p.x, otherRect->p.x, otherRect->p.x + otherRect->width);
40 float closestY = std::clamp(p.y, otherRect->p.y, otherRect->p.y + otherRect->height);
41
42 float distanceX = p.x - closestX;
43 float distanceY = p.y - closestY;
44
45 float distanceSquared = (distanceX * distanceX) + (distanceY * distanceY);
46 float radiusSquared = radius*radius;
47
48 if (distanceSquared < radiusSquared) {
49 float collisionX = closestX;
50 float collisionY = closestY;
51 return std::make_tuple(true, collisionX, collisionY);
52 }
53 }
54 else if (const TriangleCollider* triangle = dynamic_cast<const TriangleCollider*>(&other)) {
55 point vertex1 = {p.x-triangle->corner[0].x,p.y-triangle->corner[0].y};
56 point vertex2 = {p.x-triangle->corner[1].x,p.y-triangle->corner[1].y};
57 point vertex3 = {p.x-triangle->corner[2].x,p.y-triangle->corner[2].y};
58
59 // Test if a summit is in the circle
60 if (sqrt((vertex1.x*vertex1.x)+(vertex1.y*vertex1.y)) <= radius)
61 return {true, vertex1.x, vertex1.y};
62 if (sqrt((vertex2.x*vertex2.x)+(vertex2.y*vertex2.y)) <= radius)
63 return {true, vertex2.x, vertex2.y};
64 if (sqrt((vertex3.x*vertex3.x)+(vertex3.y*vertex3.y)) <= radius)
65 return {true, vertex3.x, vertex3.y};
66
67 // Test if the circle touch an edge
68 for (int i=0;i<triangle->corner.size(); i++) {
69 int next = (i+1)%triangle->corner.size();
70 point vertex = {p.x-triangle->corner[i].x,p.y-triangle->corner[i].y};
71 point nextVertex = {p.x-triangle->corner[next].x,p.y-triangle->corner[next].y};
72 point edge = {vertex.x-nextVertex.x,vertex.y-nextVertex.y};
73 float k = vertex.x*edge.x+vertex.y*edge.y;
74 if (k>0) {
75 float len = sqrt(edge.x*edge.x+edge.y*edge.y);
76 k/=len;
77 if (k<len) {
78 if (sqrt(vertex.x*vertex.x+vertex.y*vertex.y - k*k) <= radius) {
79 point c = getIntersection(triangle->corner[i], triangle->corner[next], k);
80 point vect{};
81 if (triangle->corner[i].x < triangle->corner[next].x)
82 vect = {triangle->corner[i].x-c.x, triangle->corner[i].y-c.y};
83 else
84 vect = {triangle->corner[next].x-c.x, triangle->corner[next].y-c.y};
85 return {true, vect.x, vect.y};
86 }
87 }
88 }
89 }
90 }
91 else if (const HexagonCollider* hexagon = dynamic_cast<const HexagonCollider*>(&other)) {
92 for (int i=0; i<hexagon->corner.size(); i++) {
93 point vertex = {p.x-hexagon->corner[i].x,p.y-hexagon->corner[i].y};
94 if (sqrt((vertex.x*vertex.x)+(vertex.y*vertex.y)) <= radius)
95 return {true, vertex.x, vertex.y};
96
97 int nextInd = i+1%hexagon->corner.size();
98 point nextVertex = {p.x-hexagon->corner[nextInd].x,p.y-hexagon->corner[nextInd].y};
99 float incl = (hexagon->corner[nextInd].y-hexagon->corner[i].y)/(hexagon->corner[nextInd].x-hexagon->corner[i].x);
100 float closestX = abs(hexagon->corner[i].x+hexagon->corner[nextInd].x)/2;
101 float closestY = abs(hexagon->corner[i].y+hexagon->corner[nextInd].y)/2;
102 point edge1 = {vertex.x-nextVertex.x,vertex.y-nextVertex.y};
103 float k = vertex.x*edge1.x+vertex.y*edge1.y;
104 if (k>0) {
105 float len = sqrt(edge1.x*edge1.x+edge1.y*edge1.y);
106 k/=len;
107 if (k<len) {
108 if (sqrt(vertex.x*vertex.x+vertex.y*vertex.y - k*k) <= radius) {
109 point c = getIntersection(hexagon->corner[i], hexagon->corner[nextInd], k);
110 point vect{};
111 if (hexagon->corner[i].x < hexagon->corner[nextInd].x)
112 vect = {hexagon->corner[i].x - c.x, hexagon->corner[i].y - c.y};
113 else
114 vect = {hexagon->corner[nextInd].x - c.x, hexagon->corner[nextInd].y - c.y};
115 return {true, vect.x, vect.y};
116 }
117 }
118 }
119 }
120 }
121 else if (const CircleCollider* otherCircle = dynamic_cast<const CircleCollider*>(&other)) {
122 // Collision detection logic for two circles
123 float distanceSquared = (p.x - otherCircle->p.x) * (p.x - otherCircle->p.x) +
124 (p.y - otherCircle->p.y) * (p.y - otherCircle->p.y);
125 float sumOfRadiiSquared = (radius + otherCircle->getRadius()) * (radius + otherCircle->getRadius());
126 if (distanceSquared <= sumOfRadiiSquared) {
127 // Calculate collision point (midpoint between the two circle ps)
128 float collisionX = (p.x + otherCircle->p.x) / 2;
129 float collisionY = (p.y + otherCircle->p.y) / 2;
130 return std::make_tuple(true, collisionX, collisionY);
131 }
132 }
133 // No collision
134 return std::make_tuple(false, 0.0f, 0.0f);
135}
136
137
138std::string CircleCollider::getType() const {
139 return id;
140}
141
143 return radius;
144}
145
146void CircleCollider::render(std::shared_ptr<SDL_Renderer> renderer, SDL_Color color1,SDL_Color color2){
147 SDL_SetRenderDrawColor(renderer.get(), color1.r, color1.g, color1.b, color1.a);
148
149 float x = radius - 1;
150 float y = 0;
151 float dx = 1;
152 float dy = 1;
153 float err = dx - (radius << 1);
154
155 while (x >= y) {
156 SDL_RenderDrawPointF(renderer.get(), p.x + x, p.y + y);
157 SDL_RenderDrawPointF(renderer.get(), p.x + y, p.y + x);
158 SDL_RenderDrawPointF(renderer.get(), p.x - y, p.y + x);
159 SDL_RenderDrawPointF(renderer.get(), p.x - x, p.y + y);
160 SDL_RenderDrawPointF(renderer.get(), p.x - x, p.y - y);
161 SDL_RenderDrawPointF(renderer.get(), p.x - y, p.y - x);
162 SDL_RenderDrawPointF(renderer.get(), p.x + y, p.y - x);
163 SDL_RenderDrawPointF(renderer.get(), p.x + x, p.y - y);
164
165 if (err <= 0) {
166 y++;
167 err += dy;
168 dy += 2;
169 }
170 if (err > 0) {
171 x--;
172 dx += 2;
173 err += dx - (radius << 1);
174 }
175 }
176 SDL_SetRenderDrawColor(renderer.get(), 0, 0, 0, 255);
177}
178
179std::tuple<bool, float, float> RectCollider::collided(const Collider& other) const {
180 if (const RectCollider* otherRect = dynamic_cast<const RectCollider*>(&other)) {
181 bool overlapX = (p.x < otherRect->p.x + otherRect->width) && (p.x + width > other.p.x);
182 bool overlapY = (p.y < otherRect->p.y + otherRect->height) && (p.y + height > other.p.y);
183 if (overlapX && overlapY) {
184 float collisionX = (std::max(p.x, otherRect->p.x) + std::min(p.x + width, otherRect->p.x + otherRect->width)) / 2;
185 float collisionY =
186 (std::max(p.y, otherRect->p.y) + std::min(p.y + height, otherRect->p.y + otherRect->height)) / 2;
187 return std::make_tuple(true, collisionX, collisionY);
188 }
189 } else if (const CircleCollider* otherCircle = dynamic_cast<const CircleCollider*>(&other)) {
190 float closestX = std::clamp(otherCircle->p.x, p.x, p.x + width);
191 float closestY = std::clamp(otherCircle->p.y, p.y, p.y + height);
192
193 float distanceX = otherCircle->p.x - closestX;
194 float distanceY = otherCircle->p.y - closestY;
195
196 float distanceSquared = (distanceX * distanceX) + (distanceY * distanceY);
197 float radiusSquared = otherCircle->getRadius()* otherCircle->getRadius();
198
199 if (distanceSquared < radiusSquared) {
200 // Collision detected
201 // Calculate collision point
202 float collisionX = closestX;
203 float collisionY = closestY;
204 return std::make_tuple(true, collisionX, collisionY);
205 }
206 }
207 return std::make_tuple(false, 0.0f, 0.0f);
208}
209
210std::string RectCollider::getType() const {
211 return id;
212}
213
214void RectCollider::render(std::shared_ptr<SDL_Renderer> renderer, SDL_Color color1,SDL_Color color2) {
215 SDL_Rect rect = { static_cast<int>(p.x), static_cast<int>(p.y), width, height };
216
217
218 SDL_SetRenderDrawColor(renderer.get(), color2.r,color2.g,color2.b,255);
219 SDL_RenderFillRect(renderer.get(), &rect);
220 SDL_SetRenderDrawColor(renderer.get(), color1.r,color1.g,color1.b,255);
221 SDL_RenderDrawRect(renderer.get(),&rect);
222
223 SDL_SetRenderDrawColor(renderer.get(), 0, 0, 0, 255);
224
225}
226
227std::tuple<bool, float, float> TriangleCollider::collided(const Collider &other) const {
228 if (const CircleCollider* circle = dynamic_cast<const CircleCollider*>(&other)) {
229 // TODO: check if the summit are in the circle
230 point vertex1 = {corner[0].x-circle->p.x,corner[0].y-circle->p.y};
231 point vertex2 = {corner[1].x-circle->p.x,corner[1].y-circle->p.y};
232 point vertex3 = {corner[2].x-circle->p.x,corner[2].y-circle->p.y};
233 if (sqrt((vertex1.x*vertex1.x)+(vertex1.y*vertex1.y)) <= circle->getRadius())
234 return {true, vertex1.x, vertex1.y};
235 if (sqrt((vertex2.x*vertex2.x)+(vertex2.y*vertex2.y)) <= circle->getRadius())
236 return {true, vertex2.x, vertex2.y};
237 if (sqrt((vertex3.x*vertex3.x)+(vertex3.y*vertex3.y)) <= circle->getRadius())
238 return {true, vertex3.x, vertex3.y};
239 // TODO: check if the circle intersects edge
240 // merci: https://www.phatcode.net/articles.php?id=459
241 std::cout << "TEST"<< std::endl;
242 }
243 return {false, 0.0f, 0.0f};
244}
245
246std::string TriangleCollider::getType() const {
247 return this->id;
248}
249
250void TriangleCollider::fillTriangle(const std::shared_ptr<SDL_Renderer> &renderer) {
251 auto x1=static_cast<int>(corner[0].x),y1=static_cast<int>(corner[0].y); // coordonnées du sommet
252 auto x2=static_cast<int>(corner[1].x),y2=static_cast<int>(corner[1].y); // coordonnées du coin gauche
253 auto x3=static_cast<int>(corner[2].x),y3=static_cast<int>(corner[2].y); // coordonnées du coin droite
254
255 int pente = (y2-y1)/(x2-x1);
256
257 for (int i=0; i<width/2; i++) {
258 SDL_RenderDrawLine(renderer.get(), x1-i,y1, x1-i,y2);
259 SDL_RenderDrawLine(renderer.get(), x1+i,y1, x1+i,y3);
260 y1-=pente;
261 }
262}
263
264void TriangleCollider::render(std::shared_ptr<SDL_Renderer> renderer, SDL_Color color1,SDL_Color color2) {
265 SDL_SetRenderDrawColor(renderer.get(),color1.r,color1.g,color1.b,255);
266
267 for (int i=0; i<corner.size(); i++) {
268 SDL_RenderDrawLine(renderer.get(),
269 static_cast<int>(corner[i].x),
270 static_cast<int>(corner[i].y),
271 static_cast<int>(corner[(i+1)%corner.size()].x),
272 static_cast<int>(corner[(i+1)%corner.size()].y));
273 }
274 fillTriangle(renderer);
275
276 SDL_SetRenderDrawColor(renderer.get(), 0, 0, 0, 255);
277}
278
279std::tuple<bool, float, float> HexagonCollider::collided(const Collider &other) const {
280 return {false, 0.0f, 0.0f};
281}
282
283std::string HexagonCollider::getType() const {
284 return this->id;
285}
286
287void HexagonCollider::fillHexagon(const std::shared_ptr<SDL_Renderer> &renderer) {
288// draw rectangle that is include in the hexagon
289 int start = p.x-width/4;
290 SDL_Rect hexRect{};
291 hexRect.x=start; hexRect.y=p.y-width/2+2;hexRect.w=width/2;hexRect.h=height;
292 SDL_RenderDrawRect(renderer.get(),&hexRect);
293 SDL_RenderFillRect(renderer.get(),&hexRect);
294
295
296 auto x0=static_cast<int>(corner[0].x),y0=static_cast<int>(corner[0].y);
297 auto x1=static_cast<int>(corner[1].x),y1=static_cast<int>(corner[1].y);
298 auto x2=static_cast<int>(corner[2].x),y2=static_cast<int>(corner[2].y);
299 auto x3=static_cast<int>(corner[3].x),y3=static_cast<int>(corner[3].y);
300 auto x4=static_cast<int>(corner[4].x),y4=static_cast<int>(corner[4].y);
301 auto x5=static_cast<int>(corner[5].x),y5=static_cast<int>(corner[5].y);
302
303 double angle2_3 = (y3-y2)/(x3-x2), angle4_3 = (y4-y3)/(x4-x3);
304 double angle1_0 = (y1-y0)/(x1-x0), angle5_0 = (y5-y0)/(x5-x0);
305
306 int h4=y3,h2=y3;
307
308 // draw the two triangle to fill the rest of the hexagon
309 for (int i=p.x-width/2; i<p.x-width/4; i++) {
310 SDL_RenderDrawLine(renderer.get(), i,h4,i,h2);
311 h4-=(1+angle2_3);
312 h2+=(1+angle2_3);
313 }
314 int h1=y0,h5=y0;
315 for (int i=p.x+width/2; i>p.x+width/4; i--) {
316 SDL_RenderDrawLine(renderer.get(), i,h5,i,h1);
317 h5-=(1+angle5_0);
318 h1+=(1+angle5_0);
319 }
320 SDL_RenderDrawLine(renderer.get(), p.x+width/4,h5+(1+angle5_0),p.x+width/4,h1-(1+angle5_0));
321}
322
323void HexagonCollider::render(std::shared_ptr<SDL_Renderer> renderer, SDL_Color color1,SDL_Color color2) {
324 SDL_SetRenderDrawColor(renderer.get(),color1.r,color1.g,color1.b,color1.a);
325
326 for (int i=0; i<corner.size(); i++) {
327 SDL_RenderDrawLine(renderer.get(),
328 static_cast<int>(corner[i].x),
329 static_cast<int>(corner[i].y),
330 static_cast<int>(corner[(i+1)%corner.size()].x),
331 static_cast<int>(corner[(i+1)%corner.size()].y));
332 }
333 fillHexagon(renderer);
334
335 SDL_SetRenderDrawColor(renderer.get(), 0, 0, 0, 255);
336}
float distance(const point &p1, const point &p2)
point getIntersection(point s1, point s2, int k)
The CircleCollider class represents a circular collider object.
int getRadius() const
Gets the radius of the circular collider.
std::string getType() const override
Gets the type of the collider.
int radius
The radius of the circular collider.
std::tuple< bool, float, float > collided(const Collider &other) const override
Checks for collision with another collider.
void render(std::shared_ptr< SDL_Renderer > renderer, SDL_Color color1, SDL_Color color2) override
Renders the collider on the screen.
The Collider class represents a generic collider object.
void moveTo(point newPoint)
Moves the collider to an absolute position.
std::string id
The unique identifier of the collider.
point p
The position of the collider.
void move(point newPoint)
Moves the collider to a new position.
std::shared_ptr< Collider > collider
The collider associated with the object.
std::shared_ptr< Collider > getCollider()
Gets the collider associated with the object.
The HexagonCollider class represents a hexagonal collider object.
int height
The height of the hexagonal collider.
int width
The width of the hexagonal collider.
void render(std::shared_ptr< SDL_Renderer > renderer, SDL_Color color1, SDL_Color color2) override
Renders the collider on the screen.
std::tuple< bool, float, float > collided(const Collider &other) const override
Checks for collision with another collider.
std::vector< point > corner
The vertices of the hexagonal collider.
void fillHexagon(const std::shared_ptr< SDL_Renderer > &renderer)
Fills the hexagon shape with the current renderer.
std::string getType() const override
Gets the type of the collider.
The RectCollider class represents a rectangular collider object.
int width
The width of the rectangular collider.
std::tuple< bool, float, float > collided(const Collider &other) const override
Checks for collision with another collider.
void render(std::shared_ptr< SDL_Renderer > renderer, SDL_Color color1, SDL_Color color2) override
Renders the collider on the screen.
std::string getType() const override
Gets the type of the collider.
int height
The height of the rectangular collider.
The TriangleCollider class represents a triangular collider object.
std::string getType() const override
Gets the type of the collider.
std::vector< point > corner
The vertices of the triangular collider.
int width
The width of the triangular collider.
void fillTriangle(const std::shared_ptr< SDL_Renderer > &renderer)
Fills the triangle shape with the current renderer.
std::tuple< bool, float, float > collided(const Collider &other) const override
Checks for collision with another collider.
void render(std::shared_ptr< SDL_Renderer > renderer, SDL_Color color1, SDL_Color color2) override
Renders the collider on the screen.
The point struct represents a point in 2D space.
float y
The y-coordinate of the point.
float x
The x-coordinate of the point.