From a2aeef015523632fade448d4a2b7e536701eeae6 Mon Sep 17 00:00:00 2001 From: immibis Date: Sun, 6 Aug 2017 22:03:28 +1200 Subject: [PATCH] When game speed is 2 or higher, run multiple ticks. --- src/app/app.cpp | 47 +++++++++++++++++++--------- src/app/app.h | 2 +- src/common/system/system.h | 3 ++ src/common/system/system_linux.cpp | 13 ++++++++ src/common/system/system_linux.h | 1 + src/common/system/system_other.cpp | 5 +++ src/common/system/system_other.h | 1 + src/common/system/system_windows.cpp | 5 +++ src/common/system/system_windows.h | 1 + test/unit/app/app_test.cpp | 18 ++++++++--- 10 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/app/app.cpp b/src/app/app.cpp index 2d460604..b5bd3ca0 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -1060,6 +1060,12 @@ int CApplication::Run() MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start + SystemTimeStamp *lastLoopTimeStamp = m_systemUtils->CreateTimeStamp(); + SystemTimeStamp *currentTimeStamp = m_systemUtils->CreateTimeStamp(); + SystemTimeStamp *interpolatedTimeStamp = m_systemUtils->CreateTimeStamp(); + m_systemUtils->GetCurrentTimeStamp(lastLoopTimeStamp); + m_systemUtils->CopyTimeStamp(currentTimeStamp, lastLoopTimeStamp); + while (true) { if (m_active) @@ -1158,21 +1164,30 @@ int CApplication::Run() CProfiler::StartPerformanceCounter(PCNT_UPDATE_ALL); - // Prepare and process step simulation event - Event event = CreateUpdateEvent(); - if (event.type != EVENT_NULL && m_controller != nullptr) + // Prepare and process step simulation event(s) + // If game speed is increased then we do extra ticks per loop iteration to improve physics accuracy. + int numTickSlices = static_cast(GetSimulationSpeed()); + if(numTickSlices < 1) numTickSlices = 1; + m_systemUtils->CopyTimeStamp(lastLoopTimeStamp, currentTimeStamp); + m_systemUtils->GetCurrentTimeStamp(currentTimeStamp); + for(int tickSlice = 0; tickSlice < numTickSlices; tickSlice++) { - LogEvent(event); + m_systemUtils->InterpolateTimeStamp(interpolatedTimeStamp, lastLoopTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast(numTickSlices)); + Event event = CreateUpdateEvent(interpolatedTimeStamp); + if (event.type != EVENT_NULL && m_controller != nullptr) + { + LogEvent(event); - m_sound->FrameMove(m_relTime); + m_sound->FrameMove(m_relTime); - CProfiler::StartPerformanceCounter(PCNT_UPDATE_GAME); - m_controller->ProcessEvent(event); - CProfiler::StopPerformanceCounter(PCNT_UPDATE_GAME); + CProfiler::StartPerformanceCounter(PCNT_UPDATE_GAME); + m_controller->ProcessEvent(event); + CProfiler::StopPerformanceCounter(PCNT_UPDATE_GAME); - CProfiler::StartPerformanceCounter(PCNT_UPDATE_ENGINE); - m_engine->FrameUpdate(); - CProfiler::StopPerformanceCounter(PCNT_UPDATE_ENGINE); + CProfiler::StartPerformanceCounter(PCNT_UPDATE_ENGINE); + m_engine->FrameUpdate(); + CProfiler::StopPerformanceCounter(PCNT_UPDATE_ENGINE); + } } CProfiler::StopPerformanceCounter(PCNT_UPDATE_ALL); @@ -1188,6 +1203,10 @@ int CApplication::Run() } end: + m_systemUtils->DestroyTimeStamp(lastLoopTimeStamp); + m_systemUtils->DestroyTimeStamp(currentTimeStamp); + m_systemUtils->DestroyTimeStamp(interpolatedTimeStamp); + return m_exitCode; } @@ -1529,20 +1548,20 @@ void CApplication::SetSimulationSpeed(float speed) { m_simulationSpeed = speed; - m_systemUtils->GetCurrentTimeStamp(m_baseTimeStamp); + m_systemUtils->CopyTimeStamp(m_baseTimeStamp, m_curTimeStamp); m_realAbsTimeBase = m_realAbsTime; m_absTimeBase = m_exactAbsTime; GetLogger()->Info("Simulation speed = %.2f\n", speed); } -Event CApplication::CreateUpdateEvent() +Event CApplication::CreateUpdateEvent(SystemTimeStamp *newTimeStamp) { if (m_simulationSuspended) return Event(EVENT_NULL); m_systemUtils->CopyTimeStamp(m_lastTimeStamp, m_curTimeStamp); - m_systemUtils->GetCurrentTimeStamp(m_curTimeStamp); + m_systemUtils->CopyTimeStamp(m_curTimeStamp, newTimeStamp); long long absDiff = m_systemUtils->TimeStampExactDiff(m_baseTimeStamp, m_curTimeStamp); long long newRealAbsTime = m_realAbsTimeBase + absDiff; diff --git a/src/app/app.h b/src/app/app.h index c0d48a1c..c55eca38 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -289,7 +289,7 @@ protected: //! If applicable, creates a virtual event to match the changed state as of new event Event CreateVirtualEvent(const Event& sourceEvent); //! Prepares a simulation update event - TEST_VIRTUAL Event CreateUpdateEvent(); + TEST_VIRTUAL Event CreateUpdateEvent(SystemTimeStamp *newTimeStamp); //! Logs debug data for event void LogEvent(const Event& event); diff --git a/src/common/system/system.h b/src/common/system/system.h index 553dc56f..ebc92269 100644 --- a/src/common/system/system.h +++ b/src/common/system/system.h @@ -116,6 +116,9 @@ public: //! Copies the time stamp from \a src to \a dst TEST_VIRTUAL void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src); + //! Interpolates between two timestamps. If i=0 then dst=a. If i=1 then dst=b. If i=0.5 then dst is halfway between. + virtual void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) = 0; + //! Returns a time stamp associated with current time virtual void GetCurrentTimeStamp(SystemTimeStamp *stamp) = 0; diff --git a/src/common/system/system_linux.cpp b/src/common/system/system_linux.cpp index 9a09b2c3..459c071f 100644 --- a/src/common/system/system_linux.cpp +++ b/src/common/system/system_linux.cpp @@ -83,6 +83,19 @@ SystemDialogResult CSystemUtilsLinux::SystemDialog(SystemDialogType type, const return result; } +void CSystemUtilsLinux::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) +{ + long long delta = TimeStampExactDiff(a, b); + delta *= i; // truncates + dst->clockTime.tv_sec = a->clockTime.tv_sec + delta / 1000000000; + dst->clockTime.tv_nsec = a->clockTime.tv_nsec + delta % 1000000000; + if(dst->clockTime.tv_nsec >= 1000000000) + { + dst->clockTime.tv_nsec -= 1000000000; + dst->clockTime.tv_sec++; + } +} + void CSystemUtilsLinux::GetCurrentTimeStamp(SystemTimeStamp *stamp) { clock_gettime(CLOCK_MONOTONIC_RAW, &stamp->clockTime); diff --git a/src/common/system/system_linux.h b/src/common/system/system_linux.h index 6f0c1950..b3446aa6 100644 --- a/src/common/system/system_linux.h +++ b/src/common/system/system_linux.h @@ -40,6 +40,7 @@ public: SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override; + void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override; void GetCurrentTimeStamp(SystemTimeStamp *stamp) override; long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override; diff --git a/src/common/system/system_other.cpp b/src/common/system/system_other.cpp index d73ce705..865db847 100644 --- a/src/common/system/system_other.cpp +++ b/src/common/system/system_other.cpp @@ -34,6 +34,11 @@ void CSystemUtilsOther::GetCurrentTimeStamp(SystemTimeStamp* stamp) stamp->sdlTicks = SDL_GetTicks(); } +void CSystemUtilsOther::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) +{ + dst->sdlTicks = a->sdlTicks + static_cast((b->sdlTicks - a->sdlTicks) * i); +} + long long int CSystemUtilsOther::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after) { return (after->sdlTicks - before->sdlTicks) * 1000000ll; diff --git a/src/common/system/system_other.h b/src/common/system/system_other.h index dcec37a6..5964b585 100644 --- a/src/common/system/system_other.h +++ b/src/common/system/system_other.h @@ -46,6 +46,7 @@ public: void Init() override; SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override; + void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override; void GetCurrentTimeStamp(SystemTimeStamp *stamp) override; long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override; diff --git a/src/common/system/system_windows.cpp b/src/common/system/system_windows.cpp index 6406bee3..413b0575 100644 --- a/src/common/system/system_windows.cpp +++ b/src/common/system/system_windows.cpp @@ -83,6 +83,11 @@ void CSystemUtilsWindows::GetCurrentTimeStamp(SystemTimeStamp* stamp) stamp->counterValue = value.QuadPart; } +void CSystemUtilsWindows::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) +{ + dst->counterValue = a->counterValue + static_cast((b->counterValue - a->counterValue) * static_cast(i)); +} + long long int CSystemUtilsWindows::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after) { float floatValue = static_cast(after->counterValue - before->counterValue) * (1e9 / static_cast(m_counterFrequency)); diff --git a/src/common/system/system_windows.h b/src/common/system/system_windows.h index 736ab706..4bbd704f 100644 --- a/src/common/system/system_windows.h +++ b/src/common/system/system_windows.h @@ -38,6 +38,7 @@ public: SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override; + void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override; void GetCurrentTimeStamp(SystemTimeStamp *stamp) override; long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override; diff --git a/test/unit/app/app_test.cpp b/test/unit/app/app_test.cpp index 7258f480..aad94e39 100644 --- a/test/unit/app/app_test.cpp +++ b/test/unit/app/app_test.cpp @@ -55,9 +55,9 @@ public: SDL_Quit(); } - Event CreateUpdateEvent() override + Event CreateUpdateEvent(SystemTimeStamp *timestamp) override { - return CApplication::CreateUpdateEvent(); + return CApplication::CreateUpdateEvent(timestamp); } }; @@ -157,7 +157,9 @@ void CApplicationUT::TestCreateUpdateEvent(long long relTimeExact, long long abs float relTime, float absTime, long long relTimeReal, long long absTimeReal) { - Event event = m_app->CreateUpdateEvent(); + SystemTimeStamp *now = CreateTimeStamp(); + GetCurrentTimeStamp(now); + Event event = m_app->CreateUpdateEvent(now); EXPECT_EQ(EVENT_FRAME, event.type); EXPECT_FLOAT_EQ(relTime, event.rTime); EXPECT_FLOAT_EQ(relTime, m_app->GetRelTime()); @@ -172,7 +174,11 @@ void CApplicationUT::TestCreateUpdateEvent(long long relTimeExact, long long abs TEST_F(CApplicationUT, UpdateEventTimeCalculation_SimulationSuspended) { m_app->SuspendSimulation(); - Event event = m_app->CreateUpdateEvent(); + + SystemTimeStamp *now = CreateTimeStamp(); + GetCurrentTimeStamp(now); + Event event = m_app->CreateUpdateEvent(now); + EXPECT_EQ(EVENT_NULL, event.type); } @@ -224,7 +230,9 @@ TEST_F(CApplicationUT, UpdateEventTimeCalculation_NegativeTimeOperation) NextInstant(-1111); - Event event = m_app->CreateUpdateEvent(); + SystemTimeStamp *now = CreateTimeStamp(); + GetCurrentTimeStamp(now); + Event event = m_app->CreateUpdateEvent(now); EXPECT_EQ(EVENT_NULL, event.type); }