如何在requestAnimationFrame中调整FPS且不加速游戏运行?
实现可自定义FPS且保证游戏速度不变的动画循环
核心思路
requestAnimationFrame的回调频率和显示器刷新率绑定(通常60Hz),没法直接指定帧率。要实现自定义FPS,得在循环里通过时间差判断,只在达到目标帧率的间隔时才执行游戏逻辑和渲染;同时游戏逻辑必须基于时间增量计算,而不是每帧固定变化量,这样不管帧率高低,游戏速度都一致。
具体实现步骤
1. 定义时间控制变量
需要几个变量来跟踪时间状态:
targetFPS:用户可设置的目标帧率(比如60、30、15)frameInterval:每帧的间隔时间(计算方式:1000ms / targetFPS)lastTime:上一次执行游戏逻辑的时间deltaTime:累计未处理的时间(用来应对卡顿,避免游戏跳帧)
2. 修改动画循环函数
把原函数改成基于时间判断的逻辑:
let targetFPS = 60; // 用户可通过交互修改这个值,比如下拉框选择 let frameInterval = 1000 / targetFPS; let lastTime = performance.now(); let deltaTime = 0; function animate4(currentTime) { // 计算当前与上次的时间差,累加到deltaTime deltaTime += currentTime - lastTime; lastTime = currentTime; // 当累计时间超过帧间隔时,循环处理逻辑(应对卡顿场景) while (deltaTime >= frameInterval) { ctx.clearRect(0, 0, cw, ch); // 给每个游戏层传入时间增量,让逻辑基于时间计算 gamearray.forEach((layer) => { layer.update(deltaTime); }); // 减去已处理的帧间隔时间 deltaTime -= frameInterval; } if (pause === true) { // 注意原代码拼写错误:paause → pause return; } requestAnimationFrame(animate4); } // 启动动画,传入初始时间 requestAnimationFrame(animate4);
3. 改造游戏逻辑的update方法
原来的layer.update()如果是每帧固定变化(比如layer.x += 5),要改成基于时间增量的计算,保证每秒变化量一致:
// 示例:原来的固定帧更新(60FPS时每秒移动300px,30FPS时变成150px,速度变慢) // layer.update = function() { // this.x += 5; // } // 改成基于时间的更新(不管帧率,每秒固定移动300px) layer.update = function(deltaTime) { // 每秒移动300像素 → 每毫秒移动0.3像素 this.x += 0.3 * deltaTime; }
4. 允许用户动态修改FPS
添加一个函数,让用户选择FPS时更新参数:
function setFPS(fps) { targetFPS = fps; frameInterval = 1000 / targetFPS; } // 示例:用户选择30FPS时调用 setFPS(30);
关键细节说明
- while循环处理卡顿:用while而不是if,是为了应对页面卡顿的情况。比如卡顿100ms,目标FPS30(间隔33.33ms),此时deltaTime会累计到100,循环3次处理逻辑,避免游戏状态跳变。
- 时间增量的作用:所有游戏逻辑(移动、动画、技能冷却等)都要基于deltaTime计算,这样帧率变化时,每秒的实际变化量不变,游戏速度就不会受影响。
- requestAnimationFrame的优势:即使我们控制了帧率,依然用requestAnimationFrame驱动循环,因为它会和浏览器渲染同步,避免不必要的绘制,节省性能。
内容的提问来源于stack exchange,提问作者7A7z
相关产品推荐
相关产品推荐

