GameTimer是DX12框架里面一个游戏时间控制的类,主要实现了计算两帧之间的时间差以及游戏的总运行时间(不算暂停的时间)。原理是采用获取WINDOS提供的高精度计时器进行计算。
首先看一下头文件:
#ifndef GAMETIMER_H
#define GAMETIMER_H
class GameTimer
{
public:
GameTimer();
float TotalTime()const; // 运行的总时间(减去了暂停时间)
float DeltaTime()const; // 两帧之间的时间差
void Reset(); // 重置
void Start(); // 暂停之后重新开始计时
void Stop(); // 暂停计时
void Tick(); // 每帧调用从而计算出前一帧和这一帧的时间差
private:
double mSecondsPerCount;
double mDeltaTime;
__int64 mBaseTime;
__int64 mPausedTime;
__int64 mStopTime;
__int64 mPrevTime;
__int64 mCurrTime;
bool mStopped;
};
#endif // GAMETIMER_H
构造函数
GameTimer::GameTimer()
: mSecondsPerCount(0.0), mDeltaTime(-1.0), mBaseTime(0),
mPausedTime(0), mPrevTime(0), mCurrTime(0), mStopped(false)
{
__int64 countsPerSec;
QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec);
mSecondsPerCount = 1.0 / (double)countsPerSec;
}
初始化所有变量,注意mDeltaTime赋值的是-1.QueryPerformanceFrequency是Windos里面用来返回硬件支持的高精度计数器的频率的API,详细解释点这里。所以mSecondsPerCount 便是计数器两个数之间的时间差。
void Reset()
void GameTimer::Reset()
{
__int64 currTime;
QueryPerformanceCounter((LARGE_INTEGER*)&currTime);
mBaseTime = currTime;
mPrevTime = currTime;
mStopTime = 0;
mStopped = false;
}
重置变量,类似于初始化,在应用程序开始初始化的时候调用一次,QueryPerformanceCounter是WINDOS用来返回当前计数器的值的API,返回值是整数,详细介绍点这里
void Stop()
void GameTimer::Stop()
{
if( !mStopped )
{
__int64 currTime;
QueryPerformanceCounter((LARGE_INTEGER*)&currTime);
mStopTime = currTime;
mStopped = true;
}
}
将游戏暂停,存储暂停的时候的计数器的计数到mStopTime 中。
void Start()
void GameTimer::Start()
{
__int64 startTime;
QueryPerformanceCounter((LARGE_INTEGER*)&startTime);
if( mStopped )
{
mPausedTime += (startTime - mStopTime);
mPrevTime = startTime;
mStopTime = 0;
mStopped = false;
}
}
当游戏暂停时调用这个函数继续开始计数,其中mPausedTime 会把每次暂停时间累加起来。
float TotalTime()const
float GameTimer::TotalTime()const
{
if( mStopped )
{
return (float)(((mStopTime - mPausedTime)-mBaseTime)*mSecondsPerCount);
}
else
{
return (float)(((mCurrTime-mPausedTime)-mBaseTime)*mSecondsPerCount);
}
}
如果暂停了,我们返回暂停时从WINDOS获取的计数减去之前暂停的总计数减去开始游戏时从WINDOS获取的计数,
如果是在运行中就用当前从WINDOS获取的计数减去之前暂停的总计数减去开始游戏时从WINDOS获取的计数。
其中暂停的总计数为每次暂停的计数累加。
void Tick()
void GameTimer::Tick()
{
if( mStopped )
{
mDeltaTime = 0.0;
return;
}
__int64 currTime;
QueryPerformanceCounter((LARGE_INTEGER*)&currTime);
mCurrTime = currTime;
mDeltaTime = (mCurrTime - mPrevTime)*mSecondsPerCount;
mPrevTime = mCurrTime;
if(mDeltaTime < 0.0)
{
mDeltaTime = 0.0;
}
}
如果游戏是暂停的直接那么就不存在帧与帧之间的时间差,所以直接返回0。否则的话用当前的计数器的值减去上一帧的计数器的值,并乘上计数器两个数之间的时间差(mSecondsPerCount)。这个值在构造函数的时候获得,这个值受电脑性能的影响。
在计算出当前帧与上一帧的时间差之后,把当前帧的计数器的值保存到上一帧的值(mPrevTime )里面为下一帧计算做准备。
这个函数需要在游戏的每一帧调用
float DeltaTime()const
float GameTimer::DeltaTime()const
{
return (float)mDeltaTime;
}
返回mDeltaTime,在需要使用的时候调用就可以了。