From 54f5e96b7c1dd202ffca176f2a002bfd53f100a9 Mon Sep 17 00:00:00 2001 From: aozhiwei Date: Tue, 19 Mar 2019 15:01:46 +0800 Subject: [PATCH] add collision --- server/gameserver/collider.cc | 124 +++++++-------------------------- server/gameserver/collision.cc | 96 +++++++++++++++++++++++++ server/gameserver/collision.h | 7 ++ 3 files changed, 128 insertions(+), 99 deletions(-) create mode 100644 server/gameserver/collision.cc create mode 100644 server/gameserver/collision.h diff --git a/server/gameserver/collider.cc b/server/gameserver/collider.cc index a40011d..15aff08 100644 --- a/server/gameserver/collider.cc +++ b/server/gameserver/collider.cc @@ -1,102 +1,8 @@ #include "precompile.h" -#include -#include - #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; -} +#include "collision.h" bool ColliderComponent::Intersect(ColliderComponent* b) { @@ -105,17 +11,27 @@ bool ColliderComponent::Intersect(ColliderComponent* b) break; case CT_Aabb: { + AabbCollider* a_aabb = (AabbCollider*)this; switch (b->type) { case CT_None: break; case CT_Aabb: { - return IntersectAabbAabb((AabbCollider*)this, (AabbCollider*)b); + AabbCollider* b_aabb = (AabbCollider*)b; + return IntersectAabbAabb(a_aabb->_min, + a_aabb->_max, + b_aabb->_min, + b_aabb->_max + ); } break; case CT_Circle: { - return IntersectAabbCircle((AabbCollider*)this, (CircleCollider*)b); + CircleCollider* b_circle = (CircleCollider*)b; + return IntersectAabbCircle(a_aabb->_min, + a_aabb->_max, + b_circle->pos, + b_circle->rad); } break; } @@ -123,17 +39,27 @@ bool ColliderComponent::Intersect(ColliderComponent* b) break; case CT_Circle: { + CircleCollider* a_circle = (CircleCollider*)this; switch (b->type) { case CT_None: break; case CT_Aabb: { - return IntersectAabbCircle((AabbCollider*)b, (CircleCollider*)this); + AabbCollider* b_aabb = (AabbCollider*)b; + return IntersectAabbCircle(b_aabb->_min, + b_aabb->_max, + a_circle->pos, + a_circle->rad); } break; case CT_Circle: { - return IntersectCircleCircle((CircleCollider*)this, (CircleCollider*)b); + CircleCollider* b_circle = (CircleCollider*)b; + return IntersectCircleCircle( + a_circle->pos, + a_circle->rad, + b_circle->pos, + b_circle->rad); } break; } diff --git a/server/gameserver/collision.cc b/server/gameserver/collision.cc new file mode 100644 index 0000000..014bf10 --- /dev/null +++ b/server/gameserver/collision.cc @@ -0,0 +1,96 @@ +#include "precompile.h" + +#include +#include + +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; +} + +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; +} + +bool IntersectAabbCircle(Vector2D& a_min, Vector2D& a_max, Vector2D& b_pos, float& b_rad) +{ + 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; +} + +bool IntersectAabbAabb(Vector2D& a_min, Vector2D& a_max, Vector2D& b_min, Vector2D& b_max) +{ + 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; +} + +bool IntersectCircleCircle(Vector2D& a_pos, float& a_rad, Vector2D& b_pos, float& b_rad) +{ + float t = a_rad + b_rad; + Vector2D d = b_pos - a_pos; + float n = a8::LengthSqr(d); + return n < t*t; +} diff --git a/server/gameserver/collision.h b/server/gameserver/collision.h new file mode 100644 index 0000000..c36a9c9 --- /dev/null +++ b/server/gameserver/collision.h @@ -0,0 +1,7 @@ +#pragma once + +bool IntersectSegmentCircle(Vector2D& p0, Vector2D& p1, Vector2D& pos, float rad); +bool IntersectSegmentAabb(Vector2D& p0, Vector2D& p1, Vector2D& _min, Vector2D& _max); +bool IntersectAabbCircle(Vector2D& a_min, Vector2D& a_max, Vector2D& b_pos, float& b_rad); +bool IntersectAabbAabb(Vector2D& a_min, Vector2D& a_max, Vector2D& b_min, Vector2D& b_max); +bool IntersectCircleCircle(Vector2D& a_pos, float& a_rad, Vector2D& b_pos, float& b_rad);