Added float target frame time, set UPS to 120.

Improved frame stabilization.
Ref PR #85.
This commit is contained in:
Muzychenko Andrey 2021-11-13 10:55:37 +03:00
parent 0b2fd28fda
commit ab7184ef86
3 changed files with 40 additions and 34 deletions

View File

@ -26,8 +26,8 @@
TPinballTable* pb::MainTable = nullptr; TPinballTable* pb::MainTable = nullptr;
datFileStruct* pb::record_table = nullptr; datFileStruct* pb::record_table = nullptr;
int pb::time_ticks = 0, pb::demo_mode = 0, pb::game_mode = 2, pb::mode_countdown_, pb::state, pb::frameCounter = 0; int pb::time_ticks = 0, pb::demo_mode = 0, pb::game_mode = 2, pb::state, pb::frameCounter = 0;
float pb::time_now, pb::time_next, pb::ball_speed_limit; float pb::time_now, pb::time_next, pb::ball_speed_limit, pb::mode_countdown_, pb::time_ticks_remainder = 0;
high_score_struct pb::highscore_table[5]; high_score_struct pb::highscore_table[5];
bool pb::FullTiltMode = false, pb::cheat_mode = false; bool pb::FullTiltMode = false, pb::cheat_mode = false;
@ -225,29 +225,34 @@ void pb::ballset(int x, int y)
ball->Speed = maths::normalize_2d(&ball->Acceleration); ball->Speed = maths::normalize_2d(&ball->Acceleration);
} }
void pb::frame(int time) void pb::frame(float dtMilliSec)
{ {
static int frameTime = 0; static float frameTime = 0;
if (time > 100) if (dtMilliSec > 100)
time = 100; dtMilliSec = 100;
if (time <= 0) if (dtMilliSec <= 0)
return; return;
float timeMul = time * 0.001f; auto dtSec = dtMilliSec * 0.001f;
if (!mode_countdown(time)) if (!mode_countdown(dtMilliSec))
{ {
time_next = time_now + timeMul; time_next = time_now + dtSec;
timed_frame(time_now, timeMul, true); timed_frame(time_now, dtSec, true);
time_now = time_next; time_now = time_next;
time_ticks += time;
auto dtMilliSecComp = dtMilliSec + time_ticks_remainder;
auto dtWhole = static_cast<int>(dtMilliSecComp);
time_ticks_remainder = dtMilliSecComp - static_cast<float>(dtWhole);
time_ticks += dtWhole;
if (nudge::nudged_left || nudge::nudged_right || nudge::nudged_up) if (nudge::nudged_left || nudge::nudged_right || nudge::nudged_up)
{ {
nudge::nudge_count = timeMul * 4.0f + nudge::nudge_count; nudge::nudge_count = dtSec * 4.0f + nudge::nudge_count;
} }
else else
{ {
auto nudgeDec = nudge::nudge_count - timeMul; auto nudgeDec = nudge::nudge_count - dtSec;
if (nudgeDec <= 0.0f) if (nudgeDec <= 0.0f)
nudgeDec = 0.0; nudgeDec = 0.0;
nudge::nudge_count = nudgeDec; nudge::nudge_count = nudgeDec;
@ -265,9 +270,9 @@ void pb::frame(int time)
// Retained render prevents frame skip. The next best thing - complete refresh at fixed rate. // Retained render prevents frame skip. The next best thing - complete refresh at fixed rate.
render::update(false); render::update(false);
// Frame time at 60 FPS = 16.(6) ms = (16 + 17 + 17) / 3 // Frame time at 60 FPS = 16.(6) ms
auto targetTime = frameCounter % 3 == 0 ? 16 : 17; auto targetTime = 1000 / 60.0f;
frameTime += time; frameTime += dtMilliSec;
if (frameTime >= targetTime) if (frameTime >= targetTime)
{ {
frameTime = min(frameTime - targetTime, 100); frameTime = min(frameTime - targetTime, 100);
@ -526,7 +531,7 @@ void pb::keydown(int key)
} }
} }
int pb::mode_countdown(int time) int pb::mode_countdown(float dtMilliSec)
{ {
if (!game_mode || game_mode <= 0) if (!game_mode || game_mode <= 0)
return 1; return 1;
@ -534,14 +539,14 @@ int pb::mode_countdown(int time)
{ {
if (game_mode == 3) if (game_mode == 3)
{ {
mode_countdown_ -= time; mode_countdown_ -= dtMilliSec;
if (mode_countdown_ < 0 || time < 0) if (mode_countdown_ < 0.0f || dtMilliSec < 0.0f)
mode_change(4); mode_change(4);
} }
else if (game_mode == 4) else if (game_mode == 4)
{ {
mode_countdown_ -= time; mode_countdown_ -= dtMilliSec;
if (mode_countdown_ < 0 || time < 0) if (mode_countdown_ < 0.0f || dtMilliSec < 0.0f)
mode_change(1); mode_change(1);
} }
return 1; return 1;

View File

@ -26,14 +26,14 @@ public:
static void toggle_demo(); static void toggle_demo();
static void replay_level(int demoMode); static void replay_level(int demoMode);
static void ballset(int x, int y); static void ballset(int x, int y);
static void frame(int time); static void frame(float dtMilliSec);
static void timed_frame(float timeNow, float timeDelta, bool drawBalls); static void timed_frame(float timeNow, float timeDelta, bool drawBalls);
static void window_size(int* width, int* height); static void window_size(int* width, int* height);
static void pause_continue(); static void pause_continue();
static void loose_focus(); static void loose_focus();
static void keyup(int key); static void keyup(int key);
static void keydown(int key); static void keydown(int key);
static int mode_countdown(int time); static int mode_countdown(float dtMilliSec);
static void launch_ball(); static void launch_ball();
static void end_game(); static void end_game();
static void high_scores(); static void high_scores();
@ -41,6 +41,7 @@ public:
static bool chk_highscore(); static bool chk_highscore();
static float collide(float timeNow, float timeDelta, TBall* ball); static float collide(float timeNow, float timeDelta, TBall* ball);
private: private:
static int demo_mode, mode_countdown_; static int demo_mode;
static int state; static int state;
static float mode_countdown_, time_ticks_remainder;
}; };

View File

@ -12,7 +12,7 @@
#include "splash.h" #include "splash.h"
#include "render.h" #include "render.h"
const int TargetFrameTime = 8; const float TargetUPS = 120, TargetFrameTime = 1000 / TargetUPS;
HINSTANCE winmain::hinst = nullptr; HINSTANCE winmain::hinst = nullptr;
HWND winmain::hwnd_frame = nullptr; HWND winmain::hwnd_frame = nullptr;
@ -225,7 +225,7 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
pb::replay_level(0); pb::replay_level(0);
DWORD someTimeCounter = 300u, prevTime = 0u, frameStart = timeGetTime(); DWORD someTimeCounter = 300u, prevTime = 0u, frameStart = timeGetTime();
int sleepRemainder = 0, frameDuration = TargetFrameTime; float sleepRemainder = 0, frameDuration = TargetFrameTime;
while (true) while (true)
{ {
if (!someTimeCounter) if (!someTimeCounter)
@ -299,11 +299,11 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
gdrv::fill_bitmap(&gfr_display, 1, height, width - 1, 0, 0); // Background gdrv::fill_bitmap(&gfr_display, 1, height, width - 1, 0, 0); // Background
auto targetVal = dt < target ? dt : target; auto targetVal = dt < target ? dt : target;
auto targetHeight = min(static_cast<int>(std::round(targetVal * scale)), height); auto targetHeight = min(static_cast<int>(std::floor(targetVal * scale)), height);
gdrv::fill_bitmap(&gfr_display, 1, targetHeight, width - 1, height - targetHeight, -1); // Target gdrv::fill_bitmap(&gfr_display, 1, targetHeight, width - 1, height - targetHeight, -1); // Target
auto diffVal = dt < target ? target - dt : dt - target; auto diffVal = dt < target ? target - dt : dt - target;
auto diffHeight = min(static_cast<int>(std::round(diffVal * scale)), height); auto diffHeight = min(static_cast<int>(std::floor(diffVal * scale)), height);
gdrv::fill_bitmap(&gfr_display, 1, diffHeight, width - 1, height - targetHeight - diffHeight, 1); // Target diff gdrv::fill_bitmap(&gfr_display, 1, diffHeight, width - 1, height - targetHeight - diffHeight, 1); // Target diff
gdrv::blit(&gfr_display, 0, 0, render::vscreen.Width - width, 0, width, height); gdrv::blit(&gfr_display, 0, 0, render::vscreen.Width - width, 0, width, height);
@ -311,21 +311,21 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
auto updateEnd = timeGetTime(); auto updateEnd = timeGetTime();
auto sleepDuration = TargetFrameTime - (int)(updateEnd - frameStart) - sleepRemainder; auto sleepDuration = TargetFrameTime - (int)(updateEnd - frameStart) - sleepRemainder;
auto intSleepDuration = static_cast<int>(sleepDuration);
DWORD frameEnd; DWORD frameEnd;
if (sleepDuration > 0) if (intSleepDuration > 0)
{ {
Sleep(sleepDuration); Sleep(intSleepDuration);
frameEnd = timeGetTime(); frameEnd = timeGetTime();
sleepRemainder = (frameEnd - updateEnd) - sleepDuration;
} }
else else
{ {
frameEnd = updateEnd; frameEnd = updateEnd;
sleepRemainder = 0;
} }
frameDuration = min(frameEnd - frameStart, TargetFrameTime * 2); sleepRemainder = max(min((int)(frameEnd - updateEnd) - sleepDuration, TargetFrameTime), -TargetFrameTime);
frameDuration = min((frameEnd - frameStart), TargetFrameTime * 2);
frameStart = frameEnd; frameStart = frameEnd;
--someTimeCounter; --someTimeCounter;