Fixed flipper animation frame skip bug.

It is from original 3DPB, not present in FT.
This commit is contained in:
Muzychenko Andrey 2021-10-07 08:01:34 +03:00
parent 7ee508118c
commit 48721e5811
4 changed files with 53 additions and 61 deletions

View File

@ -22,14 +22,14 @@ TFlipper::TFlipper(TPinballTable* table, int groupIndex) : TCollisionComponent(t
Smoothness = visual.Smoothness; Smoothness = visual.Smoothness;
auto collMult = *loader::query_float_attribute(groupIndex, 0, 803); auto collMult = *loader::query_float_attribute(groupIndex, 0, 803);
auto bmpCoef2 = *loader::query_float_attribute(groupIndex, 0, 805); auto retractTime = *loader::query_float_attribute(groupIndex, 0, 805);
auto bmpCoef1 = *loader::query_float_attribute(groupIndex, 0, 804); auto extendTime = *loader::query_float_attribute(groupIndex, 0, 804);
/*Full tilt hack: different flipper speed*/ /*Full tilt hack: different flipper speed*/
if (pb::FullTiltMode) if (pb::FullTiltMode)
{ {
bmpCoef2 = 0.08f; retractTime = 0.08f;
bmpCoef1 = 0.04f; extendTime = 0.04f;
} }
auto vecT2 = reinterpret_cast<vector_type*>(loader::query_float_attribute(groupIndex, 0, 802)); auto vecT2 = reinterpret_cast<vector_type*>(loader::query_float_attribute(groupIndex, 0, 802));
auto vecT1 = reinterpret_cast<vector_type*>(loader::query_float_attribute(groupIndex, 0, 801)); auto vecT1 = reinterpret_cast<vector_type*>(loader::query_float_attribute(groupIndex, 0, 801));
@ -42,8 +42,8 @@ TFlipper::TFlipper(TPinballTable* table, int groupIndex) : TCollisionComponent(t
origin, origin,
vecT1, vecT1,
vecT2, vecT2,
bmpCoef1, extendTime,
bmpCoef2, retractTime,
collMult, collMult,
Elasticity, Elasticity,
Smoothness); Smoothness);
@ -51,8 +51,8 @@ TFlipper::TFlipper(TPinballTable* table, int groupIndex) : TCollisionComponent(t
FlipperEdge = flipperEdge; FlipperEdge = flipperEdge;
if (flipperEdge) if (flipperEdge)
{ {
BmpCoef1 = flipperEdge->BmpCoef1 / static_cast<float>(ListBitmap->size() - 1); ExtendAnimationFrameTime = flipperEdge->ExtendTime / static_cast<float>(ListBitmap->size() - 1);
BmpCoef2 = flipperEdge->BmpCoef2 / static_cast<float>(ListBitmap->size() - 1); RetractAnimationFrameTime = flipperEdge->RetractTime / static_cast<float>(ListBitmap->size() - 1);
} }
BmpIndex = 0; BmpIndex = 0;
InputTime = 0.0; InputTime = 0.0;
@ -68,35 +68,30 @@ int TFlipper::Message(int code, float value)
if (code == 1 || code == 2 || code > 1008 && code <= 1011 || code == 1022) if (code == 1 || code == 2 || code > 1008 && code <= 1011 || code == 1022)
{ {
float timerTime; float timerTime;
int soundIndex = 0, code2 = code; int command = code;
if (code == 1) if (code == 1)
{ {
control::handler(1, this); control::handler(1, this);
TimerTime = BmpCoef1; TimerTime = ExtendAnimationFrameTime;
soundIndex = HardHitSoundId; loader::play_sound(HardHitSoundId);
} }
else if (code == 2) else if (code == 2)
{ {
TimerTime = BmpCoef2; TimerTime = RetractAnimationFrameTime;
soundIndex = SoftHitSoundId; loader::play_sound(SoftHitSoundId);
} }
else else
{ {
code2 = 2; // Retract for all non-input messages
TimerTime = BmpCoef2; command = 2;
TimerTime = RetractAnimationFrameTime;
} }
if (soundIndex)
loader::play_sound(soundIndex);
if (Timer)
{
timer::kill(Timer);
Timer = 0;
}
if (MessageField) if (MessageField)
{ {
auto v10 = value - FlipperEdge->InputTime; // Message arrived before animation is finished
timerTime = v10 - floor(v10 / TimerTime) * TimerTime; auto inputDt = value - FlipperEdge->InputTime;
timerTime = inputDt - floor(inputDt / TimerTime) * TimerTime;
if (timerTime < 0.0f) if (timerTime < 0.0f)
timerTime = 0.0; timerTime = 0.0;
} }
@ -104,10 +99,13 @@ int TFlipper::Message(int code, float value)
{ {
timerTime = TimerTime; timerTime = TimerTime;
} }
MessageField = code2;
MessageField = command;
InputTime = value; InputTime = value;
if (Timer)
timer::kill(Timer);
Timer = timer::set(timerTime, this, TimerExpired); Timer = timer::set(timerTime, this, TimerExpired);
FlipperEdge->SetMotion(code2, value); FlipperEdge->SetMotion(command, value);
} }
if (code == 1020 || code == 1024) if (code == 1020 || code == 1024)
@ -137,49 +135,43 @@ void TFlipper::Collision(TBall* ball, vector_type* nextPosition, vector_type* di
void TFlipper::TimerExpired(int timerId, void* caller) void TFlipper::TimerExpired(int timerId, void* caller)
{ {
auto flip = static_cast<TFlipper*>(caller); auto flip = static_cast<TFlipper*>(caller);
int timer; // eax int bmpCountSub1 = flip->ListBitmap->size() - 1;
auto newBmpIndex = static_cast<int>(floor((pb::time_now - flip->InputTime) / flip->TimerTime));
if (newBmpIndex > bmpCountSub1)
newBmpIndex = bmpCountSub1;
if (newBmpIndex < 0)
newBmpIndex = 0;
bool bmpIndexOutOfBounds = false; bool bmpIndexOutOfBounds = false;
auto bmpIndexAdvance = static_cast<int>(floor((pb::time_now - flip->InputTime) / flip->TimerTime + 0.5f));
int bmpCount = flip->ListBitmap->size();
if (bmpIndexAdvance > bmpCount)
bmpIndexAdvance = bmpCount;
if (bmpIndexAdvance < 0)
bmpIndexAdvance = 0;
if (!bmpIndexAdvance)
bmpIndexAdvance = 1;
if (flip->MessageField == 1) if (flip->MessageField == 1)
{ {
flip->BmpIndex += bmpIndexAdvance; flip->BmpIndex = newBmpIndex;
int countSub1 = flip->ListBitmap->size() - 1; if (flip->BmpIndex >= bmpCountSub1)
if (flip->BmpIndex >= countSub1)
{ {
flip->BmpIndex = countSub1; flip->BmpIndex = bmpCountSub1;
bmpIndexOutOfBounds = true; bmpIndexOutOfBounds = true;
} }
} }
if (flip->MessageField == 2) if (flip->MessageField == 2)
{ {
flip->BmpIndex -= bmpIndexAdvance; flip->BmpIndex = bmpCountSub1 - newBmpIndex;
timer = 0;
if (flip->BmpIndex <= 0) if (flip->BmpIndex <= 0)
{ {
flip->BmpIndex = 0; flip->BmpIndex = 0;
bmpIndexOutOfBounds = true; bmpIndexOutOfBounds = true;
} }
} }
else
{
timer = 0;
}
if (bmpIndexOutOfBounds) if (bmpIndexOutOfBounds)
{
flip->MessageField = 0; flip->MessageField = 0;
flip->Timer = 0;
}
else else
timer = timer::set(flip->TimerTime, flip, TimerExpired); {
flip->Timer = timer; flip->Timer = timer::set(flip->TimerTime, flip, TimerExpired);
}
auto bmp = flip->ListBitmap->at(flip->BmpIndex); auto bmp = flip->ListBitmap->at(flip->BmpIndex);
auto zMap = flip->ListZMap->at(flip->BmpIndex); auto zMap = flip->ListZMap->at(flip->BmpIndex);

View File

@ -19,8 +19,8 @@ public:
int BmpIndex; int BmpIndex;
TFlipperEdge* FlipperEdge; TFlipperEdge* FlipperEdge;
int Timer; int Timer;
float BmpCoef1{}; float ExtendAnimationFrameTime{};
float BmpCoef2{}; float RetractAnimationFrameTime{};
float TimerTime{}; float TimerTime{};
float InputTime; float InputTime;
}; };

View File

@ -12,15 +12,15 @@ line_type TFlipperEdge::lineA, TFlipperEdge::lineB;
circle_type TFlipperEdge::circlebase, TFlipperEdge::circleT1; circle_type TFlipperEdge::circlebase, TFlipperEdge::circleT1;
TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsigned int collisionGroup, TPinballTable* table, TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsigned int collisionGroup, TPinballTable* table,
vector_type* origin, vector_type* vecT1, vector_type* vecT2, float bmpCoef1, float bmpCoef2, vector_type* origin, vector_type* vecT1, vector_type* vecT2, float extendTime, float retractTime,
float collMult, float elasticity, float smoothness): TEdgeSegment(collComp, activeFlag, collisionGroup) float collMult, float elasticity, float smoothness): TEdgeSegment(collComp, activeFlag, collisionGroup)
{ {
vector_type crossProd{}, vecDir1{}, vecDir2{}; vector_type crossProd{}, vecDir1{}, vecDir2{};
Elasticity = elasticity; Elasticity = elasticity;
Smoothness = smoothness; Smoothness = smoothness;
BmpCoef1 = bmpCoef1; ExtendTime = extendTime;
BmpCoef2 = bmpCoef2; RetractTime = retractTime;
CollisionMult = collMult; CollisionMult = collMult;
T1Src = *vecT1; T1Src = *vecT1;
@ -78,9 +78,9 @@ TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsi
auto distance1 = sqrt(dy * dy + dx * dx) + table->CollisionCompOffset + vecT1->Z; auto distance1 = sqrt(dy * dy + dx * dx) + table->CollisionCompOffset + vecT1->Z;
DistanceDivSq = distance1 * distance1; DistanceDivSq = distance1 * distance1;
float bmpCoef = std::min(BmpCoef1, BmpCoef2); float minMoveTime = std::min(ExtendTime, RetractTime);
auto distance = maths::Distance(vecT1, vecT2); auto distance = maths::Distance(vecT1, vecT2);
CollisionTimeAdvance = bmpCoef / (distance / CircleT1Radius + distance / CircleT1Radius); CollisionTimeAdvance = minMoveTime / (distance / CircleT1Radius + distance / CircleT1Radius);
TFlipperEdge::place_in_grid(); TFlipperEdge::place_in_grid();
EdgeCollisionFlag = 0; EdgeCollisionFlag = 0;
@ -469,12 +469,12 @@ void TFlipperEdge::SetMotion(int code, float value)
case 1: case 1:
Angle2 = flipper_angle(value); Angle2 = flipper_angle(value);
Angle1 = AngleMax; Angle1 = AngleMax;
AngleMult = BmpCoef1; AngleMult = ExtendTime;
break; break;
case 2: case 2:
Angle2 = flipper_angle(value); Angle2 = flipper_angle(value);
Angle1 = 0.0; Angle1 = 0.0;
AngleMult = BmpCoef2; AngleMult = RetractTime;
break; break;
case 1024: case 1024:
FlipperFlag = 0; FlipperFlag = 0;

View File

@ -8,7 +8,7 @@ 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,
vector_type* origin, vector_type* vecT1, vector_type* vecT2, float bmpCoef1, float bmpCoef2, float collMult, vector_type* origin, vector_type* vecT1, vector_type* vecT2, float extendTime, float retractTime, 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;
@ -50,8 +50,8 @@ public:
float InputTime; float InputTime;
float AngleStopTime; float AngleStopTime;
float AngleMult; float AngleMult;
float BmpCoef1; float ExtendTime;
float BmpCoef2; float RetractTime;
vector_type NextBallPosition{}; vector_type NextBallPosition{};
static float flipper_sin_angle, flipper_cos_angle; static float flipper_sin_angle, flipper_cos_angle;