SDL2 游戏中 FPS 波动巨大

问题描述 投票:0回答:1

我开始使用 SDL2 库用 C 语言制作游戏。我刚刚让经典的矩形在空白屏幕上移动,并使用以下内容来计算 delta_time :

Uint64 now = SDL_GetPerformanceCounter();
Uint64 last = 0;
double delta_time = 0;
while (running) {
    last = now;
    now = SDL_GetPerformanceCounter();
    delta_time = (double)(now - last) / SDL_GetPerformanceFrequency();
}

这种方法是否正确,因为我得到的 fps 波动非常疯狂。

385.733269
1021.394121
3567.873440
364.403997
276.115181
700.447376
393.435451
571.590903
494.964479
532.557362
1445.981040
593.772396
1938.300033
468.804132
1008.120410
195.745012

相关代码如下:


void renderContext(GraphicContext* to_render, const Entity* player) {
    if (to_render->renderer == NULL) {
        return;
    }
    SDL_SetRenderDrawColor(to_render->renderer, 255, 255, 255, 255);
    SDL_RenderClear(to_render->renderer);
    SDL_SetRenderDrawColor(to_render->renderer, 255, 255, 0, 255);
    SDL_RenderFillRect(to_render->renderer, (const SDL_Rect*)&player->dimensions);
    SDL_RenderPresent(to_render->renderer);
}

void quitSDL(GraphicContext* m_context) {
    destroyGraphicContext(m_context);
    SDL_Quit();
}

static void handleKeyboard(Entity* player, double delta_time) {
    const Uint8* keys = SDL_GetKeyboardState(NULL);
    double delta_dist = calculateDeltaDist(player, delta_time);
    printf("%lf\n", 1000.0/delta_dist);
    fflush(stdout);

    if (keys[SDL_SCANCODE_A] || keys[SDL_SCANCODE_LEFT]) {
        player->dimensions.x -= delta_dist;
    } if (keys[SDL_SCANCODE_D] || keys[SDL_SCANCODE_RIGHT]) {
        player->dimensions.x += delta_dist;
    } if (keys[SDL_SCANCODE_W] || keys[SDL_SCANCODE_UP]) {
        player->dimensions.y -= delta_dist;
    } if (keys[SDL_SCANCODE_S] || keys[SDL_SCANCODE_DOWN]) {
        player->dimensions.y += delta_dist;
    }
}

static void handleMouse(SDL_Event* event) {

}

int handleEvents(Entity* player, double delta_time) {
    SDL_Event event;

    while (SDL_PollEvent(&event)) {
        if (event.type == SDL_QUIT) {
            return 1;
        }
    }
    //! Usage of this in this way can be a performance bottleneck.
    handleKeyboard(player, delta_time);
    return 0;
}

int main(int argc, char** argv) {
    GraphicContext m_context = createGraphicContext(SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1200, 800,
                                                    "My Game", SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_ALWAYS_ON_TOP);
    int running = 1;
    Entity player = createEntity(100, 100, 32, 32, 100, 1000);
    Uint64 now = SDL_GetPerformanceCounter();
    Uint64 last = 0;
    double delta_time = 0;

    if (m_context.win == NULL) {
        puts("Unable to generate window. Exiting.");
        exit(0);
    }
    while (running) {
        last = now;
        now = SDL_GetPerformanceCounter();
        delta_time = (double)(now - last) / SDL_GetPerformanceFrequency();
        if (handleEvents(&player, delta_time)) {
            break;
        }
        renderContext(&m_context, &player);
    }
    quitSDL(&m_context);
    return 0;
}

当前使用 SDL_RENDERER_PRESENTVSYNC 作为渲染标志修复了该问题,并且我获得了一致的 60 fps。

有没有更好的方法可以做到这一点,或者我做错了什么。任何事情都会有所帮助

c sdl game-development game-engine sdl-2
1个回答
0
投票

当前使用 SDL_RENDERER_PRESENTVSYNC 作为渲染标志修复了该问题,并且我获得了一致的 60 fps。

VSync 可将您的循环频率与显示器的频率同步。在你的机器上是 60fps,在我的机器上是 280fps,在其他机器上可能低至 15。垂直同步是给用户的一个很好的选项,但不是作为你的代码的基础。

delta_time = (double)(现在 - 最后) / SDL_GetPerformanceFrequency();

如果这就是您测量 fps 的方式 (

1.0 / delta_time
),那么使用它就太不稳定了。相反,计算单位时间内的帧数(我通常计算 2 秒以上),并且仅在超时触发时更新您的 fps 变量,将帧计数器重置回 0。

© www.soinside.com 2019 - 2024. All rights reserved.