我想计时 fps 计数,并将其限制设置为 60,但是我一直在通过谷歌查看一些代码,我完全不明白。
5 回答
如果您想要 60 FPS,您需要计算出每帧有多少时间。在本例中,为 16.67 毫秒。所以你想要一个每 16.67 毫秒完成一次的循环。
通常它会(简单地说):获取输入,做物理工作,渲染,暂停直到 16.67 毫秒过去。
它通常通过在循环顶部保存时间然后在结束时计算差异并在此期间休眠或循环不做任何事情来完成。
本文描述了几种不同的游戏循环方式,包括您想要的一种,尽管我将使用本文中更高级的替代方法之一。
delta time 是最后的时间,减去原来的时间。
dt= t-t0
然而,这个增量时间只是速度变化时经过的时间量。
函数的导数表示函数相对于其中一个变量的无穷小变化。函数对变量的导数定义为
f(x + h) - f(x)
f'(x) = lim -----------------
h->0 h
http://mathworld.wolfram.com/Derivative.html
#include<time.h>
#include<stdlib.h>
#include<stdio.h>
#include<windows.h>
#pragma comment(lib,"winmm.lib")
void gotoxy(int x, int y);
void StepSimulation(float dt);
int main(){
int NewTime = 0;
int OldTime = 0;
float dt = 0;
float TotalTime = 0;
int FrameCounter = 0;
int RENDER_FRAME_COUNT = 60;
while(true){
NewTime = timeGetTime();
dt = (float) (NewTime - OldTime)/1000; //delta time
OldTime = NewTime;
if (dt > (0.016f)) dt = (0.016f); //delta time
if (dt < 0.001f) dt = 0.001f;
TotalTime += dt;
if(TotalTime > 1.1f){
TotalTime=0;
StepSimulation(dt);
}
if(FrameCounter >= RENDER_FRAME_COUNT){
// draw stuff
//Render();
gotoxy(1,2);
printf(" \n");
printf("OldTime = %d \n",OldTime);
printf("NewTime = %d \n",NewTime);
printf("dt = %f \n",dt);
printf("TotalTime = %f \n",TotalTime);
printf("FrameCounter = %d fps\n",FrameCounter);
printf(" \n");
FrameCounter = 0;
}
else{
gotoxy(22,7);
printf("%d ",FrameCounter);
FrameCounter++;
}
}
return 0;
}
void gotoxy(int x, int y){
COORD coord;
coord.X = x; coord.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
return;
}
void StepSimulation(float dt){
// calculate stuff
//vVelocity += Ae * dt;
}
您不应该尝试限制 fps。这样做的唯一原因是如果您不使用增量时间并且您希望每个帧的长度相同。即使是最简单的游戏也不能保证这一点。
但是,您可以将增量时间切成固定大小,然后保留其余部分。
这是我最近写的一些代码。它没有经过彻底的测试。
void GameLoop::Run()
{
m_Timer.Reset();
while(!m_Finished())
{
Time delta = m_Timer.GetDelta();
Time frameTime(0);
unsigned int loopCount = 0;
while (delta > m_TickTime && loopCount < m_MaxLoops)
{
m_SingTick();
delta -= m_TickTime;
frameTime += m_TickTime;
++loopCount;
}
m_Independent(frameTime);
// add an exception flag later.
// This is if the game hangs
if(loopCount >= m_MaxLoops)
{
delta %= m_TickTime;
}
m_Render(delta);
m_Timer.Unused(delta);
}
}
成员对象是 Boost 插槽,因此不同的代码可以使用不同的计时方法注册。独立插槽用于诸如键映射或更改音乐之类的不需要如此精确的事物。SingTick 对物理学有好处,如果您知道每个滴答声都是相同的,但您不想穿过墙壁,这会更容易。渲染采用增量,因此动画运行流畅,但必须记住在下一个 SingTick 中考虑它。
希望有帮助。
您不应该以这种方式限制帧速率有很多充分的理由。正如 stijn 指出的那样,一个原因是,并非每个显示器都可以精确地以 60fps 运行,另一个原因是计时器的分辨率不够,另一个原因是即使给定足够的分辨率,两个单独的计时器(显示器刷新和你的)也在运行由于随机不准确,并行将始终与时间不同步(它们必须!),最重要的原因是根本没有必要。
请注意,Windows 下的默认计时器分辨率是 15 毫秒,而您可以获得的最佳分辨率(通过使用 timeBeginPeriod)是 1 毫秒。因此,您可以(最多)等待 16 毫秒或 17 毫秒。60fps 的一帧是 16.6666ms 你如何等待 16.6666ms?
如果您想将游戏速度限制为显示器的刷新率,请启用垂直同步。这将精确地完成您想要的操作,并且不会出现同步问题。垂直同步也有其特殊性(例如当一帧需要 16.67 毫秒时您会得到有趣的惊喜),但它是迄今为止最好的解决方案。
如果您想要这样做的原因是为了让您的模拟适合渲染循环,那么这对您来说是必读的。
看看这个:
//Creating Digital Watch in C++
#include<iostream>
#include<Windows.h>
using namespace std;
struct time{
int hr,min,sec;
};
int main()
{
time a;
a.hr = 0;
a.min = 0;
a.sec = 0;
for(int i = 0; i<24; i++)
{
if(a.hr == 23)
{
a.hr = 0;
}
for(int j = 0; j<60; j++)
{
if(a.min == 59)
{
a.min = 0;
}
for(int k = 0; k<60; k++)
{
if(a.sec == 59)
{
a.sec = 0;
}
cout<<a.hr<<" : "<<a.min<<" : "<<a.sec<<endl;
a.sec++;
Sleep(1000);
system("Cls");
}
a.min++;
}
a.hr++;
}
}