Test collision system for TestGame

This commit is contained in:
2025-06-12 14:39:40 -05:00
parent 397de3bc86
commit 2e4e8b20a7
10 changed files with 472 additions and 5 deletions

View File

@@ -365,7 +365,7 @@ void EditorApp::CreateWidgets()
});
file->AddButton("Open");
file->AddButton("Save", [this]{SaveTestFile();});
file->AddButton("Save", [this]{SaveCurrentLevel();});
file->AddButton("Save As");
file->AddSeparator(2_px);
file->AddButton("About", [this]{app_info_dialog->Toggle(); });

222
src/SimpleAABBSolver.cpp Normal file
View File

@@ -0,0 +1,222 @@
#include <SimpleAABBSolver.hpp>
namespace Solver {
LineSegTestResult LineSegment2DvsAABB2D(Vector2 linesegA,
Vector2 linesegB, Vector2 rectCenter, Vector2 rectSize)
{
LineSegment2D seg = LineSegment2D(linesegA, linesegB);
AABB2D aabb = AABB2D(rectCenter-rectSize, rectCenter+rectSize);
return LineSegment2DvsAABB2D(seg, aabb);
}
LineSegTestResult LineSegment2DvsAABB2D(LineSegment2D seg, AABB2D rect)
{
Vector2 intersection = Vector2::Zero;
Face collidingface = TOP;
Vector2 rect_top_left = rect.minPoint;
Vector2 rect_bottom_right = rect.maxPoint;
Vector2 rect_bottom_left = {rect.minPoint.x, rect.maxPoint.y};
Vector2 rect_top_right = {rect.maxPoint.x, rect.minPoint.y};
LineSegment2D rect_top = {rect_top_left, rect_top_right};
LineSegment2D rect_left = {rect_top_left, rect_bottom_left};
LineSegment2D rect_bottom = {rect_bottom_left, rect_bottom_right};
LineSegment2D rect_right = {rect_top_right, rect_bottom_right};
auto top_hits = LineSegment2Dvs(seg, rect_top);
auto bottom_hits = LineSegment2Dvs(seg, rect_bottom);
auto left_hits = LineSegment2Dvs(seg, rect_top);
auto right_hits = LineSegment2Dvs(seg, rect_right);
if (top_hits.intersects || bottom_hits.intersects || right_hits.intersects || left_hits.intersects)
{
intersection = seg.B;
if (top_hits.intersects && seg.A.Distance(top_hits.intersection) < seg.A.Distance(intersection))
return {true, top_hits.intersection, TOP};
if (bottom_hits.intersects && seg.A.Distance(bottom_hits.intersection) < seg.A.Distance(intersection))
return {true, bottom_hits.intersection, BOTTOM};
if (left_hits.intersects && seg.A.Distance(left_hits.intersection) < seg.A.Distance(intersection))
return {true, left_hits.intersection, LEFT};
if (right_hits.intersects && seg.A.Distance(right_hits.intersection) < seg.A.Distance(intersection))
return {true, left_hits.intersection, RIGHT};
}
return {false};
}
LineSegTestResult LineSegment2Dvs(Vector2 a1, Vector2 a2, Vector2 b1,Vector2 b2)
{
Vector2 b = a2 - a1;
Vector2 d = b2 - b1;
float bDotDPerp = b.x * d.y - b.y * d.x;
// If b dot d == 0, it means that the lines are parallel, and have infinite intersection points.
if (bDotDPerp == 0.f)
return {false};
Vector2 c = b1 - a1;
float t = (c.x * d.y - c.y * d.x) / bDotDPerp;
if (t < 0.f || t > 1.f)
return {false};
float u = (c.x * b.y - c.y * b.x) / bDotDPerp;
if (u < 0.f || u > 1.f)
return {false};
return {true, a1+t*b};
}
LineSegTestResult LineSegment2Dvs(LineSegment2D s1, LineSegment2D s2)
{
return LineSegment2Dvs(s1.A, s1.B, s2.A, s2.B);
}
bool AABB2Dvs(const Vector2& posA, const Vector2& sizeA, const Vector2& posB,
const Vector2& sizeB)
{
float absDistanceX = J3ML::Math::Abs(posA.x - posB.x);
float absDistanceY = J3ML::Math::Abs(posA.y - posB.y);
float sumWidth = sizeA.x + sizeB.x;
float sumHeight = sizeA.y + sizeB.y;
if (absDistanceY >= sumHeight || absDistanceX >= sumWidth)
return false;
return true;
}
bool AABB2Dvs(const AABB2D& a, const AABB2D& b)
{
Vector2 posA = a.minPoint + Vector2(a.Width()/2.f, a.Height()/2.f);
Vector2 posB = b.minPoint + Vector2(b.Width()/2.f, b.Height()/2.f);
Vector2 sizeA = Vector2{a.Width(), a.Height()} / 2.f;
Vector2 sizeB = Vector2{b.Width(), b.Height()} / 2.f;
return AABB2Dvs(posA, sizeA, posB, sizeB);
}
Vector2 SolveAABB(const Vector2& posA, const Vector2& sizeA, const Vector2& posB,
const Vector2& sizeB)
{
float distanceX = posA.x - posB.x;
float distanceY = posA.y - posB.y;
float absDistanceX = J3ML::Math::Abs(distanceX);
float absDistanceY = J3ML::Math::Abs(distanceY);
float sumWidth = sizeA.x + sizeB.x;
float sumHeight = sizeA.y + sizeB.y;
float sx = sumWidth - absDistanceX;
float sy = sumHeight - absDistanceY;
if (sx > sy)
{
if (sy > 0)
sx = 0;
} else {
if (sx > 0)
sy = 0;
}
if (distanceX < 0)
{
sx = -sx;
}
if (distanceY < 0)
sy = -sy;
return {sx, sy};
}
Vector2 GetNormalForAABB(const Vector2& separation, const Vector2& velocity)
{
float d = J3ML::Math::Sqrt(separation.x * separation.x + separation.y * separation.y);
float nx = separation.x / d;
float ny = separation.y / d;
float ps = velocity.x * nx + velocity.y * ny;
if (ps <= 0)
return {nx, ny};
return {0, 0};
}
Vector2 SolveAABB(const AABB2D& a, const AABB2D& b)
{
Vector2 posA = a.minPoint + Vector2(a.Width()/2.f, a.Height()/2.f);
Vector2 posB = a.minPoint + Vector2(b.Width()/2.f, b.Height()/2.f);
Vector2 sizeA = Vector2{a.Width(), a.Height()} / 2.f;
Vector2 sizeB = Vector2{b.Width(), b.Height()} / 2.f;
return SolveAABB(posA, sizeA, posB, sizeB);
}
bool AABB2DvsPoint(const Vector2 &pos, const Vector2 &size, const Vector2 &point) {
float absDistanceX = J3ML::Math::Abs(pos.x - point.x);
float absDistanceY = J3ML::Math::Abs(pos.y - point.y);
float sumWidth = size.x;
float sumHeight = size.y;
if (absDistanceY >= sumHeight || absDistanceX >= sumWidth)
return false;
return true;
}
bool AABB2DvsPoint(const AABB2D &box, const Vector2 &point) {
Vector2 pos = box.minPoint + Vector2(box.Width()/2.f, box.Height()/2.f);
Vector2 size = Vector2{box.Width(), box.Height()} / 2.f;
return AABB2DvsPoint(pos, size, point);
}
Vector2 SolveAABBvsPoint(const Vector2 &pos, const Vector2 &size, const Vector2 &point) {
float distanceX = pos.x - point.x;
float distanceY = pos.y - point.y;
float absDistanceX = J3ML::Math::Abs(distanceX);
float absDistanceY = J3ML::Math::Abs(distanceY);
float sumWidth = size.x;
float sumHeight = size.y;
float sx = sumWidth - absDistanceX;
float sy = sumHeight - absDistanceY;
if (sx > sy)
{
if (sy > 0)
sx = 0;
} else {
if (sx > 0)
sy = 0;
}
if (distanceX < 0)
{
sx = -sx;
}
if (distanceY < 0)
sy = -sy;
return {sx, sy};
}
}