在 SDL 中实现恒定的帧速率

发布于 2024-08-26 19:13:05 字数 2165 浏览 4 评论 0原文

我正在尝试制作一个以恒定帧速率运行的 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;
}

I'm trying to make an SDL program that runs with a constant frame rate. However I'm finding that even though my program is lagging a lot and skipping a lot of frames (even though it's running at a low frame and isn't rendering much).

Do you guys have any suggestions to make my program run smoother?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

相思碎 2024-09-02 19:13:05

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

There is a small example of how to do this at 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;
    }
虚拟世界 2024-09-02 19:13:05

别睡觉。

相反,使用线性插值函数来计算每次通过主循环给定当前时间的位置。这样做将保证无论硬件如何,太空飞船都会同时到达目的地(尽管在快速机器上,您会看到更多的中间步骤)。

还有其他插值/混合函数(如线性缓入、缓出、二次缓入/缓出、三次等),可实现其他炫酷效果。

查看此链接:
帧速率独立线性插值

Don't sleep.

Instead, use a linear interpolation function to compute your position given the current time each time through the main loop. Doing this will guarantee that no matter the hardware, space ships arrive at their destinations at the same time (though on a fast machine, you'll see more of the steps in between).

Also there are other interpolation/blending functions (like linear ease in, ease out, quadratic ease in/out, cubic, etc.) for other cool effects.

Check this link out:
Frame Rate Independent Linear Interpolation

心的位置 2024-09-02 19:13:05

正如迪克罗克所说,不要睡觉。为什么?因为大多数桌面操作系统都不是硬实时系统,因此 sleep(10) 并不意味着“在 10 毫秒内唤醒我”,它意味着 >“确保我至少睡着 10 毫秒”。这意味着有时您的睡眠时间比您想要的要长得多。这很少是您想要的。如果流畅的游戏体验很重要,那么通常您只想尽可能频繁地渲染 - SDL_Flip 会为您处理该问题,前提是您的视频驱动程序没有禁用 VSync。

dicroce 建议使用线性插值算法来计算实体在任何给定时间的正确位置,而不是睡觉。虽然这对于许多游戏来说是一种合理的策略,而且我自己也经常使用,但如果处理不当,在某些情况下可能会导致问题:“集成基础" 文章解释了其中的一些内容。同一作者的下一篇文章中提供了一种替代方案,名为“修复您的时间步长” ”。

As dicroce said, don't sleep. Why? Because most desktop operating systems are not hard real-time systems, and therefore sleep(10) does not mean "wake me up in exactly 10 milliseconds", it means "ensure I am asleep for at least 10 milliseconds". This means that sometimes you spend a lot longer sleeping than you wanted. This is rarely what you want. If smooth gameplay is important then generally you just want to render as frequently as you can - SDL_Flip handles that for you, providing your video drivers don't have VSync disabled.

Instead of sleeping, dicroce suggested a linear interpolation algorithm to calculate the correct positions for your entities at any given time. While this is a reasonable strategy for many games, and one I usually use myself, it can cause problems in some cases if not handled carefully: the "Integration Basics" article explains some of this. An alternative offered in the same author's next article, called "Fix Your Timestep".

や三分注定 2024-09-02 19:13:05

我尝试过并且似乎有效的方法是一种没有延迟的方法,但使用了类似的方法:

int desired_fps = 60; 
int last_ticks = SDL_GetTicks();
while (true) {
     if (SDL_GetTicks() - last_ticks < 1000/desired_fps) {
         continue;
     } 
     last_ticks = SDL_GetTicks();
     // ... render frame...
}

The approach I've tried and seems working is one without delays but using something along the lines:

int desired_fps = 60; 
int last_ticks = SDL_GetTicks();
while (true) {
     if (SDL_GetTicks() - last_ticks < 1000/desired_fps) {
         continue;
     } 
     last_ticks = SDL_GetTicks();
     // ... render frame...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文