65 lines
2.7 KiB
C++
65 lines
2.7 KiB
C++
// collision.hpp - Utilitats de detecció de colisiones
|
|
// © 2026 JailDesigner
|
|
|
|
#pragma once
|
|
|
|
#include <algorithm>
|
|
|
|
#include "core/entities/entity.hpp"
|
|
#include "core/types.hpp"
|
|
|
|
namespace Physics {
|
|
|
|
// Comprobación genèrica de colisión entre dues entidades
|
|
inline auto checkCollision(const Entities::Entity& a, const Entities::Entity& b, float amplifier = 1.0F) -> bool {
|
|
// Comprovar si ambdós són col·lisionables
|
|
if (!a.isCollidable() || !b.isCollidable()) {
|
|
return false;
|
|
}
|
|
|
|
// Calcular radius combinat (con amplificador per hitbox generós)
|
|
float suma_radis = (a.getCollisionRadius() + b.getCollisionRadius()) * amplifier;
|
|
float suma_radis_sq = suma_radis * suma_radis;
|
|
|
|
// Comprobación distancia al cuadrado (sin sqrt)
|
|
const Vec2& pos_a = a.getCenter();
|
|
const Vec2& pos_b = b.getCenter();
|
|
float dx = pos_a.x - pos_b.x;
|
|
float dy = pos_a.y - pos_b.y;
|
|
float dist_sq = (dx * dx) + (dy * dy);
|
|
|
|
return dist_sq <= suma_radis_sq;
|
|
}
|
|
|
|
// Swept collision: una entitat mòbil (radius r_a) s'ha desplaçat de p0 a p1 aquest
|
|
// frame. Comprova si el segment expandit pel radius conjunt (r_a + radius de b, amb
|
|
// amplificador) toca el cercle de l'entity b. Equival al check discrete quan
|
|
// p0 == p1 (sense moviment). Evita tunneling a velocitats altes.
|
|
inline auto checkCollisionSwept(const Vec2& p0, const Vec2& p1, float r_a, const Entities::Entity& b, float amplifier = 1.0F) -> bool {
|
|
if (!b.isCollidable()) {
|
|
return false;
|
|
}
|
|
const float SUM_R = (r_a + b.getCollisionRadius()) * amplifier;
|
|
const float SUM_R_SQ = SUM_R * SUM_R;
|
|
const Vec2& center_b = b.getCenter();
|
|
const float DX_SEG = p1.x - p0.x;
|
|
const float DY_SEG = p1.y - p0.y;
|
|
const float LEN_SQ = (DX_SEG * DX_SEG) + (DY_SEG * DY_SEG);
|
|
// Degenerat: punt-cercle (frame de spawn, o entitat parada).
|
|
if (LEN_SQ <= 0.0F) {
|
|
const float DX = p0.x - center_b.x;
|
|
const float DY = p0.y - center_b.y;
|
|
return ((DX * DX) + (DY * DY)) <= SUM_R_SQ;
|
|
}
|
|
// Projecció del centre sobre la recta del segment, clamp a [0,1] per acotar al segment.
|
|
const float T_RAW = (((center_b.x - p0.x) * DX_SEG) + ((center_b.y - p0.y) * DY_SEG)) / LEN_SQ;
|
|
const float T_CLAMPED = std::clamp(T_RAW, 0.0F, 1.0F);
|
|
const float CLOSEST_X = p0.x + (DX_SEG * T_CLAMPED);
|
|
const float CLOSEST_Y = p0.y + (DY_SEG * T_CLAMPED);
|
|
const float DX = CLOSEST_X - center_b.x;
|
|
const float DY = CLOSEST_Y - center_b.y;
|
|
return ((DX * DX) + (DY * DY)) <= SUM_R_SQ;
|
|
}
|
|
|
|
} // namespace Physics
|