在不同电脑上限制游戏的速度

3

我正在使用OpenGL和C++创建一个2D游戏。

我希望游戏在不同的电脑上运行速度相同,目前我的游戏在我的台式机上比在我的笔记本电脑上运行得更快(即我的玩家在我的台式机上移动得更快)。

有人告诉我可以使用QueryPerformanceCounter(),但我不知道如何使用它。

请问如何使用它,或者是否有更好/更容易的方法?

这是我的Display函数:

void display()                                  
{
static long timestamp = clock();
// First frame will have zero delta, but this is just an example.
float delta = (float)(clock() - timestamp) / CLOCKS_PER_SEC;

glClear(GL_COLOR_BUFFER_BIT);

glLoadIdentity();

createBackground();

int curSpeed = (player.getVelocity()/player.getMaxSpeed())*100;

glColor3f(1.0,0.0,0.0);
glRasterPos2i(-screenWidth+20,screenHeight-50);
glPrint("Speed: %i",curSpeed);

glRasterPos2i(screenWidth-200,screenHeight-50);
glPrint("Lives: %i",lives);

glRasterPos2i(screenWidth-800,screenHeight-50);
glPrint("Heading: %f",player.getHeading());

for(int i = 0;i<90;i++){
    if (numBullets[i].fireStatus == true){
        numBullets[i].updatePosition(player);
        if (numBullets[i].getXPos() > screenWidth || numBullets[i].getXPos() < -screenWidth || numBullets[i].getYPos() > screenHeight || numBullets[i].getYPos() < -screenHeight ){
            numBullets[i].fireStatus = false;
            numBullets[i].reset(player);
            numBullets[i].~Bullet();
        }
    }
}

player.updatePosition(playerTex,delta);

glFlush();

timestamp = clock();

我的更新位置方法

void Player::updatePosition(GLuint playerTex, float factor){
//draw triangle
glPushMatrix();

glEnable(GL_TEXTURE_2D);    
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, playerTex);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

glTranslatef(factor*XPos, factor*YPos, 0.0);
glRotatef(heading, 0,0,1);
glColor3f(1.0,0.0,0.0);
    glBegin(GL_POLYGON);
        glTexCoord2f(0.0, 1.0); glVertex2f(-40,40);
        glTexCoord2f(0.0, 0.0); glVertex2f(-40,-40);
        glTexCoord2f(1.0, 0.0); glVertex2f(40,-40);
        glTexCoord2f(1.0, 1.0); glVertex2f(40,40);
    glEnd();

glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glPopMatrix();

XPos += speed*cos((90+heading)*(PI/180.0f));
YPos += speed*sin((90+heading)*(PI/180.0f));
}

我记得我的游戏在20世纪80年代有这个问题。尽管当时的PC有时钟,但并不是所有的游戏开发者都在使用它们。 - csj
3个回答

9

通常情况下,您希望基于时间差进行所有游戏玩法计算,即自上一帧以来经过的时间量。这将使速度在所有设备上标准化。除非您需要极高的精度,否则可以使用<ctime>中的clock()函数获取当前时间戳。

例如:

void main_loop() {
   static long timestamp = clock();
   // First frame will have zero delta, but this is just an example.
   float delta = (float)(clock() - timestamp) / CLOCKS_PER_SEC;

   calculate_physics(delta);
   render();

   timestamp = clock();
}

void calculate_physics(float delta) {
   // Calculate expected displacement per second.
   applyDisplacement(displacement * delta);
}

void render() {
   // Do rendering.
}

编辑:如果您想要更高的精确度,您应该使用操作系统的定时器功能。在Windows中,最精确的方法是使用QueryPerformanceCounter()。示例

#include <windows.h>

void main_loop(double delta) {
  // ...
}

int main() {
  LARGE_INTEGER freq, last, current;
  double delta;
  QueryPerformanceFrequency(&freq);

  QueryPerformanceCounter(&last);
  while (1) {
    QueryPerformanceCounter(&current);
    delta = (double)(current.QuadPart - last.QuadPart) / (double)freq.QuadPart;

    main_loop(delta);

    last = current;
  }
}

这只是一个占位符,用于任何执行动画的函数。 - Max Shawabkeh
所以 Delta 是一个我应用于所有动画等的值,以便它们在任何地方以相同的速度运行? - Chris
是的。在典型调用中,delta的值会因机器而异,取决于每台机器可以挤出的帧速率。将delta应用于动画的幅度将平衡差异。 - Max Shawabkeh
不应该发生这种情况。请确保您没有在某个地方进行整数计算而不是浮点计算。顺便问一下,90+heading是怎么回事?sin()cos()的操作单位是弧度,而不是角度。 - Max Shawabkeh
编辑了一个(不可移植的)例子,更加精确。 - Max Shawabkeh
显示剩余10条评论

5
大多数游戏使用帧时间缩放因子。本质上,您需要找到您的物理和运动所设定的帧长度,并将其分配到游戏实际运行的帧长度之间(1/fps)。这会产生一个标量因子,您可以通过乘以移动变化来保持所有移动的一致性,同时保持从增加FPS中获得的好处。
这里有一个很好的例子: 点击这里

我们其余的人称之为“固定时间步循环”。 - Andreas Magnusson

0
你的问题的最佳解决方案是每10毫秒(或类似时间)更新一次对象的位置,但尽可能经常渲染对象。这被称为“固定时间步长”,因为你只在固定间隔更新游戏状态。这要求你将渲染代码与更新代码分离(这本来就是个好主意)。
基本上(在伪代码中),你需要做的是:
accumulatedTimeSinceLastUpdate = 0;
while(gameIsRunning)
{
  accumulatedTimeSinceLastUpdate += timeSinceLastFrame();
  while(accumulatedTimeSinceLastUpdate >= 10) // or another value
  {
    updatePositions();
    accumulatedTimeSinceLastUpdate -= 10;
  }
  display();
}

这意味着如果您的计算机运行速度非常快,display() 将被调用很多次,并且不时更新位置。如果您的计算机超级慢,则每次调用 display() 时可能会调用多次 updatePositions。

这是另一篇好文章(除了 Mason Blier 的文章之外):


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接