mirror of
https://github.com/k4zmu2a/SpaceCadetPinball.git
synced 2024-12-24 04:16:23 +01:00
FT collision part4: ball to ball collision.
TBall uses multiple inheritance, interesting.
This commit is contained in:
parent
f521a03322
commit
c5acdcd524
15 changed files with 132 additions and 38 deletions
|
@ -11,7 +11,8 @@
|
|||
#include "TPinballTable.h"
|
||||
#include "TTableLayer.h"
|
||||
|
||||
TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false)
|
||||
TBall::TBall(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, false),
|
||||
TEdgeSegment(this, &ActiveFlag, 0)
|
||||
{
|
||||
visualStruct visual{};
|
||||
char ballGroupName[10]{"ball"};
|
||||
|
@ -22,19 +23,29 @@ TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false)
|
|||
CollisionComp = nullptr;
|
||||
EdgeCollisionCount = 0;
|
||||
TimeDelta = 0.0;
|
||||
CollisionMask = 1;
|
||||
CollisionFlag = 0;
|
||||
Speed = 0.0;
|
||||
Direction.Y = 0.0;
|
||||
Direction.X = 0.0;
|
||||
Position.X = 0.0;
|
||||
Position.Y = 0.0;
|
||||
HasGroupFlag = false;
|
||||
|
||||
ListBitmap = new std::vector<SpriteData>();
|
||||
|
||||
if (groupIndex == -1)
|
||||
{
|
||||
HasGroupFlag = false;
|
||||
Position = {0, 0, 0};
|
||||
CollisionMask = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
HasGroupFlag = true;
|
||||
loader::query_visual(groupIndex, 0, &visual);
|
||||
CollisionMask = visual.CollisionGroup;
|
||||
auto floatArr = loader::query_float_attribute(groupIndex, 0, 408);
|
||||
Position = {floatArr[0], floatArr[1], floatArr[3]};
|
||||
}
|
||||
|
||||
/*Full tilt: ball is ballN, where N[0,2] resolution*/
|
||||
auto groupIndex = loader::query_handle(ballGroupName);
|
||||
groupIndex = loader::query_handle(ballGroupName);
|
||||
if (groupIndex < 0)
|
||||
{
|
||||
ballGroupName[4] = '0' + fullscrn::GetResolution();
|
||||
|
@ -70,7 +81,7 @@ void TBall::Repaint()
|
|||
|
||||
auto pos2D = proj::xform_to_2d(Position);
|
||||
auto zDepth = proj::z_distance(Position);
|
||||
|
||||
|
||||
auto index = 0u;
|
||||
for (; index < ListBitmap->size() - 1; ++index)
|
||||
{
|
||||
|
@ -112,7 +123,7 @@ int TBall::Message(MessageCode code, float value)
|
|||
{
|
||||
if (code == MessageCode::Reset)
|
||||
{
|
||||
SpriteSetBall(-1, { 0,0 }, 0.0f);
|
||||
SpriteSetBall(-1, {0, 0}, 0.0f);
|
||||
Position.X = 0.0;
|
||||
CollisionComp = nullptr;
|
||||
Position.Y = 0.0;
|
||||
|
@ -139,6 +150,47 @@ void TBall::throw_ball(vector3* direction, float angleMult, float speedMult1, fl
|
|||
Speed = (1.0f - (rnd + rnd)) * (speedMult1 * speedMult2) + speedMult1;
|
||||
}
|
||||
|
||||
void TBall::EdgeCollision(TBall* ball, float distance)
|
||||
{
|
||||
ball->AsEdgeCollisionFlag = true;
|
||||
vector2 nextPos{
|
||||
ball->Position.X + ball->Direction.X * distance,
|
||||
ball->Position.Y + ball->Direction.Y * distance
|
||||
},
|
||||
collDir{nextPos.X - Position.X, nextPos.Y - Position.Y};
|
||||
maths::normalize_2d(collDir);
|
||||
vector2 invCollDir{ -collDir.X, -collDir.Y };
|
||||
|
||||
ball->Position.X = nextPos.X;
|
||||
ball->Position.Y = nextPos.Y;
|
||||
ball->Direction.X *= ball->Speed;
|
||||
ball->Direction.Y *= ball->Speed;
|
||||
Direction.X *= Speed;
|
||||
Direction.Y *= Speed;
|
||||
|
||||
auto coef = -maths::DotProduct(ball->Direction, collDir);
|
||||
vector2 v44{collDir.X * coef, collDir.Y * coef};
|
||||
vector2 v13{ball->Direction.X + v44.X, ball->Direction.Y + v44.Y};
|
||||
|
||||
coef = -maths::DotProduct(Direction, invCollDir);
|
||||
vector2 v11{invCollDir.X * coef, invCollDir.Y * coef};
|
||||
vector2 v10{Direction.X + v11.X, Direction.Y + v11.Y};
|
||||
|
||||
ball->Direction.X = -v11.X + v13.X;
|
||||
ball->Direction.Y = -v11.Y + v13.Y;
|
||||
ball->Speed = maths::normalize_2d(ball->Direction);
|
||||
Direction.X = -v44.X + v10.X;
|
||||
Direction.Y = -v44.Y + v10.Y;
|
||||
Speed = maths::normalize_2d(Direction);
|
||||
}
|
||||
|
||||
float TBall::FindCollisionDistance(const ray_type& ray)
|
||||
{
|
||||
// Original inherits TCircle and aliases position.
|
||||
const circle_type ballCircle{{Position.X, Position.Y}, Radius * Radius * 4.0f};
|
||||
return maths::ray_intersect_circle(ray, ballCircle);
|
||||
}
|
||||
|
||||
vector2 TBall::get_coordinates()
|
||||
{
|
||||
return TTableLayer::edge_manager->NormalizeBox(Position);
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
#pragma once
|
||||
#include "maths.h"
|
||||
#include "TPinballComponent.h"
|
||||
#include "TCollisionComponent.h"
|
||||
#include "TEdgeSegment.h"
|
||||
|
||||
class TCollisionComponent;
|
||||
class TEdgeSegment;
|
||||
|
||||
class TBall : public TPinballComponent
|
||||
class TBall : public TCollisionComponent, public TEdgeSegment
|
||||
{
|
||||
public :
|
||||
TBall(TPinballTable* table);
|
||||
TBall(TPinballTable* table, int groupIndex);
|
||||
void Repaint();
|
||||
void not_again(TEdgeSegment* edge);
|
||||
bool already_hit(TEdgeSegment* edge);
|
||||
|
@ -16,6 +14,9 @@ public :
|
|||
vector2 get_coordinates() override;
|
||||
void Disable();
|
||||
void throw_ball(vector3* direction, float angleMult, float speedMult1, float speedMult2);
|
||||
void place_in_grid(RectF* aabb) override {}
|
||||
void EdgeCollision(TBall* ball, float distance) override;
|
||||
float FindCollisionDistance(const ray_type& ray) override;
|
||||
|
||||
vector3 Position{};
|
||||
vector3 PrevPosition{};
|
||||
|
|
|
@ -12,9 +12,9 @@ TCircle::TCircle(TCollisionComponent* collComp, char* activeFlag, unsigned colli
|
|||
Circle.Center = *center;
|
||||
}
|
||||
|
||||
float TCircle::FindCollisionDistance(ray_type* ray)
|
||||
float TCircle::FindCollisionDistance(const ray_type& ray)
|
||||
{
|
||||
return maths::ray_intersect_circle(*ray, Circle);
|
||||
return maths::ray_intersect_circle(ray, Circle);
|
||||
}
|
||||
|
||||
void TCircle::EdgeCollision(TBall* ball, float distance)
|
||||
|
|
|
@ -10,7 +10,7 @@ public:
|
|||
|
||||
TCircle(TCollisionComponent* collComp, char* activeFlag, unsigned int collisionGroup, vector2* center,
|
||||
float radius);
|
||||
float FindCollisionDistance(ray_type* ray) override;
|
||||
float FindCollisionDistance(const ray_type& ray) override;
|
||||
void EdgeCollision(TBall* ball, float distance) override;
|
||||
void place_in_grid(RectF* aabb) override;
|
||||
};
|
||||
|
|
|
@ -76,7 +76,7 @@ int TEdgeManager::TestGridBox(int x, int y, float* distPtr, TEdgeSegment** edgeD
|
|||
for (auto it = edgeBox->EdgeList.rbegin(); it != edgeBox->EdgeList.rend(); ++it)
|
||||
{
|
||||
auto edge = *it;
|
||||
if (!edge->ProcessedFlag && *edge->ActiveFlag && (edge->CollisionGroup & ray->CollisionMask))
|
||||
if (!edge->ProcessedFlag && *edge->ActiveFlagPtr && (edge->CollisionGroup & ray->CollisionMask))
|
||||
{
|
||||
if (!ball->already_hit(edge))
|
||||
{
|
||||
|
@ -84,7 +84,7 @@ int TEdgeManager::TestGridBox(int x, int y, float* distPtr, TEdgeSegment** edgeD
|
|||
*edgePtr = edge;
|
||||
++edgePtr;
|
||||
edge->ProcessedFlag = 1;
|
||||
auto dist = edge->FindCollisionDistance(ray);
|
||||
auto dist = edge->FindCollisionDistance(*ray);
|
||||
if (dist < *distPtr)
|
||||
{
|
||||
*distPtr = dist;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
TEdgeSegment::TEdgeSegment(TCollisionComponent* collComp, char* activeFlag, unsigned collisionGroup)
|
||||
{
|
||||
CollisionComponent = collComp;
|
||||
ActiveFlag = activeFlag;
|
||||
ActiveFlagPtr = activeFlag;
|
||||
CollisionGroup = collisionGroup;
|
||||
ProcessedFlag = 0;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ class TEdgeSegment
|
|||
{
|
||||
public:
|
||||
TCollisionComponent* CollisionComponent;
|
||||
char* ActiveFlag;
|
||||
char* ActiveFlagPtr;
|
||||
char ProcessedFlag;
|
||||
void* WallValue{};
|
||||
unsigned int CollisionGroup;
|
||||
|
@ -26,7 +26,7 @@ public:
|
|||
virtual void EdgeCollision(TBall* ball, float distance) = 0;
|
||||
virtual void port_draw();
|
||||
virtual void place_in_grid(RectF* aabb) = 0;
|
||||
virtual float FindCollisionDistance(ray_type* ray) = 0;
|
||||
virtual float FindCollisionDistance(const ray_type& ray) = 0;
|
||||
|
||||
static TEdgeSegment* install_wall(float* floatArr, TCollisionComponent* collComp, char* activeFlagPtr,
|
||||
unsigned int collisionGroup, float offset, size_t wallValue);
|
||||
|
|
|
@ -104,12 +104,12 @@ void TFlipperEdge::port_draw()
|
|||
set_control_points(CurrentAngle);
|
||||
}
|
||||
|
||||
float TFlipperEdge::FindCollisionDistance(ray_type* ray)
|
||||
float TFlipperEdge::FindCollisionDistance(const ray_type& ray)
|
||||
{
|
||||
ray_type dstRay{};
|
||||
if (ControlPointDirtyFlag)
|
||||
set_control_points(CurrentAngle);
|
||||
auto distance = maths::distance_to_flipper(this, *ray, dstRay);
|
||||
auto distance = maths::distance_to_flipper(this, ray, dstRay);
|
||||
if (distance >= 1e9f)
|
||||
return 1e9f;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ public:
|
|||
vector3* origin, vector3* vecT1, vector3* vecT2, float extendSpeed, float retractSpeed, float collMult,
|
||||
float elasticity, float smoothness);
|
||||
void port_draw() override;
|
||||
float FindCollisionDistance(ray_type* ray) override;
|
||||
float FindCollisionDistance(const ray_type& ray) override;
|
||||
void EdgeCollision(TBall* ball, float distance) override;
|
||||
void place_in_grid(RectF* aabb) override;
|
||||
void set_control_points(float angle);
|
||||
|
|
|
@ -36,9 +36,9 @@ void TLine::Offset(float offset)
|
|||
maths::line_init(Line, X0, Y0, X1, Y1);
|
||||
}
|
||||
|
||||
float TLine::FindCollisionDistance(ray_type* ray)
|
||||
float TLine::FindCollisionDistance(const ray_type& ray)
|
||||
{
|
||||
return maths::ray_intersect_line(*ray, Line);
|
||||
return maths::ray_intersect_line(ray, Line);
|
||||
}
|
||||
|
||||
void TLine::EdgeCollision(TBall* ball, float distance)
|
||||
|
|
|
@ -11,7 +11,7 @@ public:
|
|||
TLine(TCollisionComponent* collCmp, char* activeFlag, unsigned int collisionGroup, float x0, float y0, float x1, float y1);
|
||||
TLine(TCollisionComponent* collCmp, char* activeFlag, unsigned int collisionGroup, const vector2& start, const vector2& end);
|
||||
void Offset(float offset);
|
||||
float FindCollisionDistance(ray_type* ray) override;
|
||||
float FindCollisionDistance(const ray_type& ray) override;
|
||||
void EdgeCollision(TBall* ball, float distance) override;
|
||||
void place_in_grid(RectF* aabb) override;
|
||||
};
|
||||
|
|
|
@ -625,7 +625,7 @@ TBall* TPinballTable::AddBall(float x, float y)
|
|||
{
|
||||
if (BallList.size() >= 20)
|
||||
return nullptr;
|
||||
ball = new TBall(this);
|
||||
ball = new TBall(this, -1);
|
||||
BallList.push_back(ball);
|
||||
}
|
||||
|
||||
|
@ -655,6 +655,16 @@ int TPinballTable::BallCountInRect(const RectF& rect)
|
|||
return count;
|
||||
}
|
||||
|
||||
int TPinballTable::BallCountInRect(const vector2& pos, float margin)
|
||||
{
|
||||
RectF rect{};
|
||||
rect.XMin = pos.X - margin;
|
||||
rect.XMax = pos.X + margin;
|
||||
rect.YMin = pos.Y - margin;
|
||||
rect.YMax = pos.Y + margin;
|
||||
return BallCountInRect(rect);
|
||||
}
|
||||
|
||||
void TPinballTable::EndGame_timeout(int timerId, void* caller)
|
||||
{
|
||||
auto table = static_cast<TPinballTable*>(caller);
|
||||
|
|
|
@ -37,6 +37,7 @@ public:
|
|||
int Message(MessageCode code, float value) override;
|
||||
TBall* AddBall(float x, float y);
|
||||
int BallCountInRect(const RectF& rect);
|
||||
int BallCountInRect(const vector2& pos, float margin);
|
||||
|
||||
static void EndGame_timeout(int timerId, void* caller);
|
||||
static void LightShow_timeout(int timerId, void* caller);
|
||||
|
|
|
@ -33,7 +33,7 @@ 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::time_ticks_remainder = 0;
|
||||
float pb::BallMaxSpeed, pb::BallHalfRadius, pb::ball_collision_dist;
|
||||
float pb::BallMaxSpeed, pb::BallHalfRadius, pb::BallToBallCollisionDistance;
|
||||
bool pb::FullTiltMode = false, pb::FullTiltDemoMode = false, pb::cheat_mode = false, pb::demo_mode = false;
|
||||
std::string pb::DatFileName, pb::BasePath;
|
||||
ImU32 pb::TextBoxColor;
|
||||
|
@ -106,7 +106,7 @@ int pb::init()
|
|||
auto ball = MainTable->BallList.at(0);
|
||||
BallMaxSpeed = ball->Radius * 200.0f;
|
||||
BallHalfRadius = ball->Radius * 0.5f;
|
||||
ball_collision_dist = (ball->Radius + BallHalfRadius) * 2.0f;
|
||||
BallToBallCollisionDistance = (ball->Radius + BallHalfRadius) * 2.0f;
|
||||
|
||||
int red = 255, green = 255, blue = 255;
|
||||
auto fontColor = get_rc_string(Msg::TextBoxColor);
|
||||
|
@ -424,8 +424,7 @@ void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls)
|
|||
auto distance = TTableLayer::edge_manager->FindCollisionDistance(&ray, ball, &edge);
|
||||
if (distance > 0.0f)
|
||||
{
|
||||
// Todo: ball to ball collision
|
||||
//distance = ball_to_ball_collision();
|
||||
distance = BallToBallCollision(ray, *ball, &edge, distance);
|
||||
}
|
||||
if (ball->EdgeCollisionResetFlag)
|
||||
{
|
||||
|
@ -605,9 +604,13 @@ void pb::InputDown(GameInput input)
|
|||
switch (input.Value)
|
||||
{
|
||||
case 'b':
|
||||
if (MainTable->AddBall(6.0f, 7.0f))
|
||||
MainTable->MultiballCount++;
|
||||
break;
|
||||
{
|
||||
vector2 pos{6.0f, 7.0f};
|
||||
if (!MainTable->BallCountInRect(pos, MainTable->CollisionCompOffset * 1.2f) && MainTable->AddBall(
|
||||
pos.X, pos.Y))
|
||||
MainTable->MultiballCount++;
|
||||
break;
|
||||
}
|
||||
case 'h':
|
||||
{
|
||||
high_score_struct entry{{0}, 1000000000};
|
||||
|
@ -754,3 +757,27 @@ void pb::ShowMessageBox(Uint32 flags, LPCSTR title, LPCSTR message)
|
|||
fprintf(flags == SDL_MESSAGEBOX_ERROR ? stderr : stdout, "BL error: %s\n%s\n", title, message);
|
||||
SDL_ShowSimpleMessageBox(flags, title, message, winmain::MainWindow);
|
||||
}
|
||||
|
||||
float pb::BallToBallCollision(const ray_type& ray, const TBall& ball, TEdgeSegment** edge, float collisionDistance)
|
||||
{
|
||||
for (auto curBall : MainTable->BallList)
|
||||
{
|
||||
if (curBall->ActiveFlagPtr && curBall != &ball && (curBall->CollisionMask & ball.CollisionMask) != 0 &&
|
||||
std::abs(curBall->Position.X - ball.Position.X) < BallToBallCollisionDistance &&
|
||||
std::abs(curBall->Position.Y - ball.Position.Y) < BallToBallCollisionDistance)
|
||||
{
|
||||
auto distance = curBall->FindCollisionDistance(ray);
|
||||
if (distance < 1e9f)
|
||||
{
|
||||
distance = std::max(0.0f, distance - 0.002f);
|
||||
if (collisionDistance > distance)
|
||||
{
|
||||
collisionDistance = distance;
|
||||
*edge = curBall;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return collisionDistance;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
#include "high_score.h"
|
||||
|
||||
class TEdgeSegment;
|
||||
struct ray_type;
|
||||
struct GameInput;
|
||||
class TPinballTable;
|
||||
class DatFile;
|
||||
|
@ -43,7 +45,7 @@ class pb
|
|||
public:
|
||||
static int time_ticks;
|
||||
static float time_now, time_next, time_ticks_remainder;
|
||||
static float BallMaxSpeed, BallHalfRadius, ball_collision_dist;
|
||||
static float BallMaxSpeed, BallHalfRadius, BallToBallCollisionDistance;
|
||||
static GameModes game_mode;
|
||||
static bool cheat_mode;
|
||||
static DatFile* record_table;
|
||||
|
@ -81,4 +83,5 @@ public:
|
|||
static void ShowMessageBox(Uint32 flags, LPCSTR title, LPCSTR message);
|
||||
private:
|
||||
static bool demo_mode;
|
||||
static float BallToBallCollision(const ray_type& ray, const TBall& ball, TEdgeSegment** edge, float collisionDistance);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue