From 492cb88b82ab0f2cbc7241ce66a0db7db77aab52 Mon Sep 17 00:00:00 2001 From: aozhiwei Date: Tue, 25 Jun 2019 12:19:53 +0800 Subject: [PATCH] add collision --- a8/collision.cc | 213 ++++++++++++++++++++++++++++++++++++++++++++++++ a8/collision.h | 24 ++++++ 2 files changed, 237 insertions(+) create mode 100644 a8/collision.cc create mode 100644 a8/collision.h diff --git a/a8/collision.cc b/a8/collision.cc new file mode 100644 index 0000000..f5ec8a7 --- /dev/null +++ b/a8/collision.cc @@ -0,0 +1,213 @@ +#include + +#include +#include +#include +#include + +#include + +namespace a8 +{ + bool IntersectSegmentCircle(a8::Vec2 p0, a8::Vec2 p1, a8::Vec2 pos, float rad) + { + a8::Vec2 t = p1 - p0; + float d = std::max(t.Norm(), 0.0001f); + a8::Vec2 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(a8::Vec2 p0, a8::Vec2 p1, a8::Vec2 _min, a8::Vec2 _max) + { + a8::Vec2 c = (_min + _max) * 0.5f; + a8::Vec2 e = _max - c; + a8::Vec2 m = (p0 + p1) * 0.5f; + a8::Vec2 d = p1 - m; + m = m - c; + + float adx = std::abs(d.x); + if (std::abs(m.x) > e.x + adx) { + return false; + } + float ady = std::abs(d.y); + if (std::abs(m.y) > e.y + ady) { + return false; + } + if (p0.x > p1.x) { + float tmp = p0.x; + p0.x = p1.x; + p1.x = tmp; + } + if (p0.y > p1.y) { + float tmp = p0.y; + p0.y = p1.y; + p1.y = tmp; + } + return IntersectAabbAabb(p0, p1, _min, _max); + } + + bool IntersectAabbCircle(a8::Vec2 a_min, a8::Vec2 a_max, a8::Vec2 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; + } + a8::Vec2 nearest_point(a8::Clamp(b_pos.x, a_min.x, a_max.x), + a8::Clamp(b_pos.y, a_min.y, a_max.y)); + a8::Vec2 i = b_pos - nearest_point; + float n = a8::LengthSqr(i); + return n < b_rad*b_rad; + } + + bool IntersectAabbAabb(a8::Vec2 a_min, a8::Vec2 a_max, a8::Vec2 b_min, a8::Vec2 b_max) + { + a8::Vec2 a_v = (a_max - a_min) * 0.5f; + a8::Vec2 a_center = a_min + a_v; + a8::Vec2 b_v = (b_max - b_min) * 0.5f; + a8::Vec2 b_center = b_min + b_v; + a8::Vec2 z = b_center - a_center; + float u = a_v.x + b_v.x - std::abs(z.x); + return u > 0; + } + + bool IntersectCircleCircle(a8::Vec2 a_pos, float a_rad, a8::Vec2 b_pos, float b_rad) + { + float t = a_rad + b_rad; + a8::Vec2 d = b_pos - a_pos; + float n = a8::LengthSqr(d); + return n < t*t; + } + + bool CircleContainCircle(a8::Vec2 a_pos, float a_rad, a8::Vec2 b_pos, float b_rad) + { + float distance = (a_pos - b_pos).Norm(); + return distance < a_rad - b_rad; + } + + bool CalcCircleAabbSafePoint(a8::Vec2 a_pos, float b_rad, a8::Vec2 b_min, a8::Vec2 b_max, + a8::Vec2& new_pos) + { + new_pos = a_pos; + bool at_left = std::abs(a_pos.x - b_min.x) < std::abs(a_pos.x - b_max.x); + bool at_down = std::abs(a_pos.y - b_min.y) < std::abs(a_pos.y - b_max.y); + float x_len = at_left ? std::abs(a_pos.x - b_min.x) : std::abs(a_pos.x - b_max.x); + float y_len = at_down ? std::abs(a_pos.y - b_min.y) : std::abs(a_pos.y - b_max.y); + if (at_left) { + if (x_len < y_len) { + //左 + new_pos.x = b_min.x - b_rad - 1; + } else { + if (at_down) { + new_pos.y = b_min.y - b_rad - 1; + } else { + new_pos.y = b_max.y + b_rad + 1; + } + } + } else { + if (x_len < y_len) { + //右 + new_pos.x = b_max.x + b_rad + 1; + } else { + if (at_down) { + new_pos.y = b_min.y - b_rad - 1; + } else { + new_pos.y = b_max.y + b_rad + 1; + } + } + } + return true; + } + + bool CalcCircleCircleSafePoint(a8::Vec2 a_pos, float a_rad, a8::Vec2 b_pos, float b_rad, + a8::Vec2& new_pos) + { + a8::Vec2 dir = a_pos - b_pos; + dir.Normalize(); + new_pos = b_pos + dir*(a_rad + b_rad) + 1; + return true; + } + + bool CalcAabbAabbSafePoint(a8::Vec2 a_min, a8::Vec2 a_max, a8::Vec2 b_min, a8::Vec2 b_max, + a8::Vec2& new_pos) + { + a8::Vec2 a_pos = a_min + (a_max - a_min)/2.0f; + new_pos = a_pos; + bool at_left = std::abs(a_pos.x - b_min.x) < std::abs(a_pos.x - b_max.x); + bool at_down = std::abs(a_pos.y - b_min.y) < std::abs(a_pos.y - b_max.y); + float x_len = at_left ? std::abs(a_pos.x - b_min.x) : std::abs(a_pos.x - b_max.x); + float y_len = at_down ? std::abs(a_pos.y - b_min.y) : std::abs(a_pos.y - b_max.y); + if (at_left) { + if (x_len < y_len) { + //左 + new_pos.x = b_min.x - (a_max.x - a_min.x)/2.0f - 1; + } else { + if (at_down) { + new_pos.y = b_min.y - (a_max.y - a_min.y)/2.0f - 1; + } else { + new_pos.y = b_max.y + (a_max.y - a_min.y)/2.0f + 1; + } + } + } else { + if (x_len < y_len) { + //右 + new_pos.x = b_max.x + (a_max.x - a_min.x)/2.0f + 1; + } else { + if (at_down) { + new_pos.y = b_min.y - (a_max.y - a_min.y)/2.0f - 1; + } else { + new_pos.y = b_max.y + (a_max.y - a_min.y)/2.0f + 1; + } + } + } + return true; + } + + bool CalcAabbCircleSafePoint(a8::Vec2 a_min, a8::Vec2 a_max, a8::Vec2 b_pos, float b_rad, + a8::Vec2& new_pos) + { + a8::Vec2 a_pos = a_min + (a_max - a_min)/2.0f; + new_pos = a_pos; + bool at_left = std::abs(a_min.x - b_pos.x) < std::abs(a_max.x - b_pos.x); + bool at_down = std::abs(a_min.y - b_pos.y) < std::abs(a_max.y - b_pos.y); + float x_len = at_left ? std::abs(a_min.x - b_pos.x) : std::abs(a_max.x - b_pos.x); + float y_len = at_down ? std::abs(a_min.y - b_pos.y) : std::abs(a_max.y - b_pos.y); + if (at_left) { + if (x_len < y_len) { + //左 + new_pos.x = b_pos.x - (a_max.x - a_min.x)/2.0f - 1; + } else { + if (at_down) { + new_pos.y = b_pos.y - (a_max.y - a_min.y)/2.0f - 1; + } else { + new_pos.y = b_pos.y + (a_max.y - a_min.y)/2.0f + 1; + } + } + } else { + if (x_len < y_len) { + //右 + new_pos.x = b_pos.x + (a_max.x - a_min.x)/2.0f + 1; + } else { + if (at_down) { + new_pos.y = b_pos.y - (a_max.y - a_min.y)/2.0f - 1; + } else { + new_pos.y = b_pos.y + (a_max.y - a_min.y)/2.0f + 1; + } + } + } + return true; + } +} diff --git a/a8/collision.h b/a8/collision.h new file mode 100644 index 0000000..128119b --- /dev/null +++ b/a8/collision.h @@ -0,0 +1,24 @@ +#ifndef A8_COLLISION_H +#define A8_COLLISION_H + +#include + +namespace a8 +{ + bool IntersectSegmentCircle(a8::Vec2 p0, a8::Vec2 p1, a8::Vec2 pos, float rad); + bool IntersectSegmentAabb(a8::Vec2 p0, a8::Vec2 p1, a8::Vec2 _min, a8::Vec2 _max); + bool IntersectAabbCircle(a8::Vec2 a_min, a8::Vec2 a_max, a8::Vec2 b_pos, float b_rad); + bool IntersectAabbAabb(a8::Vec2 a_min, a8::Vec2 a_max, a8::Vec2 b_min, a8::Vec2 b_max); + bool IntersectCircleCircle(a8::Vec2 a_pos, float a_rad, a8::Vec2 b_pos, float b_rad); + bool CircleContainCircle(a8::Vec2 a_pos, float a_rad, a8::Vec2 b_pos, float b_rad); + bool CalcCircleAabbSafePoint(a8::Vec2 a_pos, float a_rad, a8::Vec2 b_min, a8::Vec2 b_max, + a8::Vec2& new_pos); + bool CalcCircleCircleSafePoint(a8::Vec2 a_pos, float a_rad, a8::Vec2 b_pos, float b_rad, + a8::Vec2& new_pos); + bool CalcAabbAabbSafePoint(a8::Vec2 a_min, a8::Vec2 a_max, a8::Vec2 b_min, a8::Vec2 b_max, + a8::Vec2& new_pos); + bool CalcAabbCircleSafePoint(a8::Vec2 a_min, a8::Vec2 a_max, a8::Vec2 b_pos, float b_rad, + a8::Vec2& new_pos); +} + +#endif