casse-brick latest
Ce projet est réalisé dans le cadre du cours de Programmation Avancée en M1 Informatique de l'université de Strasbourg.
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.