目 录CONTENT

文章目录

【2D割草类游戏 - 01】游戏中帧率控制

千年的霜雪
2024-08-30 / 1 评论 / 0 点赞 / 10 阅读 / 0 字 / 正在检测是否收录...

【2D割草类游戏 - 01】游戏中帧率控制

游戏中的主程序通常是一个死循环,由于程序运行速度较快,如果不进行帧率控制,就会占用大量资源在无效的循环中,导致游戏卡顿,同时会使游戏在不同设备上的表现不一致。

直接使用Sleep函数

#include <windows.h>
void Sleep(DWORD ms);
// ms - 程序休眠的时间,以毫秒为单位

sleep函数传入的是毫秒,于是直接使用sleep函数就能做到对游戏的延时,计算延时为1000/帧率。但是直接使用sleep得到的仅为理论延时,并没有考虑到游戏本身的运行的时间。由于游戏中每轮循环运行的时间都不同,这样直接使用静态延时时间会导致每轮循环的时间都不同,观感上就会感觉到游戏时不时的卡顿。

使用Clock函数

#include <time.h>
clock_t clock(void);

clock函数返回自程序开始运行后处理器时钟使用的时间,如果失败返回-1
使用clock函数计算程序运行的秒数时,需要除以CLOCKS_PER_SEC常量,该常量是处理器每秒的周期数

clock配合sleep就能达到不错的延时效果,具体为:
1.定义一个静态变量存储上一次循环的时间
2.每次循环都计算出当前循环的用时
3.用每帧间隔时间减去当前循环用时即为当前循环需要休眠的时间

这里给出一个示例函数:

// by yangw80<yw80@qq.com>, 2011-5-4
void HpSleep(int ms)
{
    static clock_t oldclock = clock();        // 静态变量,记录上一次 tick

    oldclock += ms * CLOCKS_PER_SEC / 1000;    // 更新 tick

    if (clock() > oldclock)                    // 如果已经超时,无需延时
        oldclock = clock();
    else
        while(clock() < oldclock)            // 延时
            Sleep(1);                        // 释放 CPU 控制权,降低 CPU 占用率,精度 10~16ms
}

使用GetTickCount函数

#include <Windows.h>
#pragma comment(lib, "Winmm.lib")
DWORD GetTickCount();

使用该函数需要链接库
该函数返回程序自开始运行后的时间,单位是毫秒
该函数的最大返回值为49.7天,如果需要计时更长时间,还有一个64位版本的函数GetTickCount64

下面是使用示例:

static int FRAME_RATE = 144; // 游戏帧率

DWORD start_time = GetTickCount();

{
    // 游戏全部逻辑
}

DWORD end_time = GetTickCount();
DWORD delta_time = end_time - start_time;
if (delta_time < 1000 / FRAME_RATE)
{
    Sleep(1000 / FRAME_RATE - delta_time);
}

sleep函数的精度

Windows API函数Sleep的精度大约在10~16ms,如果要求较高,可以通过timeBeginPeriod函数临时提升Sleep的精度,需要链接库

#include <Windows.h>
#pragma comment(lib, "Winmm.lib")

MMRESULT timeBeginPeriod(
  UINT uPeriod
);

MMRESULT timeEndPeriod(
  UINT uPeriod
);

// uPeriod - 最小计时器分辨率,以ms为单位

使用示例:

#pragma comment(lib,"winmm.lib")        // 1. 链接多媒体库

int main()
{
    timeBeginPeriod(1);                    // 2. 临时提升 Sleep 精度为 1ms

    ///////////////////////////////////////
    // 其它代码,期间会调用若干次 Sleep() 函数
    ///////////////////////////////////////

    timeEndPeriod(1);                    // 3. 恢复 Sleep 精度

    return 0;
}

参考文章

  1. 精确延时的实现 - CodeBus
  2. GetTickCount() 函数的作用和用法-CSDN博客
0

评论区