SDL2 C++中std::chrono计算deltaTime失效,玩家移动仍受帧率影响
问题根源分析
你的deltaTime计算逻辑存在核心问题:当前代码只统计了游戏逻辑+渲染的耗时,完全没把SDL_Delay的休眠时长算进去。因为你在循环开头就把prevTime更新为当前时间,后续的SDL_Delay会让帧的实际时长变长,但这部分延迟没被计入下一次的deltaTime,导致deltaTime的数值远小于真实的每帧时长,最终移动速度还是会随帧率波动。
修复方案
把prevTime的更新操作移到整个帧的末尾(包括SDL_Delay执行完成后),这样deltaTime就能完整覆盖一帧的所有耗时(逻辑处理+渲染+休眠)。同时建议统一时间计算方式,避免混用std::chrono和SDL原生API,减少逻辑混乱。
修改后的游戏循环代码(基于std::chrono实现)
SDL_Event event; int frameCount = 0; auto startTime = std::chrono::high_resolution_clock::now(); long frameStart, frameTime; auto prevTime = std::chrono::high_resolution_clock::now(); while (!quit){ frameStart = SDL_GetTicks(); // 事件处理 while (SDL_PollEvent(&event)){ if (event.type == SDL_QUIT) quit = true; UpdateInput(event); } // 计算当前帧的deltaTime(单位:秒) auto currentTime = std::chrono::high_resolution_clock::now(); std::chrono::duration<double> deltaTime2 = currentTime - prevTime; deltaTime = deltaTime2.count(); // 执行游戏逻辑(包含玩家移动) UpdateGameObjects(); // FPS限制 if (capFPS){ frameTime = SDL_GetTicks() - frameStart; const int frameTarget = 1000 / maxFPS; if (frameTarget > frameTime) { SDL_Delay(frameTarget - frameTime); } } // 关键:帧结束后更新prevTime,确保下一次deltaTime包含休眠时间 prevTime = std::chrono::high_resolution_clock::now(); // FPS统计 frameCount++; auto elapsedSeconds = std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - startTime).count(); if (elapsedSeconds >= 1.0) { int currentFPS = frameCount; text->SetText(std::to_string(currentFPS).c_str()); frameCount = 0; startTime = std::chrono::high_resolution_clock::now(); } }
额外优化建议
- 统一时间API:如果觉得std::chrono过于繁琐,也可以全程用
SDL_GetTicks()实现,逻辑更简洁:// 替换deltaTime计算部分 long currentTime = SDL_GetTicks(); double deltaTime = (currentTime - prevTime) / 1000.0; // 帧末尾更新prevTime prevTime = SDL_GetTicks(); - 修复整数除法误差:
1000 / maxFPS是整数除法,比如maxFPS=60时会得到16,但实际目标帧时长是16.666ms。可以改成static_cast<int>(1000.0 / maxFPS)来获得更精确的目标值。 - 调整速度数值:你当前的移动速度
555 * deltaTime代表每秒移动555像素,这个数值可能过大,测试时可以先改成100左右,再根据实际体验调整。
内容的提问来源于stack exchange,提问作者Nagisa
相关产品推荐
相关产品推荐

