2、刷新循环基础:游戏循环的概念、固定时间步长 vs 可变时间步长、CPU与GPU的协作
说到动画刷新系统,最核心的东西其实就是那个「循环」。说白了,就是让画面一帧一帧地动起来。我刚开始做动画时,以为只要在循环里不断重绘就行了,结果跑起来要么卡成幻灯片,要么CPU风扇狂转。后来才明白——循环本身,是有讲究的。
2.1 游戏循环是什么?
游戏循环,也叫主循环。它是整个动画系统的发动机。每一帧,它都做三件事:
- 处理输入——鼠标、键盘、触摸
- 更新逻辑——位置、碰撞、状态
- 渲染画面——把结果画到屏幕上
这三件事不断重复,直到程序退出。听起来简单吧?但坑全藏在「什么时候做」和「做多快」里。
核心要点:游戏循环决定了动画的流畅度、响应速度和资源消耗。选错策略,后面全白搭。
2.2 固定时间步长 vs 可变时间步长
这是每个做动画的人都会遇到的选择题。我当年也纠结过,后来两种都踩过坑,今天一次性说清楚。
固定时间步长
固定时间步长,就是每次更新逻辑时,都假设过去了固定的时间。比如每帧更新 16.67ms(对应 60fps)。
# 固定时间步长伪代码
FIXED_DT = 1.0 / 60.0 # 每帧16.67ms
accumulator = 0.0
while running:
frame_time = get_frame_time()
accumulator += frame_time
while accumulator >= FIXED_DT:
update(FIXED_DT) # 逻辑更新
accumulator -= FIXED_DT
render() # 渲染
优点:
- 物理模拟稳定,不会因为帧率波动而「跳帧」
- 逻辑可预测,调试方便
- 多人游戏同步容易
缺点:
- 如果渲染太慢,逻辑会堆积(螺旋死亡)
- 需要处理「剩余时间」
我曾经踩过的坑:有一次做物理模拟,用了可变时间步长,结果帧率低的时候物体直接穿墙了。换成固定步长后,问题立刻消失。物理模拟,一定要用固定步长。
可变时间步长
可变时间步长,就是每次更新时,把实际经过的时间传进去。帧率高就更新快,帧率低就更新慢。
# 可变时间步长伪代码
while running:
dt = get_frame_time() # 实际经过的时间
update(dt) # 逻辑更新
render() # 渲染
优点:
- 实现简单,代码量少
- 不会出现逻辑堆积
缺点:
- 物理模拟不稳定,dt 太大时容易出问题
- 帧率波动会直接影响游戏体验
对比表格
| 特性 | 固定时间步长 | 可变时间步长 |
|---|---|---|
| 物理稳定性 | 高 | 低 |
| 实现复杂度 | 中 | 低 |
| 帧率波动影响 | 小 | 大 |
| CPU 占用 | 可控 | 随帧率变化 |
| 适用场景 | 物理模拟、竞技游戏 | UI 动画、简单演示 |
我的建议:做动画系统,优先用固定时间步长。虽然代码多几行,但后面省心太多。可变步长只适合那些「丢了帧也无所谓」的场景。
2.3 CPU 与 GPU 的协作
很多人以为动画就是 CPU 算完,GPU 画完,完事。其实没那么简单。你想想看,CPU 和 GPU 是两套完全不同的硬件,它们怎么配合?
分工明确
- CPU:负责逻辑计算、物理模拟、碰撞检测、场景管理
- GPU:负责顶点处理、光栅化、像素着色、输出画面
说白了,CPU 是「大脑」,GPU 是「画师」。大脑想好了怎么动,画师才动手画。
流水线协作
现代渲染引擎用的是流水线模型。CPU 提交一帧的渲染指令,GPU 开始处理,同时 CPU 继续准备下一帧。就像工厂流水线,一个工位在加工,另一个工位在备料。
# CPU 与 GPU 协作示意
while running:
# CPU 阶段
update_logic() # 更新物理、动画、AI
prepare_render_data() # 准备顶点、纹理、着色器
# 提交到 GPU
submit_to_gpu() # 非阻塞调用,立即返回
# CPU 继续做其他事
# GPU 在后台并行渲染
关键点:CPU 提交渲染指令后,不会等 GPU 画完。它会立刻回来准备下一帧。这就是为什么帧率能跑满的原因——CPU 和 GPU 在并行工作。
同步问题
并行就会带来同步问题。最常见的坑是:
- CPU 跑太快:提交了 3 帧的指令,GPU 才画完 1 帧,导致指令队列溢出
- GPU 跑太快:GPU 空闲,等 CPU 喂数据
解决办法就是「垂直同步」(V-Sync)。它让 CPU 等 GPU 画完当前帧,再提交下一帧。代价是帧率被锁定在显示器刷新率(通常 60Hz)。
我曾经踩过的坑:有一次做高帧率动画,关了垂直同步,结果 GPU 温度飙到 90 度。因为 CPU 疯狂提交指令,GPU 根本停不下来。后来加了帧率限制,温度才降下来。别让 GPU 空转,那是浪费电。
2.4 知识体系总览
下面这张图,把本章的核心逻辑串起来了。你可以把它当作「刷新循环的脑图」。
2.5 本章小结
刷新循环是动画系统的地基。选固定步长还是可变步长,取决于你的场景。物理模拟必须固定步长,UI 动画可以用可变步长。CPU 和 GPU 是并行工作的,别让任何一方空转。垂直同步能解决撕裂,但会锁帧率。