Достижение постоянной частоты кадров в SDL

StackOverflow https://stackoverflow.com/questions/2548541

  •  23-09-2019
  •  | 
  •  

Вопрос

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

Ребята, у вас есть какие-нибудь предложения, как сделать мою программу более плавной?

#include "SDL.h"
#include "SDL/SDL_ttf.h"

//in milliseconds
const int FPS = 24;
const int SCREENW = 400;
const int SCREENH = 300;
const int BPP = 32;

void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination) {

    SDL_Rect offset;

    offset.x = x;

    offset.y = y;



    if(SDL_BlitSurface(source, NULL, destination, &offset) < 0) {
        printf("%s\n", SDL_GetError());
    }

}

int main(int argc, char* argv[]) {
    //calculate the period
    double period = 1.0 / (double)FPS;
    period = period * 1000;
    int milliPeriod = (int)period;
    int sleep;

    SDL_Init(SDL_INIT_EVERYTHING);
    TTF_Init();

    TTF_Font* font = TTF_OpenFont("/usr/share/fonts/truetype/freefont/FreeMono.ttf", 24);
    SDL_Color textColor = { 0x00, 0x00, 0x00 };

    SDL_Surface* screen = SDL_SetVideoMode(SCREENW, SCREENH, BPP, SDL_SWSURFACE);
    SDL_Surface* message = NULL;

    Uint32 white = SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF);

    SDL_Event event;

    char str[15];

    Uint32 lastTick;
    Uint32 currentTick;
    while(1) {
        while(SDL_PollEvent(&event)) {
            if(event.type == SDL_QUIT) {
                return 0;
            }
            else {
                lastTick = SDL_GetTicks();

                sprintf(str, "%d", lastTick);
                message = TTF_RenderText_Solid(font, str, textColor);
                if(message == NULL) { printf("%s\n", SDL_GetError()); return 1; }

                //the actual blitting
                SDL_FillRect(screen, &screen->clip_rect, white);
                apply_surface(SCREENW / 2, SCREENH / 2, message, screen);

                currentTick = SDL_GetTicks();

                //wait the appropriate amount of time
                sleep = milliPeriod - (currentTick - lastTick);
                if(sleep < 0) { sleep = 0; }
                SDL_Delay(sleep);

                SDL_Flip(screen);
            }
        }
    }

    TTF_CloseFont(font);
    TTF_Quit();
    SDL_Quit();

    return 0;
}
Это было полезно?

Решение

Не спи.

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

Также существуют другие функции интерполяции / наложения (такие как линейный ввод, простой вывод, квадратичный ввод / вывод, кубический и т.д.) Для других интересных эффектов.

Проверьте эту ссылку:Линейная Интерполяция, не зависящая от частоты кадров

Другие советы

Есть небольшой пример того, как это сделать на http://www.libsdl.org/release/SDL-1.2.15/docs/html/guidetimeexamples.html:

#define TICK_INTERVAL    30

static Uint32 next_time;

Uint32 time_left(void)
{
    Uint32 now;

    now = SDL_GetTicks();
    if(next_time <= now)
        return 0;
    else
        return next_time - now;
}


/* main game loop */

    next_time = SDL_GetTicks() + TICK_INTERVAL;
    while ( game_running ) {
        update_game_state();
        SDL_Delay(time_left());
        next_time += TICK_INTERVAL;
    }

Как сказал дикроче, не спи.Почему?Поскольку большинство настольных операционных систем не являются жесткими системами реального времени, и поэтому sleep(10) это не означает "разбуди меня ровно через 10 миллисекунд", это означает "убедитесь, что я сплю не менее 10 миллисекунд".Это означает, что иногда вы спите намного дольше, чем хотели.Это редко бывает тем, чего вы хотите.Если важен плавный игровой процесс, то, как правило, вы просто хотите выполнять рендеринг как можно чаще - SDL_Flip справится с этим за вас, при условии, что в ваших видеодрайверах не отключена VSync.

Вместо того чтобы спать, dicroce предложил алгоритм линейной интерполяции для вычисления правильных положений ваших объектов в любой момент времени.Хотя это разумная стратегия для многих игр, и я обычно использую ее сам, в некоторых случаях она может вызвать проблемы, если обращаться с ней неосторожно:тот самый "Основы интеграции" статья объясняет кое-что из этого.Альтернатива, предложенная в следующей статье того же автора, называется "Зафиксируйте Свой Временной интервал".

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top