FT collision part1: AABB.

This commit is contained in:
Muzychenko Andrey 2022-12-28 08:47:44 +03:00
parent 17f11bd428
commit 2d6f2c14e5
26 changed files with 132 additions and 113 deletions

View File

@ -123,6 +123,10 @@ void DebugOverlay::DrawOverlay()
if (options::Options.DebugOverlayBallDepthGrid)
DrawBallDepthSteps();
// Draw AABB of collision components
if (options::Options.DebugOverlayAabb)
DrawComponentAabb();
// Restore render target
SDL_SetRenderTarget(winmain::Renderer, initialRenderTarget);
SDL_SetRenderDrawColor(winmain::Renderer,
@ -271,6 +275,23 @@ void DebugOverlay::DrawBallDepthSteps()
}
}
void DebugOverlay::DrawComponentAabb()
{
SDL_SetRenderDrawColor(winmain::Renderer, 0, 50, 200, 255);
for (auto cmp : pb::MainTable->ComponentList)
{
auto collCmp = dynamic_cast<TCollisionComponent*>(cmp);
if (collCmp)
{
const auto& aabb = collCmp->AABB;
auto pt1 = proj::xform_to_2d(vector2{ aabb.XMax, aabb.YMax });
auto pt2 = proj::xform_to_2d(vector2{ aabb.XMin, aabb.YMin });
SDL_Rect rect{ pt2.X,pt2.Y, pt1.X - pt2.X , pt1.Y - pt2.Y };
SDL_RenderDrawRect(winmain::Renderer, &rect);
}
}
}
void DebugOverlay::DrawCicleType(circle_type& circle)
{
vector2 linePt{ circle.Center.X + sqrt(circle.RadiusSq), circle.Center.Y };

View File

@ -22,4 +22,5 @@ private:
static void DrawAllSprites();
static void DrawSoundPositions();
static void DrawBallDepthSteps();
static void DrawComponentAabb();
};

View File

@ -29,7 +29,16 @@ void TCircle::EdgeCollision(TBall* ball, float distance)
CollisionComponent->Collision(ball, &nextPosition, &direction, distance, this);
}
void TCircle::place_in_grid()
void TCircle::place_in_grid(RectF* aabb)
{
if(aabb)
{
const auto radius = sqrt(Circle.RadiusSq);
aabb->Merge({
Circle.Center.X + radius, Circle.Center.Y + radius,
Circle.Center.X - radius, Circle.Center.Y - radius
});
}
TTableLayer::edges_insert_circle(&Circle, this, nullptr);
}

View File

@ -12,5 +12,5 @@ public:
float radius);
float FindCollisionDistance(ray_type* ray) override;
void EdgeCollision(TBall* ball, float distance) override;
void place_in_grid() override;
void place_in_grid(RectF* aabb) override;
};

View File

@ -13,6 +13,7 @@ TCollisionComponent::TCollisionComponent(TPinballTable* table, int groupIndex, b
visualStruct visual{};
ActiveFlag = 1;
AABB = { -10000, -10000, 10000, 10000 };
if (GroupName != nullptr)
UnusedBaseFlag = 1;
if (groupIndex <= 0)

View File

@ -1,4 +1,5 @@
#pragma once
#include "maths.h"
#include "TPinballComponent.h"
struct vector2;
@ -15,6 +16,7 @@ public:
float Threshold;
int SoftHitSoundId;
int HardHitSoundId;
RectF AABB;
TCollisionComponent(TPinballTable* table, int groupIndex, bool createWall);
~TCollisionComponent() override;

View File

@ -33,15 +33,10 @@ TEdgeSegment* TEdgeSegment::install_wall(float* floatArr, TCollisionComponent* c
center.Y = floatArr[2];
auto radius = offset + floatArr[3];
auto circle = new TCircle(collComp, activeFlagPtr, collisionGroup, &center, radius);
edge = circle;
if (circle)
{
circle->WallValue = reinterpret_cast<void*>(wallValue);
circle->place_in_grid();
}
circle->WallValue = reinterpret_cast<void*>(wallValue);
circle->place_in_grid(&collComp->AABB);
collComp->EdgeList.push_back(circle);
edge = circle;
break;
}
case wall_type::Line:
@ -51,15 +46,11 @@ TEdgeSegment* TEdgeSegment::install_wall(float* floatArr, TCollisionComponent* c
end.X = floatArr[3];
end.Y = floatArr[4];
auto line = new TLine(collComp, activeFlagPtr, collisionGroup, start, end);
line->WallValue = reinterpret_cast<void*>(wallValue);
line->Offset(offset);
line->place_in_grid(&collComp->AABB);
collComp->EdgeList.push_back(line);
edge = line;
if (line)
{
line->WallValue = reinterpret_cast<void*>(wallValue);
line->Offset(offset);
line->place_in_grid();
collComp->EdgeList.push_back(line);
}
break;
}
default:
@ -99,13 +90,9 @@ TEdgeSegment* TEdgeSegment::install_wall(float* floatArr, TCollisionComponent* c
{
float radius = offset * 1.001f;
auto circle = new TCircle(collComp, activeFlagPtr, collisionGroup, &center, radius);
if (circle)
{
circle->WallValue = reinterpret_cast<void*>(wallValue);
circle->place_in_grid();
collComp->EdgeList.push_back(circle);
}
circle->WallValue = reinterpret_cast<void*>(wallValue);
circle->place_in_grid(&collComp->AABB);
collComp->EdgeList.push_back(circle);
}
}
@ -114,16 +101,12 @@ TEdgeSegment* TEdgeSegment::install_wall(float* floatArr, TCollisionComponent* c
end.X = floatArrPtr[2];
end.Y = floatArrPtr[3];
auto line = new TLine(collComp, activeFlagPtr, collisionGroup, start, end);
line->WallValue = reinterpret_cast<void*>(wallValue);
line->Offset(offset);
line->place_in_grid(&collComp->AABB);
collComp->EdgeList.push_back(line);
edge = line;
if (line)
{
line->WallValue = reinterpret_cast<void*>(wallValue);
line->Offset(offset);
line->place_in_grid();
collComp->EdgeList.push_back(line);
}
prevCenter = center;
}
}

View File

@ -3,6 +3,7 @@
class TBall;
class TCollisionComponent;
struct ray_type;
struct RectF;
enum class wall_type : int
{
@ -24,7 +25,7 @@ public:
virtual void EdgeCollision(TBall* ball, float distance) = 0;
virtual void port_draw();
virtual void place_in_grid() = 0;
virtual void place_in_grid(RectF* aabb) = 0;
virtual float FindCollisionDistance(ray_type* ray) = 0;
static TEdgeSegment* install_wall(float* floatArr, TCollisionComponent* collComp, char* activeFlagPtr,

View File

@ -24,7 +24,7 @@ TFlagSpinner::TFlagSpinner(TPinballTable* table, int groupIndex) : TCollisionCom
auto line = new TLine(this, &ActiveFlag, visual.CollisionGroup, start, end);
if (line)
{
line->place_in_grid();
line->place_in_grid(&AABB);
EdgeList.push_back(line);
}
@ -32,7 +32,7 @@ TFlagSpinner::TFlagSpinner(TPinballTable* table, int groupIndex) : TCollisionCom
PrevCollider = line;
if (line)
{
line->place_in_grid();
line->place_in_grid(&AABB);
EdgeList.push_back(line);
}

View File

@ -39,6 +39,7 @@ TFlipper::TFlipper(TPinballTable* table, int groupIndex) : TCollisionComponent(t
collMult,
Elasticity,
Smoothness);
flipperEdge->place_in_grid(&AABB);
FlipperEdge = flipperEdge;
BmpIndex = 0;

View File

@ -12,7 +12,7 @@ TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsi
vector3* origin, vector3* vecT1, vector3* vecT2, float extendTime, float retractTime,
float collMult, float elasticity, float smoothness): TEdgeSegment(collComp, activeFlag, collisionGroup)
{
vector3 crossProd{}, vecDir1{}, vecDir2{};
vector3 crossProd{}, vecOriginT1{}, vecOriginT2{};
Elasticity = elasticity;
Smoothness = smoothness;
@ -31,20 +31,21 @@ TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsi
CircleT1RadiusMSq = CircleT1Radius * 1.01f * (CircleT1Radius * 1.01f);
CircleT1RadiusSq = CircleT1Radius * CircleT1Radius;
vecDir1.X = vecT1->X - origin->X;
vecDir1.Y = vecT1->Y - origin->Y;
vecDir1.Z = 0.0;
maths::normalize_2d(vecDir1);
vecOriginT1.X = vecT1->X - origin->X;
vecOriginT1.Y = vecT1->Y - origin->Y;
vecOriginT1.Z = 0.0;
maths::normalize_2d(vecOriginT1);
vecDir2.X = vecT2->X - origin->X;
vecDir2.Y = vecT2->Y - origin->Y;
vecDir2.Z = 0.0;
maths::normalize_2d(vecDir2);
vecOriginT2.X = vecT2->X - origin->X;
vecOriginT2.Y = vecT2->Y - origin->Y;
vecOriginT2.Z = 0.0;
maths::normalize_2d(vecOriginT2);
AngleMax = acos(maths::DotProduct(vecDir1, vecDir2));
maths::cross(vecDir1, vecDir2, crossProd);
AngleMax = acos(maths::DotProduct(vecOriginT1, vecOriginT2));
maths::cross(vecOriginT1, vecOriginT2, crossProd);
if (crossProd.Z < 0.0f)
AngleMax = -AngleMax;
FlipperFlag = MessageCode::TFlipperNull;
AngleDst = 0.0;
@ -60,19 +61,17 @@ TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsi
ExtendTime = extendTime;
RetractTime = retractTime;
auto dirX1 = vecDir1.X;
auto dirY1 = -vecDir1.Y;
A2Src.X = dirY1 * CirclebaseRadius + origin->X;
A2Src.Y = dirX1 * CirclebaseRadius + origin->Y;
A1Src.X = dirY1 * CircleT1Radius + vecT1->X;
A1Src.Y = dirX1 * CircleT1Radius + vecT1->Y;
const vector2 perpOriginT1Cc = { -vecOriginT1.Y , vecOriginT1.X };
A2Src.X = perpOriginT1Cc.X * CirclebaseRadius + origin->X;
A2Src.Y = perpOriginT1Cc.Y * CirclebaseRadius + origin->Y;
A1Src.X = perpOriginT1Cc.X * CircleT1Radius + vecT1->X;
A1Src.Y = perpOriginT1Cc.Y * CircleT1Radius + vecT1->Y;
dirX1 = -dirX1;
dirY1 = -dirY1;
B1Src.X = dirY1 * CirclebaseRadius + origin->X;
B1Src.Y = dirX1 * CirclebaseRadius + origin->Y;
B2Src.X = dirY1 * CircleT1Radius + vecT1->X;
B2Src.Y = dirX1 * CircleT1Radius + vecT1->Y;
const vector2 perpOriginT1C = { vecOriginT1.Y , -vecOriginT1.X };
B1Src.X = perpOriginT1C.X * CirclebaseRadius + origin->X;
B1Src.Y = perpOriginT1C.Y * CirclebaseRadius + origin->Y;
B2Src.X = perpOriginT1C.X * CircleT1Radius + vecT1->X;
B2Src.Y = perpOriginT1C.Y * CircleT1Radius + vecT1->Y;
if (AngleMax < 0.0f)
{
@ -89,7 +88,6 @@ TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsi
auto distance = maths::Distance(*vecT1, *vecT2);
CollisionTimeAdvance = minMoveTime / (distance / CircleT1Radius + distance / CircleT1Radius);
TFlipperEdge::place_in_grid();
EdgeCollisionFlag = 0;
InputTime = 0.0;
CollisionFlag1 = 0;
@ -349,46 +347,19 @@ void TFlipperEdge::EdgeCollision(TBall* ball, float distance)
maths::basic_collision(ball, &NextBallPosition, &CollisionDirection, elasticity, Smoothness, 1000000000.0, 0.0);
}
void TFlipperEdge::place_in_grid()
void TFlipperEdge::place_in_grid(RectF* aabb)
{
float x0 = RotOrigin.X - CirclebaseRadius;
float y0 = RotOrigin.Y - CirclebaseRadius;
float x1 = RotOrigin.X + CirclebaseRadius;
float y1 = RotOrigin.Y + CirclebaseRadius;
auto xMax = std::max(std::max(T2Src.X + CircleT1Radius, T1Src.X + CircleT1Radius), RotOrigin.X + CirclebaseRadius);
auto yMax = std::max(std::max(T2Src.Y + CircleT1Radius, T1Src.Y + CircleT1Radius), RotOrigin.Y + CirclebaseRadius);
auto xMin = std::min(std::min(T2Src.X - CircleT1Radius, T1Src.X - CircleT1Radius), RotOrigin.X - CirclebaseRadius);
auto yMin = std::min(std::min(T2Src.Y - CircleT1Radius, T1Src.Y - CircleT1Radius), RotOrigin.Y - CirclebaseRadius);
float v2 = T1Src.X - CircleT1Radius;
if (v2 < x0)
x0 = v2;
if (aabb)
{
aabb->Merge({xMax, yMax, xMin, yMin});
}
float v3 = T1Src.Y - CircleT1Radius;
if (v3 < y0)
y0 = v3;
float v4 = T1Src.X + CircleT1Radius;
if (v4 > x1)
x1 = v4;
float v5 = T1Src.Y + CircleT1Radius;
if (v5 > y1)
y1 = v5;
float v6 = T2Src.X - CircleT1Radius;
if (v6 < x0)
x0 = v6;
float v7 = T2Src.Y - CircleT1Radius;
if (v7 < y0)
y0 = v7;
float v8 = T2Src.X + CircleT1Radius;
if (v8 > x1)
x1 = v8;
float v9 = T2Src.Y + CircleT1Radius;
if (v9 > y1)
y1 = v9;
TTableLayer::edges_insert_square(y0, x0, y1, x1, this, nullptr);
TTableLayer::edges_insert_square(yMin, xMin, yMax, xMax, this, nullptr);
}
void TFlipperEdge::set_control_points(float timeNow)

View File

@ -14,7 +14,7 @@ public:
void port_draw() override;
float FindCollisionDistance(ray_type* ray) override;
void EdgeCollision(TBall* ball, float distance) override;
void place_in_grid() override;
void place_in_grid(RectF* aabb) override;
void set_control_points(float timeNow);
float flipper_angle(float timeNow);
int is_ball_inside(float x, float y);

View File

@ -35,7 +35,7 @@ THole::THole(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
Circle.RadiusSq);
if (tCircle)
{
tCircle->place_in_grid();
tCircle->place_in_grid(&AABB);
EdgeList.push_back(tCircle);
}

View File

@ -39,7 +39,7 @@ TKickout::TKickout(TPinballTable* table, int groupIndex, bool someFlag): TCollis
reinterpret_cast<vector3*>(visual.FloatArr), Circle.RadiusSq);
if (tCircle)
{
tCircle->place_in_grid();
tCircle->place_in_grid(&AABB);
EdgeList.push_back(tCircle);
}

View File

@ -51,8 +51,16 @@ void TLine::EdgeCollision(TBall* ball, float distance)
this);
}
void TLine::place_in_grid()
void TLine::place_in_grid(RectF* aabb)
{
if (aabb)
{
aabb->Merge({
std::max(X0, X1), std::max(Y0, Y1),
std::min(X0, X1), std::min(Y0, Y1)
});
}
auto edgeMan = TTableLayer::edge_manager;
auto xBox0 = edgeMan->box_x(X0);
auto yBox0 = edgeMan->box_y(Y0);

View File

@ -13,5 +13,5 @@ public:
void Offset(float offset);
float FindCollisionDistance(ray_type* ray) override;
void EdgeCollision(TBall* ball, float distance) override;
void place_in_grid() override;
void place_in_grid(RectF* aabb) override;
};

View File

@ -25,7 +25,7 @@ TOneway::TOneway(TPinballTable* table, int groupIndex) : TCollisionComponent(tab
if (line)
{
line->Offset(table->CollisionCompOffset);
line->place_in_grid();
line->place_in_grid(&AABB);
EdgeList.push_back(line);
}
@ -34,7 +34,7 @@ TOneway::TOneway(TPinballTable* table, int groupIndex) : TCollisionComponent(tab
if (line)
{
line->Offset(-table->CollisionCompOffset * 0.8f);
Line->place_in_grid();
Line->place_in_grid(&AABB);
EdgeList.push_back(Line);
}
}

View File

@ -33,7 +33,7 @@ TRamp::TRamp(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
auto wall0Pts = reinterpret_cast<wall_point_type*>(wall0Arr + 2);
Line1 = new TLine(this, &ActiveFlag, wall0CollisionGroup, wall0Pts->Pt1, wall0Pts->Pt0);
Line1->WallValue = nullptr;
Line1->place_in_grid();
Line1->place_in_grid(&AABB);
EdgeList.push_back(Line1);
auto wall1Arr = loader::query_float_attribute(groupIndex, 0, 1301);
@ -49,7 +49,7 @@ TRamp::TRamp(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
Line2 = new TLine(this, &ActiveFlag, CollisionGroup, wall1Start, wall1End);
Line2->WallValue = nullptr;
Line2->place_in_grid();
Line2->place_in_grid(&AABB);
EdgeList.push_back(Line2);
auto wall2Arr = loader::query_float_attribute(groupIndex, 0, 1302);
@ -65,7 +65,7 @@ TRamp::TRamp(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
Line3 = new TLine(this, &ActiveFlag, CollisionGroup, wall2Start, wall2End);
Line3->WallValue = nullptr;
Line3->place_in_grid();
Line3->place_in_grid(&AABB);
EdgeList.push_back(Line3);
@ -105,7 +105,7 @@ TRamp::TRamp(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
{
auto line = new TLine(this, &ActiveFlag, collisionGroup, point1, point2);
line->WallValue = &plane;
line->place_in_grid();
line->place_in_grid(&AABB);
EdgeList.push_back(line);
}
}

View File

@ -91,7 +91,7 @@ TTableLayer::TTableLayer(TPinballTable* table): TCollisionComponent(table, -1, f
edgePoints[i + 1].Y,
edgePoints[i].X,
edgePoints[i].Y);
line->place_in_grid();
line->place_in_grid(&AABB);
EdgeList.push_back(line);
}

View File

@ -5,6 +5,14 @@
#include "TFlipperEdge.h"
void RectF::Merge(RectF aabb)
{
XMax = std::max(XMax, aabb.XMax);
YMax = std::max(YMax, aabb.YMax);
XMin = std::min(XMin, aabb.XMin);
YMin = std::min(YMin, aabb.YMin);
}
// Performs AABB merge, creating rect that is just large enough to contain both source rects.
void maths::enclosing_box(const rectangle_type& rect1, const rectangle_type& rect2, rectangle_type& dstRect)
{

View File

@ -88,6 +88,8 @@ struct ramp_plane_type
struct RectF
{
float XMax, YMax, XMin, YMin;
void Merge(RectF aabb);
};
enum class FlipperIntersect

View File

@ -118,6 +118,7 @@ void options::InitPrimary()
translations::SetCurrentLanguage(get_string("Language", translations::GetCurrentLanguage()->ShortName).c_str());
Options.FontFileName = get_string("FontFileName", "");
Options.DebugOverlayBallDepthGrid = get_int("Debug Overlay Ball Depth Grid", true);
Options.DebugOverlayAabb = get_int("Debug Overlay AABB", true);
}
void options::InitSecondary()
@ -169,6 +170,7 @@ void options::uninit()
set_string("Language", translations::GetCurrentLanguage()->ShortName);
set_string("FontFileName", Options.FontFileName.c_str());
set_int("Debug Overlay Ball Depth Grid", Options.DebugOverlayBallDepthGrid);
set_int("Debug Overlay AABB", Options.DebugOverlayAabb);
}

View File

@ -93,6 +93,7 @@ struct optionsStruct
bool DebugOverlaySprites;
bool DebugOverlaySounds;
bool DebugOverlayBallDepthGrid;
bool DebugOverlayAabb;
std::string FontFileName;
};

View File

@ -32,7 +32,8 @@ TPinballTable* pb::MainTable = nullptr;
DatFile* pb::record_table = nullptr;
int pb::time_ticks = 0;
GameModes pb::game_mode = GameModes::GameOver;
float pb::time_now = 0, pb::time_next = 0, pb::ball_speed_limit, pb::time_ticks_remainder = 0;
float pb::time_now = 0, pb::time_next = 0, pb::time_ticks_remainder = 0;
float pb::ball_speed_limit, pb::ball_min_smth, pb::ball_inv_smth, pb::ball_collision_dist;
bool pb::FullTiltMode = false, pb::FullTiltDemoMode = false, pb::cheat_mode = false, pb::demo_mode = false;
std::string pb::DatFileName, pb::BasePath;
ImU32 pb::TextBoxColor;
@ -102,7 +103,11 @@ int pb::init()
MainTable = new TPinballTable();
high_score::read();
ball_speed_limit = MainTable->BallList.at(0)->Offset * 200.0f;
auto ball = MainTable->BallList.at(0);
ball_speed_limit = ball->Offset * 200.0f;
ball_min_smth = ball->Offset * 0.5f;
ball_inv_smth = 1.0f / ball_min_smth;
ball_collision_dist = (ball->Offset + ball_min_smth) * 2.0f;
int red = 255, green = 255, blue = 255;
auto fontColor = get_rc_string(Msg::TextBoxColor);

View File

@ -42,7 +42,8 @@ class pb
{
public:
static int time_ticks;
static float ball_speed_limit, time_now, time_next, time_ticks_remainder;
static float time_now, time_next, time_ticks_remainder;
static float ball_speed_limit, ball_min_smth, ball_inv_smth, ball_collision_dist;
static GameModes game_mode;
static bool cheat_mode;
static DatFile* record_table;

View File

@ -732,6 +732,8 @@ void winmain::RenderUi()
Options.DebugOverlaySprites ^= true;
if (ImGui::MenuItem("All Edges", nullptr, Options.DebugOverlayAllEdges))
Options.DebugOverlayAllEdges ^= true;
if (ImGui::MenuItem("Component AABB", nullptr, Options.DebugOverlayAabb))
Options.DebugOverlayAabb ^= true;
if (ImGui::MenuItem("Ball Position", nullptr, Options.DebugOverlayBallPosition))
Options.DebugOverlayBallPosition ^= true;
if (ImGui::MenuItem("Ball Box Edges", nullptr, Options.DebugOverlayBallEdges))