zoukankan      html  css  js  c++  java
  • 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()

    分别暂停和恢复定时器。

  • 相关阅读:
    java虚拟机理解探索1
    Java线程面试题 Top 50(转载)
    (转载)浅谈我对DDD领域驱动设计的理解
    最大堆
    利用筛法求质数
    递归算法及优化
    java 根据传入的时间获取当前月的第一天的0点0分0秒和最后一天的23点59分59秒
    Uncaught Error: Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3
    mysql 子查询问题
    微信7.0以后更新后H5页面定位不准确
  • 原文地址:https://www.cnblogs.com/zhangbaochong/p/5270077.html
Copyright © 2011-2022 走看看