17

一定のフレーム レートで実行される 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;
}
4

3 に答える 3

9

これを行う方法の小さな例が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;
    }
于 2010-03-30T21:08:06.033 に答える
8

寝ないで。

代わりに、線形補間関数を使用して、メイン ループを通過するたびに現在の時間を指定して位置を計算します。これを行うと、ハードウェアに関係なく、宇宙船が同時に目的地に到着することが保証されます (ただし、高速なマシンでは、間に多くのステップが表示されます)。

また、他のクールな効果のための他の補間/ブレンド関数 (線形イーズイン、イーズアウト、二次イーズイン/アウト、キュービックなど) もあります。

このリンクを確認してください: フレーム レートに依存しない線形補間

于 2010-03-30T20:48:51.430 に答える
3

ディクロースが言ったように、眠らないで。なんで?ほとんどのデスクトップ オペレーティング システムはハード リアルタイム システムではないため、「正確に 10 ミリ秒で目を覚ます」sleep(10)という意味ではなく、「少なくとも 10 ミリ秒スリープ状態であることを確認する」という意味です。これは、時々、あなたが望んでいたよりもずっと長い睡眠をとることを意味します. これが必要になることはめったにありません。スムーズなゲームプレイが重要な場合は、通常、できるだけ頻繁にレンダリングする必要があります。ビデオ ドライバーで VSync が無効になっていない場合は、SDL_Flip が処理します。

dicroce は、スリープする代わりに、いつでもエンティティの正しい位置を計算するための線形補間アルゴリズムを提案しました。これは多くのゲームにとって合理的な戦略であり、私自身も通常使用するものですが、慎重に扱わないと問題が発生する場合があります。「統合の基本」の記事では、このいくつかについて説明しています。「 Fix Your Timestep 」と呼ばれる、同じ著者の次の記事で提供されている代替案。

于 2010-03-31T10:13:00.413 に答える