From ba470e87272ccf996c6fb7d9f2af41b83cadccb6 Mon Sep 17 00:00:00 2001 From: Muzychenko Andrey <33288308+k4zmu2a@users.noreply.github.com> Date: Sat, 4 Mar 2023 17:31:23 +0300 Subject: [PATCH] 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. --- SpaceCadetPinball/DebugOverlay.cpp | 7 +- SpaceCadetPinball/TBall.cpp | 22 +- SpaceCadetPinball/TBall.h | 12 +- SpaceCadetPinball/TFlipper.cpp | 97 ++++++- SpaceCadetPinball/TFlipper.h | 4 +- SpaceCadetPinball/TFlipperEdge.cpp | 408 ++++++++-------------------- SpaceCadetPinball/TFlipperEdge.h | 31 +-- SpaceCadetPinball/THole.cpp | 5 + SpaceCadetPinball/TKickout.cpp | 12 +- SpaceCadetPinball/TPinballTable.cpp | 3 + SpaceCadetPinball/TSink.cpp | 3 +- SpaceCadetPinball/control.cpp | 31 +++ SpaceCadetPinball/control.h | 4 + SpaceCadetPinball/maths.cpp | 17 +- SpaceCadetPinball/maths.h | 1 + SpaceCadetPinball/pb.cpp | 228 ++++++++++++---- 16 files changed, 489 insertions(+), 396 deletions(-) diff --git a/SpaceCadetPinball/DebugOverlay.cpp b/SpaceCadetPinball/DebugOverlay.cpp index 7621462..13cbc2c 100644 --- a/SpaceCadetPinball/DebugOverlay.cpp +++ b/SpaceCadetPinball/DebugOverlay.cpp @@ -344,10 +344,11 @@ void DebugOverlay::DrawEdge(TEdgeSegment* edge) auto flip = dynamic_cast(edge); if (flip) { - flip->set_control_points(pb::time_now); + if (flip->ControlPointDirtyFlag) + flip->set_control_points(flip->CurrentAngle); - DrawLineType(flip->lineA); - DrawLineType(flip->lineB); + DrawLineType(flip->LineA); + DrawLineType(flip->LineB); DrawCicleType(flip->circlebase); DrawCicleType(flip->circleT1); } diff --git a/SpaceCadetPinball/TBall.cpp b/SpaceCadetPinball/TBall.cpp index 0f53a31..c10f085 100644 --- a/SpaceCadetPinball/TBall.cpp +++ b/SpaceCadetPinball/TBall.cpp @@ -29,6 +29,7 @@ TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false) Direction.X = 0.0; Position.X = 0.0; Position.Y = 0.0; + HasGroupFlag = false; ListBitmap = new std::vector(); @@ -81,11 +82,19 @@ void TBall::Repaint() void TBall::not_again(TEdgeSegment* edge) { - if (EdgeCollisionCount < 5) + if (EdgeCollisionCount < 16) { Collisions[EdgeCollisionCount] = edge; ++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) @@ -119,15 +128,15 @@ int TBall::Message(MessageCode code, float value) 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; - ball->Direction = *direction; + CollisionComp = nullptr; + Direction = *direction; float rnd = RandFloat(); float angle = (1.0f - (rnd + rnd)) * angleMult; - maths::RotateVector(ball->Direction, angle); + maths::RotateVector(Direction, angle); rnd = RandFloat(); - ball->Speed = (1.0f - (rnd + rnd)) * (speedMult1 * speedMult2) + speedMult1; + Speed = (1.0f - (rnd + rnd)) * (speedMult1 * speedMult2) + speedMult1; } vector2 TBall::get_coordinates() @@ -138,5 +147,6 @@ vector2 TBall::get_coordinates() void TBall::Disable() { ActiveFlag = false; + AsEdgeCollisionFlag = true; SpriteSet(-1); } diff --git a/SpaceCadetPinball/TBall.h b/SpaceCadetPinball/TBall.h index 96f8a0b..528ef7c 100644 --- a/SpaceCadetPinball/TBall.h +++ b/SpaceCadetPinball/TBall.h @@ -15,11 +15,10 @@ public : int Message(MessageCode code, float value) override; vector2 get_coordinates() override; void Disable(); - - static void throw_ball(TBall* ball, vector3* direction, float angleMult, float speedMult1, - float speedMult2); + void throw_ball(vector3* direction, float angleMult, float speedMult1, float speedMult2); vector3 Position{}; + vector3 PrevPosition{}; vector3 Direction{}; float Speed; float RayMaxDistance; @@ -28,10 +27,15 @@ public : vector2 RampFieldForce{}; TCollisionComponent* CollisionComp; int CollisionMask; - TEdgeSegment* Collisions[5]{}; + TEdgeSegment* Collisions[16]{}; int EdgeCollisionCount; + bool EdgeCollisionResetFlag{}; vector3 CollisionOffset{}; int CollisionFlag; float Offset; + bool HasGroupFlag; + int SomeCounter1 = 0; + int time_ticks1{}, time_ticks2{}; float VisualZArray[50]{}; + bool AsEdgeCollisionFlag{}; }; diff --git a/SpaceCadetPinball/TFlipper.cpp b/SpaceCadetPinball/TFlipper.cpp index 300c356..15d49e6 100644 --- a/SpaceCadetPinball/TFlipper.cpp +++ b/SpaceCadetPinball/TFlipper.cpp @@ -6,6 +6,7 @@ #include "loader.h" #include "pb.h" #include "render.h" +#include "TBall.h" #include "TFlipperEdge.h" #include "timer.h" #include "TPinballTable.h" @@ -84,15 +85,17 @@ int TFlipper::Message(MessageCode code, float value) code = MessageCode::TFlipperRetract; } - MessageField = FlipperEdge->SetMotion(code, value); + MessageField = FlipperEdge->SetMotion(code); break; case MessageCode::PlayerChanged: case MessageCode::Reset: if (MessageField) { + FlipperEdge->CurrentAngle = 0; + FlipperEdge->set_control_points(0); MessageField = 0; - FlipperEdge->SetMotion(MessageCode::Reset, value); - UpdateSprite(0); + FlipperEdge->SetMotion(MessageCode::Reset); + UpdateSprite(); } 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; - auto newBmpIndex = static_cast(floor(FlipperEdge->flipper_angle(timeNow) / FlipperEdge->AngleMax * bmpCountSub1 + 0.5f)); + auto newBmpIndex = static_cast(floor(FlipperEdge->CurrentAngle / FlipperEdge->AngleMax * bmpCountSub1 + 0.5f)); newBmpIndex = Clamp(newBmpIndex, 0, bmpCountSub1); if (BmpIndex == newBmpIndex) return; @@ -122,3 +125,87 @@ void TFlipper::UpdateSprite(float timeNow) BmpIndex = newBmpIndex; 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(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; + } +} diff --git a/SpaceCadetPinball/TFlipper.h b/SpaceCadetPinball/TFlipper.h index edfed89..f6a6218 100644 --- a/SpaceCadetPinball/TFlipper.h +++ b/SpaceCadetPinball/TFlipper.h @@ -13,7 +13,9 @@ public: void port_draw() override; void Collision(TBall* ball, vector2* nextPosition, vector2* direction, float distance, TEdgeSegment* edge) override; - void UpdateSprite(float timeNow); + void UpdateSprite(); + int GetFlipperAngleDistance(float dt, float* dst) const; + void FlipperCollision(float deltaAngle); int BmpIndex; TFlipperEdge* FlipperEdge; diff --git a/SpaceCadetPinball/TFlipperEdge.cpp b/SpaceCadetPinball/TFlipperEdge.cpp index c0602e2..9545e7b 100644 --- a/SpaceCadetPinball/TFlipperEdge.cpp +++ b/SpaceCadetPinball/TFlipperEdge.cpp @@ -8,9 +8,11 @@ #include "TTableLayer.h" -TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsigned int collisionGroup, TPinballTable* table, - vector3* origin, vector3* vecT1, vector3* vecT2, float extendTime, float retractTime, - float collMult, float elasticity, float smoothness): TEdgeSegment(collComp, activeFlag, collisionGroup) +TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsigned int collisionGroup, + TPinballTable* table, + vector3* origin, vector3* vecT1, vector3* vecT2, float extendSpeed, float retractSpeed, + float collMult, float elasticity, float smoothness): TEdgeSegment( + collComp, activeFlag, collisionGroup) { 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: Time it takes for flipper to go from source to destination, in sec. // FT: Flipper movement speed, in radians per sec. - if (pb::FullTiltMode) + if (!pb::FullTiltMode) { auto angleMax = std::abs(AngleMax); - retractTime = angleMax / retractTime; - extendTime = angleMax / extendTime; + retractSpeed = angleMax / retractSpeed; + extendSpeed = angleMax / extendSpeed; } - ExtendTime = extendTime; - RetractTime = retractTime; + ExtendSpeed = extendSpeed; + RetractSpeed = retractSpeed; - const vector2 perpOriginT1Cc = { -vecOriginT1.Y , vecOriginT1.X }; + 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; - const vector2 perpOriginT1C = { vecOriginT1.Y , -vecOriginT1.X }; + 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; @@ -82,249 +84,94 @@ TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsi auto dx = vecT1->X - RotOrigin.X; auto dy = vecT1->Y - RotOrigin.Y; auto distance1 = sqrt(dy * dy + dx * dx) + table->CollisionCompOffset + vecT1->Z; + DistanceDiv = distance1; DistanceDivSq = distance1 * distance1; + InvT1Radius = 1.0f / CircleT1Radius * 1.5f; - float minMoveTime = std::min(ExtendTime, RetractTime); - auto distance = maths::Distance(*vecT1, *vecT2); - CollisionTimeAdvance = minMoveTime / (distance / CircleT1Radius + distance / CircleT1Radius); - - EdgeCollisionFlag = 0; - InputTime = 0.0; - CollisionFlag1 = 0; - AngleStopTime = 0.0; - AngleAdvanceTime = 0.0; + if (AngleMax <= 0.0f) + { + ExtendSpeed = -ExtendSpeed; + } + else + { + RetractSpeed = -RetractSpeed; + } + set_control_points(CurrentAngle); } void TFlipperEdge::port_draw() { - set_control_points(InputTime); + set_control_points(CurrentAngle); } float TFlipperEdge::FindCollisionDistance(ray_type* ray) { - auto ogRay = ray; - ray_type dstRay{}, srcRay{}; + ray_type dstRay{}; + 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.X -= srcRay.Direction.X * 1e-05f; - NextBallPosition.Y -= srcRay.Direction.Y * 1e-05f; - } - else - { - NextBallPosition = dstRay.Origin; - } - CollisionDirection = dstRay.Direction; - 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; + NextBallPosition = dstRay.Origin; + CollisionDirection = dstRay.Direction; + return distance; } void TFlipperEdge::EdgeCollision(TBall* ball, float distance) { - EdgeCollisionFlag = 1; - if (FlipperFlag == MessageCode::TFlipperNull || !CollisionFlag2 || CollisionFlag1) + if (FlipperFlag == MessageCode::TFlipperNull) { - float boost = 0.0; - if (CollisionFlag1) + maths::basic_collision( + ball, + &NextBallPosition, + &CollisionDirection, + Elasticity, + Smoothness, + 1e9f, + 0); + return; + } + + 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) { - float dx = NextBallPosition.X - RotOrigin.X; - float dy = NextBallPosition.Y - RotOrigin.Y; - float distanceSq = dy * dy + dx * dx; - if (circlebase.RadiusSq * 1.01f < distanceSq) - { - float v11; - 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; - } + auto v21 = std::fabs(MoveSpeed) * std::sqrt(distanceSq / DistanceDivSq); + auto dot1 = maths::DotProduct(CollisionLinePerp, CollisionDirection); + if (dot1 >= 0) + boost = CollisionMult * dot1 * v21; } - float threshold = boost <= 0.0f ? 1000000000.0f : -1.0f; + auto threshold = boost <= 0.0f ? 1e9f : -1.0f; maths::basic_collision( ball, &NextBallPosition, @@ -333,18 +180,14 @@ void TFlipperEdge::EdgeCollision(TBall* ball, float distance) Smoothness, threshold, 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 - 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) @@ -360,12 +203,18 @@ void TFlipperEdge::place_in_grid(RectF* aabb) } 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; - maths::SinCos(flipper_angle(timeNow), sin, cos); + maths::SinCos(angle, sin, cos); A1 = A1Src; A2 = A2Src; B1 = B1Src; @@ -376,83 +225,48 @@ void TFlipperEdge::set_control_points(float timeNow) maths::RotatePt(T1, sin, cos, RotOrigin); maths::RotatePt(B1, sin, cos, RotOrigin); maths::RotatePt(B2, sin, cos, RotOrigin); - 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(LineA, A1.X, A1.Y, A2.X, A2.Y); + maths::line_init(LineB, B1.X, B1.Y, B2.X, B2.Y); circlebase = {RotOrigin, CirclebaseRadiusSq}; 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) - return AngleDst; + return 0.0f; - // How much time it takes to go from source to destination angle, in sec. - auto arcDuration = std::abs((AngleDst - AngleSrc) / AngleMax * AngleAdvanceTime); - - // How close the flipper is to destination, in [0, 1] range. - 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); + const auto deltaAngle = MoveSpeed * timeDelta; + if (std::fabs(deltaAngle) > AngleRemainder) + return AngleDst - CurrentAngle; + return deltaAngle; } -int TFlipperEdge::is_ball_inside(float x, float y) -{ - 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) +int TFlipperEdge::SetMotion(MessageCode code) { switch (code) { case MessageCode::TFlipperExtend: - AngleSrc = flipper_angle(value); + AngleRemainder = std::fabs(AngleMax - CurrentAngle); AngleDst = AngleMax; - AngleAdvanceTime = ExtendTime; + MoveSpeed = ExtendSpeed; break; case MessageCode::TFlipperRetract: - AngleSrc = flipper_angle(value); + AngleRemainder = std::fabs(CurrentAngle); AngleDst = 0.0f; - AngleAdvanceTime = RetractTime; + MoveSpeed = RetractSpeed; break; case MessageCode::Reset: - AngleSrc = 0.0f; + AngleRemainder = 0.0f; AngleDst = 0.0f; break; default: break; } - if (AngleSrc == AngleDst) + if (AngleRemainder == 0.0f) code = MessageCode::TFlipperNull; - InputTime = value; FlipperFlag = code; - AngleStopTime = AngleAdvanceTime + InputTime; return static_cast(code); } diff --git a/SpaceCadetPinball/TFlipperEdge.h b/SpaceCadetPinball/TFlipperEdge.h index d0f4653..710f8d9 100644 --- a/SpaceCadetPinball/TFlipperEdge.h +++ b/SpaceCadetPinball/TFlipperEdge.h @@ -9,16 +9,15 @@ class TFlipperEdge : public TEdgeSegment { public: 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); void port_draw() override; float FindCollisionDistance(ray_type* ray) override; void EdgeCollision(TBall* ball, float distance) 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); - int SetMotion(MessageCode code, float value); + void set_control_points(float angle); + float flipper_angle_delta(float timeDelta); + int SetMotion(MessageCode code); MessageCode FlipperFlag{}; float Elasticity; @@ -31,10 +30,9 @@ public: float CirclebaseRadiusMSq; float CircleT1RadiusMSq; float AngleMax; - float AngleSrc{}; + float AngleRemainder{}; float AngleDst; - int CollisionFlag1; - int CollisionFlag2{}; + float CurrentAngle{}; vector2 CollisionLinePerp{}; vector2 A1Src{}; vector2 A2Src{}; @@ -43,17 +41,16 @@ public: float CollisionMult; vector2 T1Src{}; vector2 T2Src{}; - float DistanceDivSq; - float CollisionTimeAdvance; + float DistanceDiv, DistanceDivSq; vector2 CollisionDirection{}; - int EdgeCollisionFlag; - float InputTime; - float AngleStopTime; - float AngleAdvanceTime; - float ExtendTime; - float RetractTime; + float ExtendSpeed; + float RetractSpeed; + float MoveSpeed; vector2 NextBallPosition{}; vector2 A1, A2, B1, B2, T1; - line_type lineA, lineB; + line_type LineA, LineB; circle_type circlebase, circleT1; + float InvT1Radius; + float YMin, YMax, XMin, XMax; + bool ControlPointDirtyFlag{}; }; diff --git a/SpaceCadetPinball/THole.cpp b/SpaceCadetPinball/THole.cpp index 6aaef00..2db2af5 100644 --- a/SpaceCadetPinball/THole.cpp +++ b/SpaceCadetPinball/THole.cpp @@ -80,6 +80,7 @@ void THole::Collision(TBall* ball, vector2* nextPosition, vector2* direction, fl ball->Position.X = Circle.Center.X; ball->Position.Y = Circle.Center.Y; ball->Direction.Z = 0.0; + ball->AsEdgeCollisionFlag = true; // Ramp hole has no delay in FT. 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); } } + else + { + DefaultCollision(ball, nextPosition, direction); + } } int THole::FieldEffect(TBall* ball, vector2* vecDst) diff --git a/SpaceCadetPinball/TKickout.cpp b/SpaceCadetPinball/TKickout.cpp index 90591c8..73fba06 100644 --- a/SpaceCadetPinball/TKickout.cpp +++ b/SpaceCadetPinball/TKickout.cpp @@ -104,7 +104,8 @@ void TKickout::Collision(TBall* ball, vector2* nextPosition, vector2* direction, ball->Position.X = Circle.Center.X; ball->Position.Y = Circle.Center.Y; OriginalBallZ = ball->Position.Z; - ball->Position.Z = CollisionBallSetZ; + ball->Position.Z = CollisionBallSetZ; + ball->AsEdgeCollisionFlag = true; if (PinballTable->TiltLockFlag) { Message(MessageCode::TKickoutRestartTimer, 0.1f); @@ -115,6 +116,13 @@ void TKickout::Collision(TBall* ball, vector2* nextPosition, vector2* direction, 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) @@ -144,7 +152,7 @@ void TKickout::TimerExpired(int timerId, void* caller) { loader::play_sound(kick->HardHitSoundId, kick->Ball, "TKickout2"); 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->ActiveFlag = 0; kick->Ball = nullptr; diff --git a/SpaceCadetPinball/TPinballTable.cpp b/SpaceCadetPinball/TPinballTable.cpp index 8e9cd17..5b494ea 100644 --- a/SpaceCadetPinball/TPinballTable.cpp +++ b/SpaceCadetPinball/TPinballTable.cpp @@ -631,6 +631,9 @@ TBall* TPinballTable::AddBall(float x, float y) ball->Position.X = x; ball->Position.Y = y; + ball->PrevPosition = ball->Position; + ball->SomeCounter1 = 0; + ball->time_ticks1 = ball->time_ticks2 = pb::time_ticks; return ball; } diff --git a/SpaceCadetPinball/TSink.cpp b/SpaceCadetPinball/TSink.cpp index b5db3cc..295906b 100644 --- a/SpaceCadetPinball/TSink.cpp +++ b/SpaceCadetPinball/TSink.cpp @@ -88,7 +88,8 @@ void TSink::TimerExpired(int timerId, void* caller) { auto ball = table->AddBall(sink->BallPosition.X, sink->BallPosition.Y); 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); if (sink->SoundIndex3) loader::play_sound(sink->SoundIndex3, ball, "TSink2"); diff --git a/SpaceCadetPinball/control.cpp b/SpaceCadetPinball/control.cpp index b369424..b9f5d94 100644 --- a/SpaceCadetPinball/control.cpp +++ b/SpaceCadetPinball/control.cpp @@ -3,6 +3,7 @@ #include "midi.h" #include "pb.h" +#include "TBall.h" #include "TBlocker.h" #include "TBumper.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 prevFlag1 = TableG->ScoreSpecial3Flag; diff --git a/SpaceCadetPinball/control.h b/SpaceCadetPinball/control.h index a5999e1..3d2bd3c 100644 --- a/SpaceCadetPinball/control.h +++ b/SpaceCadetPinball/control.h @@ -1,5 +1,7 @@ #pragma once +class TCollisionComponent; +class TBall; enum class MessageCode; class TSink; class TLight; @@ -87,6 +89,8 @@ public: static void table_set_multiball(float time); static void table_bump_ball_sink_lock(); 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 int SpecialAddScore(int score); static int AddRankProgress(int rank); diff --git a/SpaceCadetPinball/maths.cpp b/SpaceCadetPinball/maths.cpp index 382aab2..708f34d 100644 --- a/SpaceCadetPinball/maths.cpp +++ b/SpaceCadetPinball/maths.cpp @@ -217,6 +217,11 @@ float maths::magnitude(const vector3& vec) 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) { 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 distanceType = FlipperIntersect::none; - auto newDistance = ray_intersect_line(ray1, flipper->lineA); + auto newDistance = ray_intersect_line(ray1, flipper->LineA); if (newDistance < distance) { distance = newDistance; @@ -330,7 +335,7 @@ float maths::distance_to_flipper(TFlipperEdge* flipper, const ray_type& ray1, ra distance = newDistance; distanceType = FlipperIntersect::circleT1; } - newDistance = ray_intersect_line(ray1, flipper->lineB); + newDistance = ray_intersect_line(ray1, flipper->LineB); if (newDistance < distance) { distance = newDistance; @@ -340,12 +345,12 @@ float maths::distance_to_flipper(TFlipperEdge* flipper, const ray_type& ray1, ra switch (distanceType) { case FlipperIntersect::lineA: - ray2.Direction = flipper->lineA.PerpendicularC; - ray2.Origin = flipper->lineA.RayIntersect; + ray2.Direction = flipper->LineA.PerpendicularC; + ray2.Origin = flipper->LineA.RayIntersect; break; case FlipperIntersect::lineB: - ray2.Direction = flipper->lineB.PerpendicularC; - ray2.Origin = flipper->lineB.RayIntersect; + ray2.Direction = flipper->LineB.PerpendicularC; + ray2.Origin = flipper->LineB.RayIntersect; break; case FlipperIntersect::circlebase: case FlipperIntersect::circleT1: diff --git a/SpaceCadetPinball/maths.h b/SpaceCadetPinball/maths.h index 6ba3c32..f230eeb 100644 --- a/SpaceCadetPinball/maths.h +++ b/SpaceCadetPinball/maths.h @@ -114,6 +114,7 @@ public: static void cross(const vector3& vec1, const vector3& vec2, vector3& dstVec); static float cross(const vector2& vec1, const vector2& vec2); static float magnitude(const vector3& vec); + static float magnitudeSq(const vector2& vec); static void vector_add(vector2& vec1Dst, const vector2& vec2); static vector2 vector_sub(const vector2& vec1, const vector2& vec2); static vector3 vector_sub(const vector3& vec1, const vector3& vec2); diff --git a/SpaceCadetPinball/pb.cpp b/SpaceCadetPinball/pb.cpp index d41b664..e199da7 100644 --- a/SpaceCadetPinball/pb.cpp +++ b/SpaceCadetPinball/pb.cpp @@ -324,13 +324,45 @@ void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls) 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) { - auto collComp = ball->CollisionComp; - if (collComp) + ball->TimeDelta = timeDelta; + if (ball->TimeDelta > 0.01f && ball->Speed < 0.8f) + ball->TimeDelta = 0.01f; + ball->AsEdgeCollisionFlag = false; + if (ball->CollisionComp) { - ball->TimeDelta = timeDelta; - collComp->FieldEffect(ball, &vec1); + ball->CollisionComp->FieldEffect(ball, &vec1); } else { @@ -345,23 +377,107 @@ void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls) ball->Direction.Y = ball->Speed * ball->Direction.Y; maths::vector_add(ball->Direction, vec2); ball->Speed = maths::normalize_2d(ball->Direction); - } + if (ball->Speed > ball_speed_limit) + ball->Speed = ball_speed_limit; - auto timeDelta2 = timeDelta; - auto timeNow2 = timeNow; - for (auto index = 10; timeDelta2 > 0.000001f && index; --index) - { - auto time = collide(timeNow2, timeDelta2, ball); - timeDelta2 -= time; - timeNow2 += time; + distanceArray[index] = ball->Speed * ball->TimeDelta; + auto distanceCoef = static_cast(std::ceil(distanceArray[index] * ball_inv_smth)) - 1; + distanceCoefArray[index] = distanceCoef; + if (distanceCoef >= 0) + { + distanceArrayX[index] = ball->Direction.X * ball_min_smth; + distanceArrayY[index] = ball->Direction.Y * ball_min_smth; + 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(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) @@ -423,7 +539,7 @@ void pb::InputUp(GameInput input) { if (game_mode != GameModes::InGame || winmain::single_step || demo_mode) return; - + const auto bindings = options::MapGameInput(input); for (const auto binding : bindings) { @@ -454,7 +570,7 @@ void pb::InputUp(GameInput input) void pb::InputDown(GameInput input) { - if (options::WaitingForInput()) + if (options::WaitingForInput()) { options::InputDown(input); return; @@ -475,31 +591,31 @@ void pb::InputDown(GameInput input) for (const auto binding : bindings) { switch (binding) - { - case GameBindings::LeftFlipper: - MainTable->Message(MessageCode::LeftFlipperInputPressed, time_now); - break; - case GameBindings::RightFlipper: - MainTable->Message(MessageCode::RightFlipperInputPressed, time_now); - break; - case GameBindings::Plunger: - MainTable->Message(MessageCode::PlungerInputPressed, time_now); - break; - case GameBindings::LeftTableBump: - if (!MainTable->TiltLockFlag) - nudge::nudge_right(); - break; - case GameBindings::RightTableBump: - if (!MainTable->TiltLockFlag) - nudge::nudge_left(); - break; - case GameBindings::BottomTableBump: - if (!MainTable->TiltLockFlag) - nudge::nudge_up(); - break; - default: break; - } + { + case GameBindings::LeftFlipper: + MainTable->Message(MessageCode::LeftFlipperInputPressed, time_now); + break; + case GameBindings::RightFlipper: + MainTable->Message(MessageCode::RightFlipperInputPressed, time_now); + break; + case GameBindings::Plunger: + MainTable->Message(MessageCode::PlungerInputPressed, time_now); + break; + case GameBindings::LeftTableBump: + if (!MainTable->TiltLockFlag) + nudge::nudge_right(); + break; + case GameBindings::RightTableBump: + if (!MainTable->TiltLockFlag) + nudge::nudge_left(); + break; + case GameBindings::BottomTableBump: + if (!MainTable->TiltLockFlag) + nudge::nudge_up(); + break; + default: break; } + } if (cheat_mode && input.Type == InputTypes::Keyboard) { @@ -510,12 +626,12 @@ void pb::InputDown(GameInput input) MainTable->MultiballCount++; break; case 'h': - { - high_score_struct entry{ {0}, 1000000000 }; - strncpy(entry.Name, get_rc_string(Msg::STRING127), sizeof entry.Name - 1); - high_score::show_and_set_high_score_dialog({ entry, 1 }); - break; - } + { + high_score_struct entry{{0}, 1000000000}; + strncpy(entry.Name, get_rc_string(Msg::STRING127), sizeof entry.Name - 1); + high_score::show_and_set_high_score_dialog({entry, 1}); + break; + } case 'r': control::cheat_bump_rank(); break; @@ -580,20 +696,24 @@ void pb::end_game() int position = high_score::get_score_position(scores[i]); if (position >= 0) { - high_score_struct entry{ {0}, scores[i] }; + high_score_struct entry{{0}, scores[i]}; const char* playerName; - switch(scoreIndex[i]) + switch (scoreIndex[i]) { - default: - case 0: playerName = get_rc_string(Msg::STRING127); break; - case 1: playerName = get_rc_string(Msg::STRING128); break; - case 2: playerName = get_rc_string(Msg::STRING129); break; - case 3: playerName = get_rc_string(Msg::STRING130); break; + default: + case 0: playerName = get_rc_string(Msg::STRING127); + break; + case 1: playerName = get_rc_string(Msg::STRING128); + 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); - high_score::show_and_set_high_score_dialog({ entry, -1 }); + high_score::show_and_set_high_score_dialog({entry, -1}); } } }