Directx11学习笔记【七】 游戏定时器的实现

  无论是在动画还是在一些游戏中,定时器总是必不可少的,游戏的帧数动画的播放等都离不开定时器的控制。这里以dx11龙书中提供的定时器为例,具体看看是怎么实现一个简单但精度高使用方便的定时器的。

  这个定时器使用的windows中的高精度计时函数QueryPerformanceCounter和QueryPerformanceFrequency

BOOL QueryPerformanceCounter(  LARGE_INTEGER* lpPerformanceCount );
BOOL QueryPerformanceFrequency(  LARGE_INTEGER* lpFrequency );
 QueryPerformanceCounter函数以计数为单位,因为不同的机器中两次计数之间的差值可能不同,所以就需要QueryPerformanceFrequency函数 返回1s内计数的个数
__int64 countsPerSec;
QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec);
m_secondsPerCount = 1.0 / countsPerSec;

  通过这样便可以得到系统两次计数之间的时间差,这是定时器把时间转换为秒的基准。

  下面看看这个定时器类GameTimer的具体实现

  GameTimer.h

 1 #ifndef GAMETIMER_H
 2 #define GAMETIMER_H
 3 
 4 class GameTimer
 5 {
 6 public:
 7     GameTimer();
 8     float TotalTime() const;//返回定时器从计时开始到现在的总时间,不包括暂停时间
 9     float DeltaTime() const;//返回本次计时与上次计时之间的时间差
10 
11     void Reset();//重置
12     void Start();//暂停后恢复计时
13     void Stop();//暂停
14     void Tick();//计时一次,每一帧调用
15 
16 private:
17     double m_secondsPerCount;//系统相关,系统两次计数之间的时间差,是定时器把时间转换为s的基准
18     double m_deltaTime;//距离上次计时的时间差
19 
20     __int64 m_baseTime;//定时器开始工作的时间点
21     __int64 m_pausedTime;//暂停的总时间
22     __int64 m_stopTime;//暂停的开始时间
23     __int64 m_prevTime;//上次计时的时间点
24     __int64 m_currTime;//本次计时的时间点
25 
26     bool m_isStopped;//是否暂停
27 };
28 
29 #endif    //GAMETIMER_H

  

  GameTimer.cpp

 1 #include "GameTimer.h"
 2 #include <windows.h>
 3 
 4 GameTimer::GameTimer() : m_secondsPerCount(0.0), m_deltaTime(-1.0), m_baseTime(0), m_pausedTime(0),
 5 m_prevTime(0), m_currTime(0), m_isStopped(false)
 6 {
 7     __int64 countsPerSec;
 8     QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec);
 9     m_secondsPerCount = 1.0 / countsPerSec;
10 }
11 
12 
13 float GameTimer::TotalTime() const
14 {
15     if (m_isStopped)
16     {
17         return static_cast<float>((m_stopTime - m_baseTime - m_pausedTime)*m_secondsPerCount);
18     }
19     else
20     {
21         return static_cast<float>((m_currTime - m_baseTime - m_pausedTime)*m_secondsPerCount);
22     }
23 }
24 
25 float GameTimer::DeltaTime() const
26 {
27     return static_cast<float>(m_deltaTime);
28 }
29 
30 void GameTimer::Tick()
31 {
32     if (m_isStopped)
33     {
34         m_deltaTime = 0.0;
35         return;
36     }
37     //得到这一帧的时间
38     __int64 currentTime;
39     QueryPerformanceCounter((LARGE_INTEGER*)&currentTime);
40     m_currTime = currentTime;
41 
42     //两次计时之间的时间
43     m_deltaTime = (m_currTime - m_prevTime) * m_secondsPerCount;
44 
45     m_prevTime = m_currTime;
46 
47     if (m_deltaTime < 0.0)
48         m_deltaTime = 0.0;
49 }
50 
51 void GameTimer::Reset()
52 {
53     __int64 currentTime;
54     QueryPerformanceCounter((LARGE_INTEGER*)(&currentTime));
55 
56     m_baseTime = currentTime;
57     m_prevTime = currentTime;
58     m_stopTime = 0;
59     m_isStopped = false;
60 }
61 
62 void GameTimer::Start()
63 {
64     __int64 startTime;
65     QueryPerformanceCounter((LARGE_INTEGER*)&startTime);
66 
67     if (m_isStopped)
68     {
69         //更新暂停的总时间
70         m_pausedTime += (startTime - m_stopTime);
71 
72         m_prevTime = startTime;
73 
74         //不再暂停
75         m_stopTime = 0;
76         m_isStopped = false;
77     }
78 }
79 
80 void GameTimer::Stop()
81 {
82     if (!m_isStopped)
83     {
84         __int64 currentTime;
85         QueryPerformanceCounter((LARGE_INTEGER*)&currentTime);
86 
87         m_stopTime = currentTime;
88         m_isStopped = true;
89     }
90 }

  注释已经很详细了,类中函数和变量的作用也很明显。构造函数主要是获得根机器相关的变量,得到两次计数之间的时间差。

  定时第一次工作是应调用Reset()初始化,以后在每一帧中调用Tick()更新计时器的各种变量。通过TotalTime()和DeltaTime()可以得到相关时间信息,用Stop()和Start()

分别暂停和恢复定时器。

原文地址:https://www.cnblogs.com/zhangbaochong/p/5270077.html