mirror of
https://github.com/k4zmu2a/SpaceCadetPinball.git
synced 2024-12-18 10:37:53 +01:00
FT collision part2: added most of the FT collision system.
Aka "World's most expensive flippers". This is an aggregate of collision-related changes made during 3DPB->FT transition. The most important part is in flipper collision - a shift from monolithic iterative solver in TFlipperEdge::EdgeCollision to a distributed non-iterative solver. Both 3DPB and FT data sets use FT collision, keeping two collision systems does not make much sense. From user perspective, FT/3DPB systems should not have any major differences.
This commit is contained in:
parent
466c875f8a
commit
ba470e8727
16 changed files with 489 additions and 396 deletions
|
@ -344,10 +344,11 @@ void DebugOverlay::DrawEdge(TEdgeSegment* edge)
|
||||||
auto flip = dynamic_cast<TFlipperEdge*>(edge);
|
auto flip = dynamic_cast<TFlipperEdge*>(edge);
|
||||||
if (flip)
|
if (flip)
|
||||||
{
|
{
|
||||||
flip->set_control_points(pb::time_now);
|
if (flip->ControlPointDirtyFlag)
|
||||||
|
flip->set_control_points(flip->CurrentAngle);
|
||||||
|
|
||||||
DrawLineType(flip->lineA);
|
DrawLineType(flip->LineA);
|
||||||
DrawLineType(flip->lineB);
|
DrawLineType(flip->LineB);
|
||||||
DrawCicleType(flip->circlebase);
|
DrawCicleType(flip->circlebase);
|
||||||
DrawCicleType(flip->circleT1);
|
DrawCicleType(flip->circleT1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false)
|
||||||
Direction.X = 0.0;
|
Direction.X = 0.0;
|
||||||
Position.X = 0.0;
|
Position.X = 0.0;
|
||||||
Position.Y = 0.0;
|
Position.Y = 0.0;
|
||||||
|
HasGroupFlag = false;
|
||||||
|
|
||||||
ListBitmap = new std::vector<SpriteData>();
|
ListBitmap = new std::vector<SpriteData>();
|
||||||
|
|
||||||
|
@ -81,11 +82,19 @@ void TBall::Repaint()
|
||||||
|
|
||||||
void TBall::not_again(TEdgeSegment* edge)
|
void TBall::not_again(TEdgeSegment* edge)
|
||||||
{
|
{
|
||||||
if (EdgeCollisionCount < 5)
|
if (EdgeCollisionCount < 16)
|
||||||
{
|
{
|
||||||
Collisions[EdgeCollisionCount] = edge;
|
Collisions[EdgeCollisionCount] = edge;
|
||||||
++EdgeCollisionCount;
|
++EdgeCollisionCount;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
Collisions[i] = Collisions[i + 8];
|
||||||
|
Collisions[8] = edge;
|
||||||
|
EdgeCollisionCount = 9;
|
||||||
|
}
|
||||||
|
EdgeCollisionResetFlag = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TBall::already_hit(TEdgeSegment* edge)
|
bool TBall::already_hit(TEdgeSegment* edge)
|
||||||
|
@ -119,15 +128,15 @@ int TBall::Message(MessageCode code, float value)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TBall::throw_ball(TBall* ball, vector3* direction, float angleMult, float speedMult1, float speedMult2)
|
void TBall::throw_ball(vector3* direction, float angleMult, float speedMult1, float speedMult2)
|
||||||
{
|
{
|
||||||
ball->CollisionComp = nullptr;
|
CollisionComp = nullptr;
|
||||||
ball->Direction = *direction;
|
Direction = *direction;
|
||||||
float rnd = RandFloat();
|
float rnd = RandFloat();
|
||||||
float angle = (1.0f - (rnd + rnd)) * angleMult;
|
float angle = (1.0f - (rnd + rnd)) * angleMult;
|
||||||
maths::RotateVector(ball->Direction, angle);
|
maths::RotateVector(Direction, angle);
|
||||||
rnd = RandFloat();
|
rnd = RandFloat();
|
||||||
ball->Speed = (1.0f - (rnd + rnd)) * (speedMult1 * speedMult2) + speedMult1;
|
Speed = (1.0f - (rnd + rnd)) * (speedMult1 * speedMult2) + speedMult1;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector2 TBall::get_coordinates()
|
vector2 TBall::get_coordinates()
|
||||||
|
@ -138,5 +147,6 @@ vector2 TBall::get_coordinates()
|
||||||
void TBall::Disable()
|
void TBall::Disable()
|
||||||
{
|
{
|
||||||
ActiveFlag = false;
|
ActiveFlag = false;
|
||||||
|
AsEdgeCollisionFlag = true;
|
||||||
SpriteSet(-1);
|
SpriteSet(-1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,10 @@ public :
|
||||||
int Message(MessageCode code, float value) override;
|
int Message(MessageCode code, float value) override;
|
||||||
vector2 get_coordinates() override;
|
vector2 get_coordinates() override;
|
||||||
void Disable();
|
void Disable();
|
||||||
|
void throw_ball(vector3* direction, float angleMult, float speedMult1, float speedMult2);
|
||||||
static void throw_ball(TBall* ball, vector3* direction, float angleMult, float speedMult1,
|
|
||||||
float speedMult2);
|
|
||||||
|
|
||||||
vector3 Position{};
|
vector3 Position{};
|
||||||
|
vector3 PrevPosition{};
|
||||||
vector3 Direction{};
|
vector3 Direction{};
|
||||||
float Speed;
|
float Speed;
|
||||||
float RayMaxDistance;
|
float RayMaxDistance;
|
||||||
|
@ -28,10 +27,15 @@ public :
|
||||||
vector2 RampFieldForce{};
|
vector2 RampFieldForce{};
|
||||||
TCollisionComponent* CollisionComp;
|
TCollisionComponent* CollisionComp;
|
||||||
int CollisionMask;
|
int CollisionMask;
|
||||||
TEdgeSegment* Collisions[5]{};
|
TEdgeSegment* Collisions[16]{};
|
||||||
int EdgeCollisionCount;
|
int EdgeCollisionCount;
|
||||||
|
bool EdgeCollisionResetFlag{};
|
||||||
vector3 CollisionOffset{};
|
vector3 CollisionOffset{};
|
||||||
int CollisionFlag;
|
int CollisionFlag;
|
||||||
float Offset;
|
float Offset;
|
||||||
|
bool HasGroupFlag;
|
||||||
|
int SomeCounter1 = 0;
|
||||||
|
int time_ticks1{}, time_ticks2{};
|
||||||
float VisualZArray[50]{};
|
float VisualZArray[50]{};
|
||||||
|
bool AsEdgeCollisionFlag{};
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
#include "pb.h"
|
#include "pb.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
#include "TBall.h"
|
||||||
#include "TFlipperEdge.h"
|
#include "TFlipperEdge.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "TPinballTable.h"
|
#include "TPinballTable.h"
|
||||||
|
@ -84,15 +85,17 @@ int TFlipper::Message(MessageCode code, float value)
|
||||||
code = MessageCode::TFlipperRetract;
|
code = MessageCode::TFlipperRetract;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageField = FlipperEdge->SetMotion(code, value);
|
MessageField = FlipperEdge->SetMotion(code);
|
||||||
break;
|
break;
|
||||||
case MessageCode::PlayerChanged:
|
case MessageCode::PlayerChanged:
|
||||||
case MessageCode::Reset:
|
case MessageCode::Reset:
|
||||||
if (MessageField)
|
if (MessageField)
|
||||||
{
|
{
|
||||||
|
FlipperEdge->CurrentAngle = 0;
|
||||||
|
FlipperEdge->set_control_points(0);
|
||||||
MessageField = 0;
|
MessageField = 0;
|
||||||
FlipperEdge->SetMotion(MessageCode::Reset, value);
|
FlipperEdge->SetMotion(MessageCode::Reset);
|
||||||
UpdateSprite(0);
|
UpdateSprite();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
|
@ -110,11 +113,11 @@ void TFlipper::Collision(TBall* ball, vector2* nextPosition, vector2* direction,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void TFlipper::UpdateSprite(float timeNow)
|
void TFlipper::UpdateSprite()
|
||||||
{
|
{
|
||||||
int bmpCountSub1 = ListBitmap->size() - 1;
|
int bmpCountSub1 = ListBitmap->size() - 1;
|
||||||
|
|
||||||
auto newBmpIndex = static_cast<int>(floor(FlipperEdge->flipper_angle(timeNow) / FlipperEdge->AngleMax * bmpCountSub1 + 0.5f));
|
auto newBmpIndex = static_cast<int>(floor(FlipperEdge->CurrentAngle / FlipperEdge->AngleMax * bmpCountSub1 + 0.5f));
|
||||||
newBmpIndex = Clamp(newBmpIndex, 0, bmpCountSub1);
|
newBmpIndex = Clamp(newBmpIndex, 0, bmpCountSub1);
|
||||||
if (BmpIndex == newBmpIndex)
|
if (BmpIndex == newBmpIndex)
|
||||||
return;
|
return;
|
||||||
|
@ -122,3 +125,87 @@ void TFlipper::UpdateSprite(float timeNow)
|
||||||
BmpIndex = newBmpIndex;
|
BmpIndex = newBmpIndex;
|
||||||
SpriteSet(BmpIndex);
|
SpriteSet(BmpIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TFlipper::GetFlipperAngleDistance(float dt, float* dst) const
|
||||||
|
{
|
||||||
|
if (!MessageField)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
auto deltaAngle = FlipperEdge->flipper_angle_delta(dt);
|
||||||
|
auto distance = std::fabs(std::ceil(FlipperEdge->DistanceDiv * deltaAngle * FlipperEdge->InvT1Radius));
|
||||||
|
if (distance > 3.0f)
|
||||||
|
distance = 3.0f;
|
||||||
|
if (distance >= 2.0f)
|
||||||
|
{
|
||||||
|
*dst = deltaAngle / distance;
|
||||||
|
return static_cast<int>(distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst = deltaAngle;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TFlipper::FlipperCollision(float deltaAngle)
|
||||||
|
{
|
||||||
|
if (!MessageField)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ray_type ray{}, rayDst{};
|
||||||
|
ray.MinDistance = 0.002f;
|
||||||
|
auto deltaAngleNeg = -deltaAngle;
|
||||||
|
bool collisionFlag = false;
|
||||||
|
for (auto ball : pb::MainTable->BallList)
|
||||||
|
{
|
||||||
|
if ((FlipperEdge->CollisionGroup & ball->CollisionMask) != 0 &&
|
||||||
|
FlipperEdge->YMax >= ball->Position.Y && FlipperEdge->YMin <= ball->Position.Y &&
|
||||||
|
FlipperEdge->XMax >= ball->Position.X && FlipperEdge->XMin <= ball->Position.X)
|
||||||
|
{
|
||||||
|
if (FlipperEdge->ControlPointDirtyFlag)
|
||||||
|
FlipperEdge->set_control_points(FlipperEdge->CurrentAngle);
|
||||||
|
ray.CollisionMask = ball->CollisionMask;
|
||||||
|
ray.Origin = ball->Position;
|
||||||
|
|
||||||
|
float sin, cos;
|
||||||
|
auto ballPosRot = ray.Origin;
|
||||||
|
maths::SinCos(deltaAngleNeg, sin, cos);
|
||||||
|
maths::RotatePt(ballPosRot, sin, cos, FlipperEdge->RotOrigin);
|
||||||
|
ray.Direction.X = ballPosRot.X - ray.Origin.X;
|
||||||
|
ray.Direction.Y = ballPosRot.Y - ray.Origin.Y;
|
||||||
|
ray.MaxDistance = maths::normalize_2d(ray.Direction);
|
||||||
|
auto distance = maths::distance_to_flipper(FlipperEdge, ray, rayDst);
|
||||||
|
if (distance < 1e9f)
|
||||||
|
{
|
||||||
|
FlipperEdge->NextBallPosition = ball->Position;
|
||||||
|
FlipperEdge->CollisionDirection = rayDst.Direction;
|
||||||
|
FlipperEdge->EdgeCollision(ball, distance);
|
||||||
|
collisionFlag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collisionFlag)
|
||||||
|
{
|
||||||
|
auto angleAdvance = deltaAngle / (std::fabs(FlipperEdge->MoveSpeed) * 5.0f);
|
||||||
|
FlipperEdge->CurrentAngle -= angleAdvance;
|
||||||
|
FlipperEdge->AngleRemainder += std::fabs(angleAdvance);
|
||||||
|
if (FlipperEdge->AngleRemainder <= 0.0001f)
|
||||||
|
{
|
||||||
|
FlipperEdge->CurrentAngle = FlipperEdge->AngleDst;
|
||||||
|
FlipperEdge->FlipperFlag = MessageCode::TFlipperNull;
|
||||||
|
MessageField = 0;
|
||||||
|
}
|
||||||
|
FlipperEdge->ControlPointDirtyFlag = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FlipperEdge->CurrentAngle += deltaAngle;
|
||||||
|
FlipperEdge->AngleRemainder -= std::fabs(deltaAngle);
|
||||||
|
if (FlipperEdge->AngleRemainder <= 0.0001f)
|
||||||
|
{
|
||||||
|
FlipperEdge->CurrentAngle = FlipperEdge->AngleDst;
|
||||||
|
FlipperEdge->FlipperFlag = MessageCode::TFlipperNull;
|
||||||
|
MessageField = 0;
|
||||||
|
}
|
||||||
|
FlipperEdge->ControlPointDirtyFlag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,9 @@ public:
|
||||||
void port_draw() override;
|
void port_draw() override;
|
||||||
void Collision(TBall* ball, vector2* nextPosition, vector2* direction, float distance,
|
void Collision(TBall* ball, vector2* nextPosition, vector2* direction, float distance,
|
||||||
TEdgeSegment* edge) override;
|
TEdgeSegment* edge) override;
|
||||||
void UpdateSprite(float timeNow);
|
void UpdateSprite();
|
||||||
|
int GetFlipperAngleDistance(float dt, float* dst) const;
|
||||||
|
void FlipperCollision(float deltaAngle);
|
||||||
|
|
||||||
int BmpIndex;
|
int BmpIndex;
|
||||||
TFlipperEdge* FlipperEdge;
|
TFlipperEdge* FlipperEdge;
|
||||||
|
|
|
@ -8,9 +8,11 @@
|
||||||
#include "TTableLayer.h"
|
#include "TTableLayer.h"
|
||||||
|
|
||||||
|
|
||||||
TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsigned int collisionGroup, TPinballTable* table,
|
TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsigned int collisionGroup,
|
||||||
vector3* origin, vector3* vecT1, vector3* vecT2, float extendTime, float retractTime,
|
TPinballTable* table,
|
||||||
float collMult, float elasticity, float smoothness): TEdgeSegment(collComp, activeFlag, collisionGroup)
|
vector3* origin, vector3* vecT1, vector3* vecT2, float extendSpeed, float retractSpeed,
|
||||||
|
float collMult, float elasticity, float smoothness): TEdgeSegment(
|
||||||
|
collComp, activeFlag, collisionGroup)
|
||||||
{
|
{
|
||||||
vector3 crossProd{}, vecOriginT1{}, vecOriginT2{};
|
vector3 crossProd{}, vecOriginT1{}, vecOriginT2{};
|
||||||
|
|
||||||
|
@ -52,22 +54,22 @@ TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsi
|
||||||
// 3DPB and FT have different formats for flipper speed:
|
// 3DPB and FT have different formats for flipper speed:
|
||||||
// 3DPB: Time it takes for flipper to go from source to destination, in sec.
|
// 3DPB: Time it takes for flipper to go from source to destination, in sec.
|
||||||
// FT: Flipper movement speed, in radians per sec.
|
// FT: Flipper movement speed, in radians per sec.
|
||||||
if (pb::FullTiltMode)
|
if (!pb::FullTiltMode)
|
||||||
{
|
{
|
||||||
auto angleMax = std::abs(AngleMax);
|
auto angleMax = std::abs(AngleMax);
|
||||||
retractTime = angleMax / retractTime;
|
retractSpeed = angleMax / retractSpeed;
|
||||||
extendTime = angleMax / extendTime;
|
extendSpeed = angleMax / extendSpeed;
|
||||||
}
|
}
|
||||||
ExtendTime = extendTime;
|
ExtendSpeed = extendSpeed;
|
||||||
RetractTime = retractTime;
|
RetractSpeed = retractSpeed;
|
||||||
|
|
||||||
const vector2 perpOriginT1Cc = { -vecOriginT1.Y , vecOriginT1.X };
|
const vector2 perpOriginT1Cc = {-vecOriginT1.Y, vecOriginT1.X};
|
||||||
A2Src.X = perpOriginT1Cc.X * CirclebaseRadius + origin->X;
|
A2Src.X = perpOriginT1Cc.X * CirclebaseRadius + origin->X;
|
||||||
A2Src.Y = perpOriginT1Cc.Y * CirclebaseRadius + origin->Y;
|
A2Src.Y = perpOriginT1Cc.Y * CirclebaseRadius + origin->Y;
|
||||||
A1Src.X = perpOriginT1Cc.X * CircleT1Radius + vecT1->X;
|
A1Src.X = perpOriginT1Cc.X * CircleT1Radius + vecT1->X;
|
||||||
A1Src.Y = perpOriginT1Cc.Y * CircleT1Radius + vecT1->Y;
|
A1Src.Y = perpOriginT1Cc.Y * CircleT1Radius + vecT1->Y;
|
||||||
|
|
||||||
const vector2 perpOriginT1C = { vecOriginT1.Y , -vecOriginT1.X };
|
const vector2 perpOriginT1C = {vecOriginT1.Y, -vecOriginT1.X};
|
||||||
B1Src.X = perpOriginT1C.X * CirclebaseRadius + origin->X;
|
B1Src.X = perpOriginT1C.X * CirclebaseRadius + origin->X;
|
||||||
B1Src.Y = perpOriginT1C.Y * CirclebaseRadius + origin->Y;
|
B1Src.Y = perpOriginT1C.Y * CirclebaseRadius + origin->Y;
|
||||||
B2Src.X = perpOriginT1C.X * CircleT1Radius + vecT1->X;
|
B2Src.X = perpOriginT1C.X * CircleT1Radius + vecT1->X;
|
||||||
|
@ -82,249 +84,94 @@ TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsi
|
||||||
auto dx = vecT1->X - RotOrigin.X;
|
auto dx = vecT1->X - RotOrigin.X;
|
||||||
auto dy = vecT1->Y - RotOrigin.Y;
|
auto dy = vecT1->Y - RotOrigin.Y;
|
||||||
auto distance1 = sqrt(dy * dy + dx * dx) + table->CollisionCompOffset + vecT1->Z;
|
auto distance1 = sqrt(dy * dy + dx * dx) + table->CollisionCompOffset + vecT1->Z;
|
||||||
|
DistanceDiv = distance1;
|
||||||
DistanceDivSq = distance1 * distance1;
|
DistanceDivSq = distance1 * distance1;
|
||||||
|
InvT1Radius = 1.0f / CircleT1Radius * 1.5f;
|
||||||
|
|
||||||
float minMoveTime = std::min(ExtendTime, RetractTime);
|
if (AngleMax <= 0.0f)
|
||||||
auto distance = maths::Distance(*vecT1, *vecT2);
|
{
|
||||||
CollisionTimeAdvance = minMoveTime / (distance / CircleT1Radius + distance / CircleT1Radius);
|
ExtendSpeed = -ExtendSpeed;
|
||||||
|
}
|
||||||
EdgeCollisionFlag = 0;
|
else
|
||||||
InputTime = 0.0;
|
{
|
||||||
CollisionFlag1 = 0;
|
RetractSpeed = -RetractSpeed;
|
||||||
AngleStopTime = 0.0;
|
}
|
||||||
AngleAdvanceTime = 0.0;
|
set_control_points(CurrentAngle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TFlipperEdge::port_draw()
|
void TFlipperEdge::port_draw()
|
||||||
{
|
{
|
||||||
set_control_points(InputTime);
|
set_control_points(CurrentAngle);
|
||||||
}
|
}
|
||||||
|
|
||||||
float TFlipperEdge::FindCollisionDistance(ray_type* ray)
|
float TFlipperEdge::FindCollisionDistance(ray_type* ray)
|
||||||
{
|
{
|
||||||
auto ogRay = ray;
|
ray_type dstRay{};
|
||||||
ray_type dstRay{}, srcRay{};
|
if (ControlPointDirtyFlag)
|
||||||
|
set_control_points(CurrentAngle);
|
||||||
|
auto distance = maths::distance_to_flipper(this, *ray, dstRay);
|
||||||
|
if (distance >= 1e9f)
|
||||||
|
return 1e9f;
|
||||||
|
|
||||||
if (ogRay->TimeNow > AngleStopTime)
|
|
||||||
{
|
|
||||||
FlipperFlag = MessageCode::TFlipperNull;
|
|
||||||
}
|
|
||||||
if (EdgeCollisionFlag == 0)
|
|
||||||
{
|
|
||||||
if (FlipperFlag == MessageCode::TFlipperNull)
|
|
||||||
{
|
|
||||||
CollisionFlag1 = 0;
|
|
||||||
CollisionFlag2 = 0;
|
|
||||||
set_control_points(ogRay->TimeNow);
|
|
||||||
auto ballInside = is_ball_inside(ogRay->Origin.X, ogRay->Origin.Y);
|
|
||||||
srcRay.MinDistance = ogRay->MinDistance;
|
|
||||||
if (ballInside == 0)
|
|
||||||
{
|
|
||||||
srcRay.Direction = ogRay->Direction;
|
|
||||||
srcRay.MaxDistance = ogRay->MaxDistance;
|
|
||||||
srcRay.Origin = ogRay->Origin;
|
|
||||||
auto distance = maths::distance_to_flipper(this, srcRay, dstRay);
|
|
||||||
if (distance == 0.0f)
|
|
||||||
{
|
|
||||||
NextBallPosition = dstRay.Origin;
|
NextBallPosition = dstRay.Origin;
|
||||||
NextBallPosition.X -= srcRay.Direction.X * 1e-05f;
|
|
||||||
NextBallPosition.Y -= srcRay.Direction.Y * 1e-05f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NextBallPosition = dstRay.Origin;
|
|
||||||
}
|
|
||||||
CollisionDirection = dstRay.Direction;
|
CollisionDirection = dstRay.Direction;
|
||||||
return distance;
|
return distance;
|
||||||
}
|
|
||||||
|
|
||||||
if (maths::Distance_Squared(ogRay->Origin, RotOrigin) >= CirclebaseRadiusMSq)
|
|
||||||
{
|
|
||||||
if (maths::Distance_Squared(ogRay->Origin, T1) >= CircleT1RadiusMSq)
|
|
||||||
{
|
|
||||||
srcRay.Direction.Y = lineB.PerpendicularC.Y;
|
|
||||||
srcRay.Direction.X = lineB.PerpendicularC.X;
|
|
||||||
if (ballInside == 4)
|
|
||||||
{
|
|
||||||
srcRay.Direction.Y = lineA.PerpendicularC.Y;
|
|
||||||
srcRay.Direction.X = lineA.PerpendicularC.X;
|
|
||||||
}
|
|
||||||
srcRay.Direction.X = -srcRay.Direction.X;
|
|
||||||
srcRay.Direction.Y = -srcRay.Direction.Y;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
srcRay.Direction.X = T1.X - ogRay->Origin.X;
|
|
||||||
srcRay.Direction.Y = T1.Y - ogRay->Origin.Y;
|
|
||||||
maths::normalize_2d(srcRay.Direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
srcRay.Direction.X = RotOrigin.X - ogRay->Origin.X;
|
|
||||||
srcRay.Direction.Y = RotOrigin.Y - ogRay->Origin.Y;
|
|
||||||
maths::normalize_2d(srcRay.Direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
srcRay.Origin.X = ogRay->Origin.X - srcRay.Direction.X * 5.0f;
|
|
||||||
srcRay.Origin.Y = ogRay->Origin.Y - srcRay.Direction.Y * 5.0f;
|
|
||||||
srcRay.MaxDistance = ogRay->MaxDistance + 10.0f;
|
|
||||||
if (maths::distance_to_flipper(this, srcRay, dstRay) >= 1e+09f)
|
|
||||||
{
|
|
||||||
srcRay.Direction.X = RotOrigin.X - ogRay->Origin.X;
|
|
||||||
srcRay.Direction.Y = RotOrigin.Y - ogRay->Origin.Y;
|
|
||||||
maths::normalize_2d(srcRay.Direction);
|
|
||||||
srcRay.Origin.X = ogRay->Origin.X - srcRay.Direction.X * 5.0f;
|
|
||||||
srcRay.Origin.Y = ogRay->Origin.Y - srcRay.Direction.Y * 5.0f;
|
|
||||||
if (maths::distance_to_flipper(this, srcRay, dstRay) >= 1e+09f)
|
|
||||||
{
|
|
||||||
return 1e+09;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NextBallPosition = dstRay.Origin;
|
|
||||||
CollisionDirection = dstRay.Direction;
|
|
||||||
NextBallPosition.X -= srcRay.Direction.X * 1e-05f;
|
|
||||||
NextBallPosition.Y -= srcRay.Direction.Y * 1e-05f;
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto posX = ogRay->Origin.X;
|
|
||||||
auto posY = ogRay->Origin.Y;
|
|
||||||
auto posXAdvance = ogRay->Direction.X * CollisionTimeAdvance;
|
|
||||||
auto posYAdvance = ogRay->Direction.Y * CollisionTimeAdvance;
|
|
||||||
auto rayMaxDistance = ogRay->MaxDistance * CollisionTimeAdvance;
|
|
||||||
auto timeNow = ogRay->TimeNow;
|
|
||||||
auto stopTime = ogRay->TimeDelta + ogRay->TimeNow;
|
|
||||||
while (timeNow < stopTime)
|
|
||||||
{
|
|
||||||
set_control_points(timeNow);
|
|
||||||
auto ballInside = is_ball_inside(posX, posY);
|
|
||||||
if (ballInside != 0)
|
|
||||||
{
|
|
||||||
vector2* linePtr;
|
|
||||||
if (FlipperFlag == MessageCode::TFlipperExtend && ballInside != 5)
|
|
||||||
{
|
|
||||||
linePtr = &lineA.PerpendicularC;
|
|
||||||
srcRay.Direction.Y = lineA.PerpendicularC.Y;
|
|
||||||
srcRay.Direction.X = lineA.PerpendicularC.X;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (FlipperFlag != MessageCode::TFlipperRetract || ballInside == 4)
|
|
||||||
{
|
|
||||||
CollisionFlag1 = 0;
|
|
||||||
CollisionFlag2 = 1;
|
|
||||||
srcRay.Direction.X = RotOrigin.X - posX;
|
|
||||||
srcRay.Direction.Y = RotOrigin.Y - posY;
|
|
||||||
maths::normalize_2d(srcRay.Direction);
|
|
||||||
|
|
||||||
srcRay.Origin.X = posX - srcRay.Direction.X * 5.0f;
|
|
||||||
srcRay.Origin.Y = posY - srcRay.Direction.Y * 5.0f;
|
|
||||||
srcRay.MaxDistance = ogRay->MaxDistance + 10.0f;
|
|
||||||
if (maths::distance_to_flipper(this, srcRay, dstRay) >= 1e+09f)
|
|
||||||
{
|
|
||||||
NextBallPosition.X = posX;
|
|
||||||
NextBallPosition.Y = posY;
|
|
||||||
CollisionDirection.X = -srcRay.Direction.X;
|
|
||||||
CollisionDirection.Y = -srcRay.Direction.Y;
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
NextBallPosition = dstRay.Origin;
|
|
||||||
CollisionDirection = dstRay.Direction;
|
|
||||||
NextBallPosition.X -= srcRay.Direction.X * 1e-05f;
|
|
||||||
NextBallPosition.Y -= srcRay.Direction.Y * 1e-05f;
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
linePtr = &lineB.PerpendicularC;
|
|
||||||
srcRay.Direction.Y = lineB.PerpendicularC.Y;
|
|
||||||
srcRay.Direction.X = lineB.PerpendicularC.X;
|
|
||||||
}
|
|
||||||
|
|
||||||
CollisionLinePerp = *linePtr;
|
|
||||||
CollisionFlag2 = 0;
|
|
||||||
CollisionFlag1 = 1;
|
|
||||||
srcRay.Direction.X = -srcRay.Direction.X;
|
|
||||||
srcRay.Direction.Y = -srcRay.Direction.Y;
|
|
||||||
srcRay.MinDistance = 0.002f;
|
|
||||||
srcRay.Origin.X = ogRay->Origin.X - srcRay.Direction.X * 5.0f;
|
|
||||||
srcRay.Origin.Y = ogRay->Origin.Y - srcRay.Direction.Y * 5.0f;
|
|
||||||
srcRay.MaxDistance = ogRay->MaxDistance + 10.0f;
|
|
||||||
auto distance = maths::distance_to_flipper(this, srcRay, dstRay);
|
|
||||||
CollisionDirection = dstRay.Direction;
|
|
||||||
if (distance >= 1e+09f)
|
|
||||||
{
|
|
||||||
return 1e+09;
|
|
||||||
}
|
|
||||||
NextBallPosition = dstRay.Origin;
|
|
||||||
NextBallPosition.X -= srcRay.Direction.X * 1e-05f;
|
|
||||||
NextBallPosition.Y -= srcRay.Direction.Y * 1e-05f;
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
srcRay.Direction = ogRay->Direction;
|
|
||||||
srcRay.MinDistance = ogRay->MinDistance;
|
|
||||||
srcRay.Origin = ogRay->Origin;
|
|
||||||
srcRay.MaxDistance = rayMaxDistance;
|
|
||||||
auto distance = maths::distance_to_flipper(this, srcRay, dstRay);
|
|
||||||
if (distance < 1e+09f)
|
|
||||||
{
|
|
||||||
NextBallPosition = dstRay.Origin;
|
|
||||||
NextBallPosition.X -= srcRay.Direction.X * 1e-05f;
|
|
||||||
NextBallPosition.Y -= srcRay.Direction.Y * 1e-05f;
|
|
||||||
vector2* linePtr;
|
|
||||||
if (FlipperFlag == MessageCode::TFlipperRetract)
|
|
||||||
{
|
|
||||||
linePtr = &lineB.PerpendicularC;
|
|
||||||
CollisionFlag1 = AngleMax <= 0.0f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CollisionFlag1 = AngleMax > 0.0f;
|
|
||||||
linePtr = &lineA.PerpendicularC;
|
|
||||||
}
|
|
||||||
CollisionLinePerp = *linePtr;
|
|
||||||
CollisionDirection = dstRay.Direction;
|
|
||||||
return distance;
|
|
||||||
}
|
|
||||||
timeNow = timeNow + CollisionTimeAdvance;
|
|
||||||
posX = posX + posXAdvance;
|
|
||||||
posY = posY + posYAdvance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EdgeCollisionFlag = 0;
|
|
||||||
}
|
|
||||||
return 1e+09;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TFlipperEdge::EdgeCollision(TBall* ball, float distance)
|
void TFlipperEdge::EdgeCollision(TBall* ball, float distance)
|
||||||
{
|
{
|
||||||
EdgeCollisionFlag = 1;
|
if (FlipperFlag == MessageCode::TFlipperNull)
|
||||||
if (FlipperFlag == MessageCode::TFlipperNull || !CollisionFlag2 || CollisionFlag1)
|
|
||||||
{
|
{
|
||||||
float boost = 0.0;
|
maths::basic_collision(
|
||||||
if (CollisionFlag1)
|
ball,
|
||||||
{
|
&NextBallPosition,
|
||||||
float dx = NextBallPosition.X - RotOrigin.X;
|
&CollisionDirection,
|
||||||
float dy = NextBallPosition.Y - RotOrigin.Y;
|
Elasticity,
|
||||||
float distanceSq = dy * dy + dx * dx;
|
Smoothness,
|
||||||
if (circlebase.RadiusSq * 1.01f < distanceSq)
|
1e9f,
|
||||||
{
|
0);
|
||||||
float v11;
|
return;
|
||||||
float v20 = sqrt(distanceSq / DistanceDivSq) * (fabs(AngleMax) / AngleAdvanceTime);
|
|
||||||
float dot1 = maths::DotProduct(CollisionLinePerp, CollisionDirection);
|
|
||||||
if (dot1 >= 0.0f)
|
|
||||||
v11 = dot1 * v20;
|
|
||||||
else
|
|
||||||
v11 = 0.0;
|
|
||||||
boost = v11 * CollisionMult;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float threshold = boost <= 0.0f ? 1000000000.0f : -1.0f;
|
auto someProduct = (NextBallPosition.Y - T1.Y) * (RotOrigin.X - T1.X) -
|
||||||
|
(NextBallPosition.X - T1.X) * (RotOrigin.Y - T1.Y);
|
||||||
|
|
||||||
|
bool someFlag = false;
|
||||||
|
if (someProduct <= 0)
|
||||||
|
{
|
||||||
|
if (AngleMax > 0)
|
||||||
|
someFlag = true;
|
||||||
|
}
|
||||||
|
else if (AngleMax <= 0)
|
||||||
|
{
|
||||||
|
someFlag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FlipperFlag == MessageCode::TFlipperRetract)
|
||||||
|
{
|
||||||
|
someFlag ^= true;
|
||||||
|
CollisionLinePerp = LineB.PerpendicularC;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CollisionLinePerp = LineA.PerpendicularC;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dx = NextBallPosition.X - RotOrigin.X;
|
||||||
|
auto dy = NextBallPosition.Y - RotOrigin.Y;
|
||||||
|
auto distanceSq = dy * dy + dx * dx;
|
||||||
|
if (someFlag)
|
||||||
|
{
|
||||||
|
float boost = 0;
|
||||||
|
if (circlebase.RadiusSq * 1.01f < distanceSq)
|
||||||
|
{
|
||||||
|
auto v21 = std::fabs(MoveSpeed) * std::sqrt(distanceSq / DistanceDivSq);
|
||||||
|
auto dot1 = maths::DotProduct(CollisionLinePerp, CollisionDirection);
|
||||||
|
if (dot1 >= 0)
|
||||||
|
boost = CollisionMult * dot1 * v21;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto threshold = boost <= 0.0f ? 1e9f : -1.0f;
|
||||||
maths::basic_collision(
|
maths::basic_collision(
|
||||||
ball,
|
ball,
|
||||||
&NextBallPosition,
|
&NextBallPosition,
|
||||||
|
@ -333,18 +180,14 @@ void TFlipperEdge::EdgeCollision(TBall* ball, float distance)
|
||||||
Smoothness,
|
Smoothness,
|
||||||
threshold,
|
threshold,
|
||||||
boost);
|
boost);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float elasticity;
|
|
||||||
float dx = NextBallPosition.X - RotOrigin.X;
|
|
||||||
float dy = NextBallPosition.Y - RotOrigin.Y;
|
|
||||||
float distanceSq = dy * dy + dx * dx;
|
|
||||||
if (circlebase.RadiusSq * 1.01f < distanceSq)
|
|
||||||
elasticity = (1.0f - sqrt(distanceSq / DistanceDivSq)) * Elasticity;
|
|
||||||
else
|
else
|
||||||
elasticity = Elasticity;
|
{
|
||||||
maths::basic_collision(ball, &NextBallPosition, &CollisionDirection, elasticity, Smoothness, 1000000000.0, 0.0);
|
auto elasticity = Elasticity;
|
||||||
|
if (circlebase.RadiusSq * 1.01f < distanceSq)
|
||||||
|
elasticity = (1.0f - std::sqrt(distanceSq / DistanceDivSq)) * Elasticity;
|
||||||
|
maths::basic_collision(ball, &NextBallPosition, &CollisionDirection, elasticity, Smoothness, 1e9f, 0.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TFlipperEdge::place_in_grid(RectF* aabb)
|
void TFlipperEdge::place_in_grid(RectF* aabb)
|
||||||
|
@ -360,12 +203,18 @@ void TFlipperEdge::place_in_grid(RectF* aabb)
|
||||||
}
|
}
|
||||||
|
|
||||||
TTableLayer::edges_insert_square(yMin, xMin, yMax, xMax, this, nullptr);
|
TTableLayer::edges_insert_square(yMin, xMin, yMax, xMax, this, nullptr);
|
||||||
|
|
||||||
|
auto offset = 1.0f / InvT1Radius + pb::ball_min_smth;
|
||||||
|
XMin = xMin - offset;
|
||||||
|
YMin = yMin - offset;
|
||||||
|
XMax = xMax + offset;
|
||||||
|
YMax = yMax + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TFlipperEdge::set_control_points(float timeNow)
|
void TFlipperEdge::set_control_points(float angle)
|
||||||
{
|
{
|
||||||
float sin, cos;
|
float sin, cos;
|
||||||
maths::SinCos(flipper_angle(timeNow), sin, cos);
|
maths::SinCos(angle, sin, cos);
|
||||||
A1 = A1Src;
|
A1 = A1Src;
|
||||||
A2 = A2Src;
|
A2 = A2Src;
|
||||||
B1 = B1Src;
|
B1 = B1Src;
|
||||||
|
@ -376,83 +225,48 @@ void TFlipperEdge::set_control_points(float timeNow)
|
||||||
maths::RotatePt(T1, sin, cos, RotOrigin);
|
maths::RotatePt(T1, sin, cos, RotOrigin);
|
||||||
maths::RotatePt(B1, sin, cos, RotOrigin);
|
maths::RotatePt(B1, sin, cos, RotOrigin);
|
||||||
maths::RotatePt(B2, sin, cos, RotOrigin);
|
maths::RotatePt(B2, sin, cos, RotOrigin);
|
||||||
maths::line_init(lineA, A1.X, A1.Y, A2.X, A2.Y);
|
maths::line_init(LineA, A1.X, A1.Y, A2.X, A2.Y);
|
||||||
maths::line_init(lineB, B1.X, B1.Y, B2.X, B2.Y);
|
maths::line_init(LineB, B1.X, B1.Y, B2.X, B2.Y);
|
||||||
circlebase = {RotOrigin, CirclebaseRadiusSq};
|
circlebase = {RotOrigin, CirclebaseRadiusSq};
|
||||||
circleT1 = {T1, CircleT1RadiusSq};
|
circleT1 = {T1, CircleT1RadiusSq};
|
||||||
|
ControlPointDirtyFlag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float TFlipperEdge::flipper_angle(float timeNow)
|
float TFlipperEdge::flipper_angle_delta(float timeDelta)
|
||||||
{
|
{
|
||||||
// When not moving, flipper is at destination angle.
|
|
||||||
if (FlipperFlag == MessageCode::TFlipperNull)
|
if (FlipperFlag == MessageCode::TFlipperNull)
|
||||||
return AngleDst;
|
return 0.0f;
|
||||||
|
|
||||||
// How much time it takes to go from source to destination angle, in sec.
|
const auto deltaAngle = MoveSpeed * timeDelta;
|
||||||
auto arcDuration = std::abs((AngleDst - AngleSrc) / AngleMax * AngleAdvanceTime);
|
if (std::fabs(deltaAngle) > AngleRemainder)
|
||||||
|
return AngleDst - CurrentAngle;
|
||||||
// How close the flipper is to destination, in [0, 1] range.
|
return deltaAngle;
|
||||||
auto t = arcDuration >= 0.0000001f ? (timeNow - InputTime) / arcDuration : 1.0f;
|
|
||||||
t = Clamp(t, 0.0f, 1.0f);
|
|
||||||
|
|
||||||
// Result = linear interpolation between source and destination angle.
|
|
||||||
return AngleSrc + t * (AngleDst - AngleSrc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int TFlipperEdge::is_ball_inside(float x, float y)
|
int TFlipperEdge::SetMotion(MessageCode code)
|
||||||
{
|
|
||||||
vector2 testPoint{};
|
|
||||||
float dx = RotOrigin.X - x;
|
|
||||||
float dy = RotOrigin.Y - y;
|
|
||||||
if (((A2.X - A1.X) * (y - A1.Y) - (A2.Y - A1.Y) * (x - A1.X) >= 0.0f &&
|
|
||||||
(B1.X - A2.X) * (y - A2.Y) - (B1.Y - A2.Y) * (x - A2.X) >= 0.0f &&
|
|
||||||
(B2.X - B1.X) * (y - B1.Y) - (B2.Y - B1.Y) * (x - B1.X) >= 0.0f &&
|
|
||||||
(A1.X - B2.X) * (y - B2.Y) - (A1.Y - B2.Y) * (x - B2.X) >= 0.0f) ||
|
|
||||||
dy * dy + dx * dx <= CirclebaseRadiusSq ||
|
|
||||||
(T1.Y - y) * (T1.Y - y) + (T1.X - x) * (T1.X - x) < CircleT1RadiusSq)
|
|
||||||
{
|
|
||||||
float flipperLR = AngleMax < 0.0f ? -1.0f : 1.0f;
|
|
||||||
if (FlipperFlag == MessageCode::TFlipperExtend)
|
|
||||||
testPoint = AngleMax < 0.0f ? B1 : B2;
|
|
||||||
else if (FlipperFlag == MessageCode::TFlipperRetract)
|
|
||||||
testPoint = AngleMax < 0.0f ? A2 : A1;
|
|
||||||
else
|
|
||||||
testPoint = T1;
|
|
||||||
|
|
||||||
if (((y - testPoint.Y) * (RotOrigin.X - testPoint.X) -
|
|
||||||
(x - testPoint.X) * (RotOrigin.Y - testPoint.Y)) * flipperLR < 0.0f)
|
|
||||||
return 4;
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int TFlipperEdge::SetMotion(MessageCode code, float value)
|
|
||||||
{
|
{
|
||||||
switch (code)
|
switch (code)
|
||||||
{
|
{
|
||||||
case MessageCode::TFlipperExtend:
|
case MessageCode::TFlipperExtend:
|
||||||
AngleSrc = flipper_angle(value);
|
AngleRemainder = std::fabs(AngleMax - CurrentAngle);
|
||||||
AngleDst = AngleMax;
|
AngleDst = AngleMax;
|
||||||
AngleAdvanceTime = ExtendTime;
|
MoveSpeed = ExtendSpeed;
|
||||||
break;
|
break;
|
||||||
case MessageCode::TFlipperRetract:
|
case MessageCode::TFlipperRetract:
|
||||||
AngleSrc = flipper_angle(value);
|
AngleRemainder = std::fabs(CurrentAngle);
|
||||||
AngleDst = 0.0f;
|
AngleDst = 0.0f;
|
||||||
AngleAdvanceTime = RetractTime;
|
MoveSpeed = RetractSpeed;
|
||||||
break;
|
break;
|
||||||
case MessageCode::Reset:
|
case MessageCode::Reset:
|
||||||
AngleSrc = 0.0f;
|
AngleRemainder = 0.0f;
|
||||||
AngleDst = 0.0f;
|
AngleDst = 0.0f;
|
||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AngleSrc == AngleDst)
|
if (AngleRemainder == 0.0f)
|
||||||
code = MessageCode::TFlipperNull;
|
code = MessageCode::TFlipperNull;
|
||||||
|
|
||||||
InputTime = value;
|
|
||||||
FlipperFlag = code;
|
FlipperFlag = code;
|
||||||
AngleStopTime = AngleAdvanceTime + InputTime;
|
|
||||||
return static_cast<int>(code);
|
return static_cast<int>(code);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,16 +9,15 @@ class TFlipperEdge : public TEdgeSegment
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsigned int collisionGroup, TPinballTable* table,
|
TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsigned int collisionGroup, TPinballTable* table,
|
||||||
vector3* origin, vector3* vecT1, vector3* vecT2, float extendTime, float retractTime, float collMult,
|
vector3* origin, vector3* vecT1, vector3* vecT2, float extendSpeed, float retractSpeed, float collMult,
|
||||||
float elasticity, float smoothness);
|
float elasticity, float smoothness);
|
||||||
void port_draw() override;
|
void port_draw() override;
|
||||||
float FindCollisionDistance(ray_type* ray) override;
|
float FindCollisionDistance(ray_type* ray) override;
|
||||||
void EdgeCollision(TBall* ball, float distance) override;
|
void EdgeCollision(TBall* ball, float distance) override;
|
||||||
void place_in_grid(RectF* aabb) override;
|
void place_in_grid(RectF* aabb) override;
|
||||||
void set_control_points(float timeNow);
|
void set_control_points(float angle);
|
||||||
float flipper_angle(float timeNow);
|
float flipper_angle_delta(float timeDelta);
|
||||||
int is_ball_inside(float x, float y);
|
int SetMotion(MessageCode code);
|
||||||
int SetMotion(MessageCode code, float value);
|
|
||||||
|
|
||||||
MessageCode FlipperFlag{};
|
MessageCode FlipperFlag{};
|
||||||
float Elasticity;
|
float Elasticity;
|
||||||
|
@ -31,10 +30,9 @@ public:
|
||||||
float CirclebaseRadiusMSq;
|
float CirclebaseRadiusMSq;
|
||||||
float CircleT1RadiusMSq;
|
float CircleT1RadiusMSq;
|
||||||
float AngleMax;
|
float AngleMax;
|
||||||
float AngleSrc{};
|
float AngleRemainder{};
|
||||||
float AngleDst;
|
float AngleDst;
|
||||||
int CollisionFlag1;
|
float CurrentAngle{};
|
||||||
int CollisionFlag2{};
|
|
||||||
vector2 CollisionLinePerp{};
|
vector2 CollisionLinePerp{};
|
||||||
vector2 A1Src{};
|
vector2 A1Src{};
|
||||||
vector2 A2Src{};
|
vector2 A2Src{};
|
||||||
|
@ -43,17 +41,16 @@ public:
|
||||||
float CollisionMult;
|
float CollisionMult;
|
||||||
vector2 T1Src{};
|
vector2 T1Src{};
|
||||||
vector2 T2Src{};
|
vector2 T2Src{};
|
||||||
float DistanceDivSq;
|
float DistanceDiv, DistanceDivSq;
|
||||||
float CollisionTimeAdvance;
|
|
||||||
vector2 CollisionDirection{};
|
vector2 CollisionDirection{};
|
||||||
int EdgeCollisionFlag;
|
float ExtendSpeed;
|
||||||
float InputTime;
|
float RetractSpeed;
|
||||||
float AngleStopTime;
|
float MoveSpeed;
|
||||||
float AngleAdvanceTime;
|
|
||||||
float ExtendTime;
|
|
||||||
float RetractTime;
|
|
||||||
vector2 NextBallPosition{};
|
vector2 NextBallPosition{};
|
||||||
vector2 A1, A2, B1, B2, T1;
|
vector2 A1, A2, B1, B2, T1;
|
||||||
line_type lineA, lineB;
|
line_type LineA, LineB;
|
||||||
circle_type circlebase, circleT1;
|
circle_type circlebase, circleT1;
|
||||||
|
float InvT1Radius;
|
||||||
|
float YMin, YMax, XMin, XMax;
|
||||||
|
bool ControlPointDirtyFlag{};
|
||||||
};
|
};
|
||||||
|
|
|
@ -80,6 +80,7 @@ void THole::Collision(TBall* ball, vector2* nextPosition, vector2* direction, fl
|
||||||
ball->Position.X = Circle.Center.X;
|
ball->Position.X = Circle.Center.X;
|
||||||
ball->Position.Y = Circle.Center.Y;
|
ball->Position.Y = Circle.Center.Y;
|
||||||
ball->Direction.Z = 0.0;
|
ball->Direction.Z = 0.0;
|
||||||
|
ball->AsEdgeCollisionFlag = true;
|
||||||
|
|
||||||
// Ramp hole has no delay in FT.
|
// Ramp hole has no delay in FT.
|
||||||
auto captureTime = pb::FullTiltMode ? 0 : 0.5f;
|
auto captureTime = pb::FullTiltMode ? 0 : 0.5f;
|
||||||
|
@ -91,6 +92,10 @@ void THole::Collision(TBall* ball, vector2* nextPosition, vector2* direction, fl
|
||||||
control::handler(MessageCode::ControlBallCaptured, this);
|
control::handler(MessageCode::ControlBallCaptured, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DefaultCollision(ball, nextPosition, direction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int THole::FieldEffect(TBall* ball, vector2* vecDst)
|
int THole::FieldEffect(TBall* ball, vector2* vecDst)
|
||||||
|
|
|
@ -105,6 +105,7 @@ void TKickout::Collision(TBall* ball, vector2* nextPosition, vector2* direction,
|
||||||
ball->Position.Y = Circle.Center.Y;
|
ball->Position.Y = Circle.Center.Y;
|
||||||
OriginalBallZ = ball->Position.Z;
|
OriginalBallZ = ball->Position.Z;
|
||||||
ball->Position.Z = CollisionBallSetZ;
|
ball->Position.Z = CollisionBallSetZ;
|
||||||
|
ball->AsEdgeCollisionFlag = true;
|
||||||
if (PinballTable->TiltLockFlag)
|
if (PinballTable->TiltLockFlag)
|
||||||
{
|
{
|
||||||
Message(MessageCode::TKickoutRestartTimer, 0.1f);
|
Message(MessageCode::TKickoutRestartTimer, 0.1f);
|
||||||
|
@ -115,6 +116,13 @@ void TKickout::Collision(TBall* ball, vector2* nextPosition, vector2* direction,
|
||||||
control::handler(MessageCode::ControlCollision, this);
|
control::handler(MessageCode::ControlCollision, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ball->Position.X = nextPosition->X;
|
||||||
|
ball->Position.Y = nextPosition->Y;
|
||||||
|
ball->RayMaxDistance -= distance;
|
||||||
|
ball->not_again(edge);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int TKickout::FieldEffect(TBall* ball, vector2* dstVec)
|
int TKickout::FieldEffect(TBall* ball, vector2* dstVec)
|
||||||
|
@ -144,7 +152,7 @@ void TKickout::TimerExpired(int timerId, void* caller)
|
||||||
{
|
{
|
||||||
loader::play_sound(kick->HardHitSoundId, kick->Ball, "TKickout2");
|
loader::play_sound(kick->HardHitSoundId, kick->Ball, "TKickout2");
|
||||||
kick->Ball->Position.Z = kick->OriginalBallZ;
|
kick->Ball->Position.Z = kick->OriginalBallZ;
|
||||||
TBall::throw_ball(kick->Ball, &kick->BallThrowDirection, kick->ThrowAngleMult, kick->ThrowSpeedMult1,
|
kick->Ball->throw_ball(&kick->BallThrowDirection, kick->ThrowAngleMult, kick->ThrowSpeedMult1,
|
||||||
kick->ThrowSpeedMult2);
|
kick->ThrowSpeedMult2);
|
||||||
kick->ActiveFlag = 0;
|
kick->ActiveFlag = 0;
|
||||||
kick->Ball = nullptr;
|
kick->Ball = nullptr;
|
||||||
|
|
|
@ -631,6 +631,9 @@ TBall* TPinballTable::AddBall(float x, float y)
|
||||||
|
|
||||||
ball->Position.X = x;
|
ball->Position.X = x;
|
||||||
ball->Position.Y = y;
|
ball->Position.Y = y;
|
||||||
|
ball->PrevPosition = ball->Position;
|
||||||
|
ball->SomeCounter1 = 0;
|
||||||
|
ball->time_ticks1 = ball->time_ticks2 = pb::time_ticks;
|
||||||
|
|
||||||
return ball;
|
return ball;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,8 @@ void TSink::TimerExpired(int timerId, void* caller)
|
||||||
{
|
{
|
||||||
auto ball = table->AddBall(sink->BallPosition.X, sink->BallPosition.Y);
|
auto ball = table->AddBall(sink->BallPosition.X, sink->BallPosition.Y);
|
||||||
assertm(ball, "Failure to create ball in sink");
|
assertm(ball, "Failure to create ball in sink");
|
||||||
TBall::throw_ball(ball, &sink->BallThrowDirection, sink->ThrowAngleMult, sink->ThrowSpeedMult1,
|
ball->AsEdgeCollisionFlag = true;
|
||||||
|
ball->throw_ball(&sink->BallThrowDirection, sink->ThrowAngleMult, sink->ThrowSpeedMult1,
|
||||||
sink->ThrowSpeedMult2);
|
sink->ThrowSpeedMult2);
|
||||||
if (sink->SoundIndex3)
|
if (sink->SoundIndex3)
|
||||||
loader::play_sound(sink->SoundIndex3, ball, "TSink2");
|
loader::play_sound(sink->SoundIndex3, ball, "TSink2");
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "midi.h"
|
#include "midi.h"
|
||||||
#include "pb.h"
|
#include "pb.h"
|
||||||
|
#include "TBall.h"
|
||||||
#include "TBlocker.h"
|
#include "TBlocker.h"
|
||||||
#include "TBumper.h"
|
#include "TBumper.h"
|
||||||
#include "TComponentGroup.h"
|
#include "TComponentGroup.h"
|
||||||
|
@ -1062,6 +1063,36 @@ void control::cheat_bump_rank()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void control::BallThrowOrDisable(TBall& ball, int dt)
|
||||||
|
{
|
||||||
|
if (!CheckBallInControlBounds(ball, *flip1) &&
|
||||||
|
!CheckBallInControlBounds(ball, *flip2) &&
|
||||||
|
!CheckBallInControlBounds(ball, *plunger))
|
||||||
|
{
|
||||||
|
if (ball.SomeCounter1 <= 20)
|
||||||
|
{
|
||||||
|
vector3 throwDir{0.0f, -1.0f, 0.0f};
|
||||||
|
ball.throw_ball(&throwDir, 90.0f, 1.0f, 0.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ball.Disable();
|
||||||
|
TableG->MultiballCount--;
|
||||||
|
plunger->Message(MessageCode::PlungerRelaunchBall, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool control::CheckBallInControlBounds(const TBall& ball, const TCollisionComponent& cmp)
|
||||||
|
{
|
||||||
|
auto offset = TableG->CollisionCompOffset / 2.0f;
|
||||||
|
return ball.ActiveFlag &&
|
||||||
|
ball.Position.X >= cmp.AABB.XMin - offset &&
|
||||||
|
ball.Position.X <= cmp.AABB.XMax + offset &&
|
||||||
|
ball.Position.Y >= cmp.AABB.YMin - offset &&
|
||||||
|
ball.Position.Y <= cmp.AABB.YMax + offset;
|
||||||
|
}
|
||||||
|
|
||||||
int control::SpecialAddScore(int score)
|
int control::SpecialAddScore(int score)
|
||||||
{
|
{
|
||||||
int prevFlag1 = TableG->ScoreSpecial3Flag;
|
int prevFlag1 = TableG->ScoreSpecial3Flag;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
class TCollisionComponent;
|
||||||
|
class TBall;
|
||||||
enum class MessageCode;
|
enum class MessageCode;
|
||||||
class TSink;
|
class TSink;
|
||||||
class TLight;
|
class TLight;
|
||||||
|
@ -87,6 +89,8 @@ public:
|
||||||
static void table_set_multiball(float time);
|
static void table_set_multiball(float time);
|
||||||
static void table_bump_ball_sink_lock();
|
static void table_bump_ball_sink_lock();
|
||||||
static void table_set_replay(float value);
|
static void table_set_replay(float value);
|
||||||
|
static void BallThrowOrDisable(TBall& ball, int dt);
|
||||||
|
static bool CheckBallInControlBounds(const TBall& ball, const TCollisionComponent& cmp);
|
||||||
static void cheat_bump_rank();
|
static void cheat_bump_rank();
|
||||||
static int SpecialAddScore(int score);
|
static int SpecialAddScore(int score);
|
||||||
static int AddRankProgress(int rank);
|
static int AddRankProgress(int rank);
|
||||||
|
|
|
@ -217,6 +217,11 @@ float maths::magnitude(const vector3& vec)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float maths::magnitudeSq(const vector2& vec)
|
||||||
|
{
|
||||||
|
return vec.X * vec.X + vec.Y * vec.Y;
|
||||||
|
}
|
||||||
|
|
||||||
void maths::vector_add(vector2& vec1Dst, const vector2& vec2)
|
void maths::vector_add(vector2& vec1Dst, const vector2& vec2)
|
||||||
{
|
{
|
||||||
vec1Dst.X += vec2.X;
|
vec1Dst.X += vec2.X;
|
||||||
|
@ -312,7 +317,7 @@ float maths::distance_to_flipper(TFlipperEdge* flipper, const ray_type& ray1, ra
|
||||||
{
|
{
|
||||||
auto distance = 1000000000.0f;
|
auto distance = 1000000000.0f;
|
||||||
auto distanceType = FlipperIntersect::none;
|
auto distanceType = FlipperIntersect::none;
|
||||||
auto newDistance = ray_intersect_line(ray1, flipper->lineA);
|
auto newDistance = ray_intersect_line(ray1, flipper->LineA);
|
||||||
if (newDistance < distance)
|
if (newDistance < distance)
|
||||||
{
|
{
|
||||||
distance = newDistance;
|
distance = newDistance;
|
||||||
|
@ -330,7 +335,7 @@ float maths::distance_to_flipper(TFlipperEdge* flipper, const ray_type& ray1, ra
|
||||||
distance = newDistance;
|
distance = newDistance;
|
||||||
distanceType = FlipperIntersect::circleT1;
|
distanceType = FlipperIntersect::circleT1;
|
||||||
}
|
}
|
||||||
newDistance = ray_intersect_line(ray1, flipper->lineB);
|
newDistance = ray_intersect_line(ray1, flipper->LineB);
|
||||||
if (newDistance < distance)
|
if (newDistance < distance)
|
||||||
{
|
{
|
||||||
distance = newDistance;
|
distance = newDistance;
|
||||||
|
@ -340,12 +345,12 @@ float maths::distance_to_flipper(TFlipperEdge* flipper, const ray_type& ray1, ra
|
||||||
switch (distanceType)
|
switch (distanceType)
|
||||||
{
|
{
|
||||||
case FlipperIntersect::lineA:
|
case FlipperIntersect::lineA:
|
||||||
ray2.Direction = flipper->lineA.PerpendicularC;
|
ray2.Direction = flipper->LineA.PerpendicularC;
|
||||||
ray2.Origin = flipper->lineA.RayIntersect;
|
ray2.Origin = flipper->LineA.RayIntersect;
|
||||||
break;
|
break;
|
||||||
case FlipperIntersect::lineB:
|
case FlipperIntersect::lineB:
|
||||||
ray2.Direction = flipper->lineB.PerpendicularC;
|
ray2.Direction = flipper->LineB.PerpendicularC;
|
||||||
ray2.Origin = flipper->lineB.RayIntersect;
|
ray2.Origin = flipper->LineB.RayIntersect;
|
||||||
break;
|
break;
|
||||||
case FlipperIntersect::circlebase:
|
case FlipperIntersect::circlebase:
|
||||||
case FlipperIntersect::circleT1:
|
case FlipperIntersect::circleT1:
|
||||||
|
|
|
@ -114,6 +114,7 @@ public:
|
||||||
static void cross(const vector3& vec1, const vector3& vec2, vector3& dstVec);
|
static void cross(const vector3& vec1, const vector3& vec2, vector3& dstVec);
|
||||||
static float cross(const vector2& vec1, const vector2& vec2);
|
static float cross(const vector2& vec1, const vector2& vec2);
|
||||||
static float magnitude(const vector3& vec);
|
static float magnitude(const vector3& vec);
|
||||||
|
static float magnitudeSq(const vector2& vec);
|
||||||
static void vector_add(vector2& vec1Dst, const vector2& vec2);
|
static void vector_add(vector2& vec1Dst, const vector2& vec2);
|
||||||
static vector2 vector_sub(const vector2& vec1, const vector2& vec2);
|
static vector2 vector_sub(const vector2& vec1, const vector2& vec2);
|
||||||
static vector3 vector_sub(const vector3& vec1, const vector3& vec2);
|
static vector3 vector_sub(const vector3& vec1, const vector3& vec2);
|
||||||
|
|
|
@ -324,13 +324,45 @@ void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls)
|
||||||
|
|
||||||
for (auto ball : MainTable->BallList)
|
for (auto ball : MainTable->BallList)
|
||||||
{
|
{
|
||||||
|
if (!ball->ActiveFlag || ball->HasGroupFlag || ball->CollisionComp || ball->Speed >= 0.8f)
|
||||||
|
{
|
||||||
|
if (ball->SomeCounter1 > 0)
|
||||||
|
{
|
||||||
|
vector2 dxy{ball->Position.X - ball->PrevPosition.X, ball->Position.Y - ball->PrevPosition.Y};
|
||||||
|
auto offsetX2 = ball->Offset * 2.0f;
|
||||||
|
if (offsetX2 * offsetX2 < maths::magnitudeSq(dxy))
|
||||||
|
ball->SomeCounter1 = 0;
|
||||||
|
}
|
||||||
|
ball->time_ticks1 = ball->time_ticks2 = time_ticks;
|
||||||
|
}
|
||||||
|
else if (time_ticks - ball->time_ticks2 > 500)
|
||||||
|
{
|
||||||
|
vector2 dxy{ball->Position.X - ball->PrevPosition.X, ball->Position.Y - ball->PrevPosition.Y};
|
||||||
|
auto offsetD2 = ball->Offset / 2.0f;
|
||||||
|
ball->PrevPosition = ball->Position;
|
||||||
|
if (offsetD2 * offsetD2 < maths::magnitudeSq(dxy))
|
||||||
|
ball->SomeCounter1 = 0;
|
||||||
|
else
|
||||||
|
ball->SomeCounter1++;
|
||||||
|
control::BallThrowOrDisable(*ball, time_ticks - ball->time_ticks1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int distanceCoefArray[20]{-1};
|
||||||
|
float distanceArray[20]{}, distanceArrayX[20]{}, distanceArrayY[20]{};
|
||||||
|
int minDistanceCoef = -1;
|
||||||
|
for (auto index = 0u; index < MainTable->BallList.size(); index++)
|
||||||
|
{
|
||||||
|
auto ball = MainTable->BallList[index];
|
||||||
if (ball->ActiveFlag != 0)
|
if (ball->ActiveFlag != 0)
|
||||||
{
|
|
||||||
auto collComp = ball->CollisionComp;
|
|
||||||
if (collComp)
|
|
||||||
{
|
{
|
||||||
ball->TimeDelta = timeDelta;
|
ball->TimeDelta = timeDelta;
|
||||||
collComp->FieldEffect(ball, &vec1);
|
if (ball->TimeDelta > 0.01f && ball->Speed < 0.8f)
|
||||||
|
ball->TimeDelta = 0.01f;
|
||||||
|
ball->AsEdgeCollisionFlag = false;
|
||||||
|
if (ball->CollisionComp)
|
||||||
|
{
|
||||||
|
ball->CollisionComp->FieldEffect(ball, &vec1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -345,23 +377,107 @@ void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls)
|
||||||
ball->Direction.Y = ball->Speed * ball->Direction.Y;
|
ball->Direction.Y = ball->Speed * ball->Direction.Y;
|
||||||
maths::vector_add(ball->Direction, vec2);
|
maths::vector_add(ball->Direction, vec2);
|
||||||
ball->Speed = maths::normalize_2d(ball->Direction);
|
ball->Speed = maths::normalize_2d(ball->Direction);
|
||||||
}
|
if (ball->Speed > ball_speed_limit)
|
||||||
|
ball->Speed = ball_speed_limit;
|
||||||
|
|
||||||
auto timeDelta2 = timeDelta;
|
distanceArray[index] = ball->Speed * ball->TimeDelta;
|
||||||
auto timeNow2 = timeNow;
|
auto distanceCoef = static_cast<int>(std::ceil(distanceArray[index] * ball_inv_smth)) - 1;
|
||||||
for (auto index = 10; timeDelta2 > 0.000001f && index; --index)
|
distanceCoefArray[index] = distanceCoef;
|
||||||
|
if (distanceCoef >= 0)
|
||||||
{
|
{
|
||||||
auto time = collide(timeNow2, timeDelta2, ball);
|
distanceArrayX[index] = ball->Direction.X * ball_min_smth;
|
||||||
timeDelta2 -= time;
|
distanceArrayY[index] = ball->Direction.Y * ball_min_smth;
|
||||||
timeNow2 += time;
|
if (distanceCoef > minDistanceCoef)
|
||||||
|
minDistanceCoef = distanceCoef;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto flipper : MainTable->FlipperList)
|
float deltaAngle[4]{};
|
||||||
|
for (auto index = 0u; index < MainTable->FlipperList.size(); index++)
|
||||||
{
|
{
|
||||||
flipper->UpdateSprite(timeNow);
|
auto distanceCoef = MainTable->FlipperList[index]->GetFlipperAngleDistance(timeDelta, &deltaAngle[index]) - 1;
|
||||||
|
distanceArrayY[index] = static_cast<float>(distanceCoef);
|
||||||
|
if (distanceCoef > minDistanceCoef)
|
||||||
|
minDistanceCoef = distanceCoef;
|
||||||
|
}
|
||||||
|
|
||||||
|
ray_type ray{};
|
||||||
|
ray.MinDistance = 0.002f;
|
||||||
|
for (auto index4 = 0; index4 <= minDistanceCoef; index4++)
|
||||||
|
{
|
||||||
|
for (auto index5 = 0u; index5 < MainTable->BallList.size(); index5++)
|
||||||
|
{
|
||||||
|
auto ball = MainTable->BallList[index5];
|
||||||
|
if (!ball->AsEdgeCollisionFlag && index4 <= distanceCoefArray[index5])
|
||||||
|
{
|
||||||
|
float distanceSum = 0.0f;
|
||||||
|
ray.CollisionMask = ball->CollisionMask;
|
||||||
|
ball->TimeNow = timeNow;
|
||||||
|
if (ball_min_smth > 0.0f)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
ray.Origin = ball->Position;
|
||||||
|
ray.Direction = ball->Direction;
|
||||||
|
if (index4 >= distanceCoefArray[index5])
|
||||||
|
{
|
||||||
|
ray.MaxDistance = distanceArray[index5] - distanceCoefArray[index5] * ball_min_smth;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ray.MaxDistance = ball_min_smth;
|
||||||
|
}
|
||||||
|
ray.TimeNow = ball->TimeNow;
|
||||||
|
|
||||||
|
TEdgeSegment* edge = nullptr;
|
||||||
|
auto distance = TTableLayer::edge_manager->FindCollisionDistance(&ray, ball, &edge);
|
||||||
|
if (distance > 0.0f)
|
||||||
|
{
|
||||||
|
// Todo: ball to ball collision
|
||||||
|
//distance = ball_to_ball_collision();
|
||||||
|
}
|
||||||
|
if (ball->EdgeCollisionResetFlag)
|
||||||
|
{
|
||||||
|
ball->EdgeCollisionResetFlag = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ball->EdgeCollisionCount = 0;
|
||||||
|
ball->EdgeCollisionResetFlag = true;
|
||||||
|
}
|
||||||
|
if (distance >= 1e9f)
|
||||||
|
{
|
||||||
|
ball->Position.X += ray.MaxDistance * ray.Direction.X;
|
||||||
|
ball->Position.Y += ray.MaxDistance * ray.Direction.Y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
edge->EdgeCollision(ball, distance);
|
||||||
|
if (distance > 0.0f && !ball->AsEdgeCollisionFlag)
|
||||||
|
{
|
||||||
|
distanceSum += distance;
|
||||||
|
if (distanceSum < ball_min_smth)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto index = 0u; index < MainTable->FlipperList.size(); index++)
|
||||||
|
{
|
||||||
|
if (distanceArrayY[index] >= index4)
|
||||||
|
MainTable->FlipperList[index]->FlipperCollision(deltaAngle[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto flipper : MainTable->FlipperList)
|
||||||
|
{
|
||||||
|
flipper->UpdateSprite();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drawBalls)
|
if (drawBalls)
|
||||||
|
@ -511,9 +627,9 @@ void pb::InputDown(GameInput input)
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
{
|
{
|
||||||
high_score_struct entry{ {0}, 1000000000 };
|
high_score_struct entry{{0}, 1000000000};
|
||||||
strncpy(entry.Name, get_rc_string(Msg::STRING127), sizeof entry.Name - 1);
|
strncpy(entry.Name, get_rc_string(Msg::STRING127), sizeof entry.Name - 1);
|
||||||
high_score::show_and_set_high_score_dialog({ entry, 1 });
|
high_score::show_and_set_high_score_dialog({entry, 1});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'r':
|
case 'r':
|
||||||
|
@ -580,20 +696,24 @@ void pb::end_game()
|
||||||
int position = high_score::get_score_position(scores[i]);
|
int position = high_score::get_score_position(scores[i]);
|
||||||
if (position >= 0)
|
if (position >= 0)
|
||||||
{
|
{
|
||||||
high_score_struct entry{ {0}, scores[i] };
|
high_score_struct entry{{0}, scores[i]};
|
||||||
const char* playerName;
|
const char* playerName;
|
||||||
|
|
||||||
switch(scoreIndex[i])
|
switch (scoreIndex[i])
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case 0: playerName = get_rc_string(Msg::STRING127); break;
|
case 0: playerName = get_rc_string(Msg::STRING127);
|
||||||
case 1: playerName = get_rc_string(Msg::STRING128); break;
|
break;
|
||||||
case 2: playerName = get_rc_string(Msg::STRING129); break;
|
case 1: playerName = get_rc_string(Msg::STRING128);
|
||||||
case 3: playerName = get_rc_string(Msg::STRING130); break;
|
break;
|
||||||
|
case 2: playerName = get_rc_string(Msg::STRING129);
|
||||||
|
break;
|
||||||
|
case 3: playerName = get_rc_string(Msg::STRING130);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(entry.Name, playerName, sizeof entry.Name - 1);
|
strncpy(entry.Name, playerName, sizeof entry.Name - 1);
|
||||||
high_score::show_and_set_high_score_dialog({ entry, -1 });
|
high_score::show_and_set_high_score_dialog({entry, -1});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue