为何使用 Canvas 内元素动画总是在颤抖?

背景

过年的项目中遇到一个问题让我百思不得其解,明明我的帧率保持在60帧,为何我的动画却一直抖动?

我的场景是一个匀速直线运动的物体。

先上一个 Demo

在这个 Demo 中,小姐姐是按照 x 轴 10px/s,y 轴 30 px/s 进行移动的,不过她的移动是明显伴随着抖动的。

这到底是怎么了呢?

解决

如果小姐姐的y轴速度是10px/s,我们的帧率是60f/s,计算一下:

10 / 60 = 1/6 (px/f)

实际上,的实际速度是每 6 帧才会移动 1px,这当然会有抖动,小姐姐走一步停一会,当然会抖喽~

我索性把小姐姐的移动速度调快,调成 100px/s,发现,还是会抖动,以为高高兴兴能解决了这个问题,发现还是没那么简单。

既然我们能算,那我们就算一算

100 / 60 = 10/6 (px/f) = 1.666666....(px/f)

写了个for循环,看看一秒中每一帧小姐姐都在什么位置

for(let i = 0; i < 60; i ++) {
  console.log(i*10/6)
}

输出结果是这样的:

0 1.66 3.33 4.99 6.66 8.33 9.99 11.66 13.33 14.99 16.66 18.33 19.99 21.66 23.33 24.99 26.66 28.33 29.99 31.66
33.33 34.99 36.66 38.33 39.99 41.66 43.33 44.99 46.66 48.33 49.99 51.66 53.33 54.99 56.66 58.33 59.99 61.66 63.33 64.99
66.66 68.33 69.99 71.66 73.33 74.99 76.66 78.33 79.99 81.66 83.33 84.99 86.66 88.33 89.99 91.66 93.33 94.99 96.66 98.33

那么作为小数,Canvas 将如何定位呢?

我们来写一个 Demo

使用 Chrome 打开,作为一个像素眼,我发现,小姐姐定位在 50.6px 的时候,其实就已经被渲染到 51px 的位置。

所以在Chrome中,应该使用了 Banker's rounding 来处理小数的问题。

所以真正的位置其实是

 0 2 3 5 7 8 10 12 13 15 17 18 20 22 23 25 27 28 30 32
 33 35 37 38 40 42 43 45 47 48 50 52 53 55 57 58 60 62 63 65
 67 68 70 72 73 75 77 78 80 82 83 85 87 88 90 92 93 95 97 98

从数值来看,每帧移动的距离可能是 1px 也可能是 2px,小姐姐可能是在边跳芭蕾边走路喽~

既然这样,60 帧的帧率下,设置 60px/s 就可以解决问题了,尝试了一下,真的可以!

总结

前端动画/游戏开发 requestAnimationFrame 之 锁帧 这篇文章介绍过,在项目中我们可能对动画进行锁帧,帧率可能是 60 或者 30,如果我们想保证渲染不抖动,在匀速直线运动中,我们尽量保证我们设置的速度要是帧率的倍数,或者保证平均每帧移动的像素点是一样的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值