game2001/server/gameserver/collider.cc
aozhiwei 285250d83f 1
2019-03-19 14:38:49 +08:00

145 lines
3.6 KiB
C++

#include "precompile.h"
#include <algorithm>
#include<cfloat>
#include "entity.h"
#include "collider.h"
static bool IntersectSegmentCircle(Vector2D& p0, Vector2D& p1, Vector2D& pos, float rad)
{
Vector2D t = p1 - p0;
float d = std::max(t.Norm(), 0.0001f);
Vector2D n = p0 - pos;
float v = n.Dot(t);
float z = n.Dot(n) - rad*rad;
if (z > 0 && v > 0) {
return false;
}
float u = v*v - z;
if (u < 0) {
return false;
}
float i = sqrt(u);
float x = -v - i;
if (x < 0 && (x = -v + i), x <= d) {
return true;
}
return false;
}
static bool IntersectSegmentAabb(Vector2D& p0, Vector2D& p1, Vector2D& _min, Vector2D& _max)
{
float t = 0.0f;
float d = FLT_MAX;
Vector2D n = p0;
Vector2D v = p1 - p0;
float z = v.Norm();
v = z > (float)1e-5 ? v / z : Vector2D(1, 0);
if (std::abs(v.x) < (float)1e-5) {
v.x = float(2e-5);
}
if (std::abs(v.y) < (float)1e-5) {
v.y = (float)2e-5;
}
if (std::abs(v.x) > (float)1e-5) {
float u = (_min.x - n.x) / v.x;
float i = (_max.x - n.x) / v.x;
t = std::max(t, std::min(u, i));
d = std::min(d, std::max(u, i));
if (t > d) {
return false;
}
}
if (std::abs(v.y) > (float)1e-5) {
float x = (_min.y - n.y) / v.y;
float l = (_max.y - n.y) / v.y;
t = std::max(t, std::min(x, l));
d = std::min(d, std::max(x, l));
if (t > d) {
return false;
}
}
if (t > z) {
return false;
}
return true;
}
static bool IntersectAabbCircle(AabbCollider* a, CircleCollider* b)
{
if (b->pos.x >= a->_min.x && b->pos.x <= a->_max.x &&
b->pos.y >= a->_min.y && b->pos.y <= a->_max.y) {
return true;
}
Vector2D nearest_point(a8::Clamp(b->pos.x, a->_min.x, a->_max.y),
a8::Clamp(b->pos.y, a->_min.y, a->_max.y));
Vector2D i = b->pos - nearest_point;
float n = a8::LengthSqr(i);
return n < b->rad*b->rad;
}
static bool IntersectAabbAabb(AabbCollider* a, AabbCollider* b)
{
Vector2D a_v = (a->_max - a->_min) * 0.5f;
Vector2D a_center = a->_min + a_v;
Vector2D b_v = (b->_max - b->_min) * 0.5f;
Vector2D b_center = b->_min + b_v;
Vector2D z = b_center - a_center;
float u = a_v.x + b_v.x - std::abs(z.x);
return u > 0;
}
static bool IntersectCircleCircle(CircleCollider* a, CircleCollider* b)
{
float t = a->rad + b->rad;
Vector2D d = b->pos - a->pos;
float n = a8::LengthSqr(d);
return n < t*t;
}
bool ColliderComponent::Intersect(ColliderComponent* b)
{
switch (type) {
case CT_None:
break;
case CT_Aabb:
{
switch (b->type) {
case CT_None:
break;
case CT_Aabb:
{
return IntersectAabbAabb((AabbCollider*)this, (AabbCollider*)b);
}
break;
case CT_Circle:
{
return IntersectAabbCircle((AabbCollider*)this, (CircleCollider*)b);
}
break;
}
};
break;
case CT_Circle:
{
switch (b->type) {
case CT_None:
break;
case CT_Aabb:
{
return IntersectAabbCircle((AabbCollider*)b, (CircleCollider*)this);
}
break;
case CT_Circle:
{
return IntersectCircleCircle((CircleCollider*)this, (CircleCollider*)b);
}
break;
}
}
break;
}
return false;
}