#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2013 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License #ifndef NUCLEX_GAME_TIMING_SCALEDTIMER_H #define NUCLEX_GAME_TIMING_SCALEDTIMER_H #include "Timer.h" namespace Nuclex { namespace Game { namespace Timing { // ------------------------------------------------------------------------------------------- // /// Timer designed to facilitate time-scaled updating /// /// /// Frame rate independent movement can be implemented in two ways: either via /// time scaling or via time stepping. Time scaling will scale the movements of all /// objects in a game by the amount of time passed since the last frame. Time stepping /// advances time in fixed steps, multiple times if more time has passed than the length /// of a single step. /// /// /// This timer is intended for the scaled approach. Its advantage is a little less CPU /// load on low end systems (where a stepped timer would be doing several steps each /// cycle). However, physics simulations tend to get unstable if time jumps by larger /// amounts and scaling object movements by time means that multiplayer states will /// eventually drift apart due to different rounding errors occuring as a result of speed /// differences between the connected systems. /// /// /// /// scaledTimer.Reset(); /// /// while(!this->quitRequested) { /// GameTime deltaTime = scaledTimer.GetElapsedAndReset(); /// /// UpdateAll(deltaTime); /// DrawAll(deltaTime); /// /// RunMessagePump(); /// } /// /// /// /// The time returned from GetElapsed() or GetElapsedAndReset() is the number of /// completely elapsed microseconds. The fractional part of the currently running /// microsecond is kept until the next call to GetElapsed() or GetElapsedAndReset(), /// guaranteeing that no time is ever lost. The same goes for when the provided Clock's /// frequency is not evenly divisible to microseconds. /// /// class ScaledTimer : public Timer { /// Initializes a new scaled timer using the default clock public: NUCLEX_GAME_API ScaledTimer(); /// Initializes a new scaled timer using the specified clock /// Clock the scaled timer will use public: NUCLEX_GAME_API ScaledTimer(const std::shared_ptr &clock); /// Destroys the scaled timer public: NUCLEX_GAME_API virtual ~ScaledTimer() {} /// Pauses the simulation clock /// /// Real world time will still continue running, but the timer's simulation time /// will stop counting until the ResumeSimulation() or Reset() methods are called. /// public: NUCLEX_GAME_API void PauseSimulation(); /// Resumes the simulation clock after it has been paused public: NUCLEX_GAME_API void ResumeSimulation(); /// Resets the delta times to zero /// /// /// You should call this method once immediately before entering the main loop so the /// time accumulated between the time provider being created and your game becoming /// ready to run will not result in a jump of possibly several seconds of game time /// being skipped/caught up. /// /// /// Do not use this method in your normal update loop as this will result in the time /// that passes between retrieving the timer's delta time or steps and calling Reset(), /// leading to minuscule speed differences depending on the operating system's CPU load /// and performance. /// /// /// If the simulation clock was paused, calling Reset() will also restore it running. /// /// public: NUCLEX_GAME_API void Reset(); /// Returns the elapsed time since the timer was last reset /// The time that has elapsed since the last Reset() call /// /// This method is identical to GetElapsedAndReset() except that it doesn't reset /// the delta times, allowing you to "peek" at what the timing values would /// be right now. Do not use this method in your game loop to advance time due to /// the effects described in the documentation of the Reset() method. /// public: NUCLEX_GAME_API GameTime GetElapsed() const; /// /// Returns the amount of time elapsed since the last call and resets the elapsed time /// /// The time that has elapsed since the last Reset() call /// /// /// Use this method in a time-scaled game loop to determine the amount of time that /// has elapsed since the previous frame. Time will be advanced in such a way that /// all of clocks ticks will be accounted for. If the elapsed time is not evenly /// divisible to the next millisecond, the remaining clock ticks will be budgeted /// for the next frame. /// /// public: NUCLEX_GAME_API GameTime GetElapsedAndResetDelta(); /// Accumulated simulation time during the intervals where it was running private: std::chrono::microseconds accumulatedSimulationUs; /// Time since which the simulation clock has been running private: std::chrono::microseconds simulationResumeUs; /// Total elapsed simulation time in microseconds private: std::chrono::microseconds totalSimulationUs; /// Total elapsed time in the real world in microseconds private: std::chrono::microseconds totalRealWorldUs; }; // ------------------------------------------------------------------------------------------- // }}} // namespace Nuclex::Game::Timing #endif // NUCLEX_GAME_TIMING_WINDOWSTIMEPROVIDER_H