/Engine/Game/GameTime.cs
C# | 368 lines | 219 code | 37 blank | 112 comment | 15 complexity | d6c5cbf21f36be5d03a7fc7663cf3e8e MD5 | raw file
Possible License(s): Apache-2.0
- using Delta.Engine.Dynamic;
- using Delta.Utilities;
-
- namespace Delta.Engine.Game
- {
- /// <summary>
- /// Game Time is used for having a pausable and resetable time source,
- /// which is useful for games that can pause.<para />
- /// Dependant systems are Effects, Physics.
- /// </summary>
- public class GameTime : DynamicModule
- {
- #region CheckEvery (Static)
- /// <summary>
- /// Check every time (e.g. one second, half a second, every 10 seconds)
- /// if the time has passed and return true once in that time frame and
- /// false otherwise. Used for spawning stuff, e.g. every 0.5 seconds and
- /// is very useful to write framerate independent code.
- /// Note: If using a small value here like 1.0f/100.0f and we have less
- /// fps (e.g. 60), then this will return true every time, but obviously
- /// we cannot return true 100 times if this method is only called 60 times.
- /// </summary>
- /// <param name="timeStep">Time step in seconds</param>
- /// <returns>
- /// True if the timeStep is reached, false if we have too many frames and
- /// need to wait until timeStep is reached next.
- /// </returns>
- public static bool CheckEvery(float timeStep)
- {
- // Make sure the timeStep value is valid!
- if (timeStep <= 0)
- {
- Log.Warning("Invalid time step=" + timeStep);
- return true;
- }
- // Calculate with millisecond values calculated in the timer.
- return (int)(Milliseconds / (1000 * timeStep)) >
- (int)(LastMilliseconds / (1000 * timeStep));
- }
-
- /// <summary>
- /// Check every time (e.g. one second, half a second, every 10 seconds)
- /// if the time has passed and return true once in that time frame and
- /// false otherwise. Used for spawning stuff, e.g. every 0.5 seconds and
- /// is very useful to write framerate independent code.
- /// Note: If using a small value here like 1.0f/100.0f and we have less
- /// fps (e.g. 60), then this will return true every time, but obviously
- /// we cannot return true 100 times if this method is only called 60 times.
- /// </summary>
- /// <param name="timeStep">Time step in seconds</param>
- /// <param name="startTimeMs">
- /// Only start checking when this time is reached and then every time step
- /// after (in milliseconds).
- /// </param>
- /// <returns>
- /// True if the timeStep is reached, false if we have too many frames and
- /// need to wait until timeStep is reached next.
- /// </returns>
- public static bool CheckEvery(float timeStep, long startTimeMs)
- {
- // Make sure the timeStep value is valid!
- if (startTimeMs < 0 ||
- timeStep <= 0)
- {
- Log.Warning("Invalid timeStep='" + timeStep +
- "' or startTimeMs='" + startTimeMs + "'");
- return true;
- }
- // Calculate with millisecond values calculated in the timer.
- long relativeStartMs = Milliseconds - startTimeMs;
- if (relativeStartMs < 0)
- {
- // Not started yet
- return false;
- } // if
-
- long relativeLastMs = LastMilliseconds - startTimeMs;
- return (int)(relativeStartMs / (1000 * timeStep)) >
- (int)(relativeLastMs / (1000 * timeStep));
- }
- #endregion
-
- #region GetDeltaToNow (Static)
- /// <summary>
- /// Get delta to now in seconds as a floating point value.
- /// </summary>
- /// <param name="startTimeInMs">The start time in ms.</param>
- /// <returns>Float Delta to Now</returns>
- public static float GetDeltaToNow(long startTimeInMs)
- {
- return (Milliseconds - startTimeInMs) / 1000.0f;
- }
- #endregion
-
- #region IsRunning (Static)
- /// <summary>
- /// Flag if the game time is updating or not.
- /// </summary>
- public static bool IsRunning
- {
- get
- {
- return Instance.isRunning;
- }
- }
- #endregion
-
- #region Milliseconds (Static)
- /// <summary>
- /// The elapsed game time in milliseconds.
- /// </summary>
- public static long Milliseconds
- {
- get
- {
- return Instance.milliseconds;
- }
- }
- #endregion
-
- #region LastMilliseconds (Static)
- /// <summary>
- /// The elapsed game time in milliseconds from the last frame. This allows
- /// us to do some checks from frame to frame to see if a timeout or
- /// cooldown has been reached. See CheckEvery for a use case.
- /// </summary>
- public static long LastMilliseconds
- {
- get
- {
- return Instance.lastMilliseconds;
- }
- }
- #endregion
-
- #region Delta (Static)
- /// <summary>
- /// Returns the current delta time. It represents the difference between
- /// the last tick and the current tick in seconds (usually small values).
- /// Used for many calculations and updates to make sure the time goes
- /// on constantly no matter how many frames we have per second.
- /// </summary>
- public static float Delta
- {
- get
- {
- return Instance.delta;
- }
- }
- #endregion
-
- #region TotalTime (Static)
- /// <summary>
- /// The total time since the game time was started.
- /// </summary>
- public static float TotalTime
- {
- get
- {
- return Instance.totalTime;
- }
- }
- #endregion
-
- #region Paused (event)
- /// <summary>
- /// Event which will occur everytime the game time is paused.
- /// </summary>
- public static event RunDelegate Paused;
- #endregion
-
- #region Resumed (event)
- /// <summary>
- /// Event which will occur everytime the game time is resumed again.
- /// </summary>
- public static event RunDelegate Resumed;
- #endregion
-
- #region Private
-
- #region cachedInstance (Private)
- private static GameTime cachedInstance;
- #endregion
-
- #region Instance (Private)
- private static GameTime Instance
- {
- get
- {
- if (cachedInstance == null)
- {
- cachedInstance = Factory.Create<GameTime>();
- }
-
- return cachedInstance;
- }
- }
- #endregion
-
- #region timeMsOffset (Private)
- private long timeMsOffset;
- #endregion
-
- #region pauseStartOffset (Private)
- private long pauseStartOffset;
- #endregion
-
- #region isRunning (Private)
- private bool isRunning;
- #endregion
-
- #region totalTime (Private)
- /// <summary>
- /// The total time since the game time was started.
- /// </summary>
- private float totalTime;
- #endregion
-
- #region delta (Private)
- /// <summary>
- /// Returns the current delta time.
- /// </summary>
- private float delta;
- #endregion
-
- #region milliseconds (Private)
- /// <summary>
- /// Milliseconds the game time has been running.
- /// </summary>
- private long milliseconds;
- #endregion
-
- #region lastMilliseconds
- /// <summary>
- /// Milliseconds from last frame, allows us to do frame by frame checks.
- /// </summary>
- private long lastMilliseconds;
- #endregion
-
- #region wasRunningBeforeAppPause
- /// <summary>
- /// Flag if the game time was running before it was paused by the
- /// system information event. If we don't save this state we might
- /// start the game time again accidentally in OnAppResume.
- /// </summary>
- private bool wasRunningBeforeAppPause;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Create a new game time instance, which is started by default, but can
- /// be stopped or restarted by the game if a new level starts.
- /// </summary>
- internal GameTime()
- : base("GameTime", typeof(Time))
- {
- wasRunningBeforeAppPause = false;
- isRunning = true;
- timeMsOffset += Time.Milliseconds - pauseStartOffset;
-
- Application.Information.OnAppPause += OnAppPause;
- Application.Information.OnAppResume += OnAppResume;
- }
-
- /// <summary>
- /// Remove OnAppPause and OnAppResume event handlers added in constructor.
- /// </summary>
- ~GameTime()
- {
- Application.Information.OnAppPause -= OnAppPause;
- Application.Information.OnAppResume -= OnAppResume;
- }
- #endregion
-
- #region OnAppPause
- private void OnAppPause()
- {
- wasRunningBeforeAppPause = isRunning;
- Pause();
- }
- #endregion
-
- #region OnAppResume
- private void OnAppResume()
- {
- if (wasRunningBeforeAppPause)
- {
- Start();
- wasRunningBeforeAppPause = false;
- }
- }
- #endregion
-
- #region Start (Static)
- /// <summary>
- /// Start or resume the game time updating.
- /// </summary>
- public static void Start()
- {
- if (IsRunning == false)
- {
- Instance.isRunning = true;
- Instance.timeMsOffset += Time.Milliseconds - Instance.pauseStartOffset;
-
- // Still notfiy the listeners (if required)
- if (Resumed != null &&
- // but only if the time si resumed from a previous pause
- TotalTime > 0.0f)
- {
- Resumed();
- } // if
- }
- }
- #endregion
-
- #region Pause (Static)
- /// <summary>
- /// Pause the game time updating.
- /// </summary>
- public static void Pause()
- {
- if (IsRunning)
- {
- Instance.isRunning = false;
- Instance.pauseStartOffset = Time.Milliseconds;
-
- // Still notfiy the listeners (if required)
- if (Paused != null)
- {
- Paused();
- } // if
- }
- }
- #endregion
-
- #region Reset (Static)
- /// <summary>
- /// Reset the game time.
- /// </summary>
- public static void Reset()
- {
- Instance.totalTime = 0.0f;
- }
- #endregion
-
- #region Run (Public)
- /// <summary>
- /// Update the game time.
- /// </summary>
- public override void Run()
- {
- if (IsRunning == false)
- {
- delta = 0.0f;
- return;
- }
-
- lastMilliseconds = milliseconds;
- milliseconds = Time.Milliseconds - timeMsOffset;
-
- delta = Time.Delta;
- totalTime += Delta;
- }
- #endregion
- }
- }