You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

HTML5 Canvas游戏开发中帧率与显示器刷新率适配卡顿问题咨询

解决Canvas动画跨帧率卡顿问题的正确姿势

嘿,我一眼就揪出问题所在了——你的位移计算完全搞错了delta time(增量时间)的核心作用!

先拆解下你的逻辑矛盾:你现在用this.x += this.vx * dt * fps,但本质上dt = 1/fps(因为dt是两帧的时间差,fps是每秒帧数,换算后dt就是1秒除以fps),所以dt * fps其实等于1,这相当于你完全没用到dt做帧率适配,每帧都固定移动vx像素!

这就导致了直观的卡顿差异:

  • 144Hz显示器每秒更新144次,每次移动2px,视觉上是细腻的小步移动
  • 60Hz显示器每秒仅更新60次,每次同样移动2px,视觉上是更大的跳跃步长,自然会显得卡顿

正确的实现逻辑

delta time的核心意义是把“每帧移动多少像素”转换成“每秒移动多少像素”,让物体运动速度完全和帧率解绑。正确的计算应该是:

  1. 位移 = 速度(像素/秒) × dt(当前帧占用的时间,单位:秒)
  2. 加速度(比如重力)的更新也要乘以dt,因为加速度是“像素/秒²”,速度增量=加速度×时间

修正后的代码示例

let previous = 0;
// 设定速度单位为「像素/秒」,比如vx=288表示每秒移动288像素(对应144Hz下每帧2px)
const vx = 288;
let vy = 0;
const gravity = 980; // 模拟重力,单位:像素/秒²

function update(timestamp = Date.now()){ 
  if(!previous) previous = timestamp; 
  const dt = (timestamp - previous) / 1000; 
  // 可选优化:限制最大dt,避免页面切后台后再激活时出现跳帧
  const clampedDt = Math.min(dt, 0.1);
  const fps = 1000 / (timestamp - previous); 
  previous = timestamp; 

  // 正确的运动更新逻辑
  this.x += vx * clampedDt; 
  this.y += vy * clampedDt; 
  vy += gravity * clampedDt; 

  // 你的其他渲染、游戏逻辑代码...

  window.requestAnimationFrame(update); 
} 
window.requestAnimationFrame(update);

额外优化建议

  • 限制dt最大值:当页面被切换到后台,requestAnimationFrame会暂停,再次激活时dt会变得极大,导致物体瞬间瞬移。用Math.min(dt, 0.1)把dt限制在0.1秒内,能避免这种极端情况。
  • 固定时间步长(可选):如果你的游戏涉及物理碰撞等精准逻辑,建议用固定时间步长更新物理(比如每16ms更新一次),渲染时再根据剩余时间做位置插值,这样不管帧率波动多大,物理逻辑都是稳定的。

这样修改后,60Hz下的动画会立刻变得流畅——虽然每帧移动的像素数比144Hz多,但整体速度保持一致,基于时间的增量会让运动看起来连续自然,不会再有卡顿感。

内容的提问来源于stack exchange,提问作者nitroflox

火山引擎 最新活动