Ограничить скорость геймплея на разных компьютерах - PullRequest
3 голосов
/ 20 февраля 2010

Я создаю 2D-игру, используя OpenGL и C ++.

Я хочу, чтобы игра работала с одинаковой скоростью на разных компьютерах. В данный момент моя игра работает на моем настольном компьютере быстрее, чем на моем ноутбуке (то есть мой игрок быстрее на моем настольном компьютере)

Мне сказали о QueryPerformanceCounter (), но я не знаю, как это использовать.

как мне это использовать или есть лучший / более простой способ?

Моя функция отображения

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));
}

Ответы [ 3 ]

9 голосов
/ 20 февраля 2010

Как правило, вы хотите делать все расчеты игрового процесса на основе дельты времени, то есть количества времени, прошедшего с последнего кадра. Это стандартизирует скорость на всех машинах. Если вам не нужна предельная точность, вы можете использовать clock() (из <ctime>) для получения текущей отметки времени.

Пример:

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;
  }
}
4 голосов
/ 20 февраля 2010

В большинстве игр используется коэффициент масштабирования кадра. По сути, вы находите длину кадра, на котором установлена ​​ваша физика и движение, и делите ее на фактическую длину кадра, на котором работает игра (1 / кадр / с). Это приводит к скалярному коэффициенту, который можно умножить на изменения в движении, чтобы сохранить постоянство всех движений, сохраняя при этом выгоды от увеличения FPS.

Хороший пример: здесь.

0 голосов
/ 23 февраля 2010

Лучшее решение вашей проблемы - обновлять позиции ваших объектов каждые 10 мс (или что-то подобное), но визуализировать объекты как можно чаще. Это называется «фиксированным временным шагом», поскольку вы обновляете состояние игры только через фиксированные интервалы. Это требует от вас отделения кода рендеринга от кода обновления (что в любом случае является хорошей идеей).

В основном (в псевдокоде) вы должны сделать что-то вроде:

accumulatedTimeSinceLastUpdate = 0;
while(gameIsRunning)
{
  accumulatedTimeSinceLastUpdate += timeSinceLastFrame();
  while(accumulatedTimeSinceLastUpdate >= 10) // or another value
  {
    updatePositions();
    accumulatedTimeSinceLastUpdate -= 10;
  }
  display();
}

Это означает, что если на вашем компьютере работает super-duper fast, то display () будет вызываться много раз и время от времени updatePositions (). Если ваш компьютер работает очень медленно, updatePositions может вызываться несколько раз при каждом вызове display ().

Вот еще одно хорошее чтение (в дополнение к Мейсону Блиеру):

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...