Canvas上绘制动画
Canvas上绘制精灵图的一帧
我们知道我们需要调用drawImage 在画布上去绘制一个图片,那如果我们要绘制一个动图我们需要如何实现呢?我们要获取精灵图片对应的那一帧,然后在画布上绘制。每次绘制一帧,我们需要先清空原先画布上的内容
|
|
注意: sx,sy 是指源精灵图片获取的位置, dx,dy 指的是在画布上需要对应的位置,所以我们写一个Sprite 类,这个类一般要描述下面这些信息
|
|
我们再创建一个绘制画布类DrawCanvas, 主要需要两个方法,一个是renderFrame(绘制精灵的某帧), 一个是清空画布clear
|
|
结合上面两个类,我们就可以再画布上先绘制精灵图的第一帧
|
|
Canvas 上让精灵图动起来
我们需要绘制我们的精灵图,那么我们需要setInterval清空我们的画布,绘制对应帧数的图片。
|
|
注意:我们创建我们的sprite之前我们需要预先将我们使用的图片下载完,所以我们需要
|
|
所以在下一篇文章里我们会看到相关框架里面会实现preload,预先加载所有要使用的资源然后再开始绘制。以上,就是canvas动画主要的实现原理。如果想要我们的动画在不同方向上再进行移动,即我们只要不断更改我们绘制坐标位置即可。
拓展阅读里面提到我们对动画可以分层,让不同频率的动画绘制在不同的图层上,同时我们对这一次图层的变化与上一次图层的内容进行对比,找出变化的区域,这也是我们称为的脏区域,这样只要更新脏区域的内容,就能提升canvas的性能了。
RequestAnimationFrame 与setInterval setTimeout 区别
我们以前做动画的时候,都知道要动画流畅,需要让页面1s渲染60帧,所以我们的时间间隔会设置为1/60*1000 = 16 ms 。再后来看到的文章都指出,动画不要使用setInterval或者setTimeout 去实现我们想要的效果,而应该使用RAF,那RAF和setTimeout 与 setInterval的区别到底在哪里?
RequestAnimationFrame 与setInterval setTimeout 区别
setInterval和setTimeout 在非当前窗口,或者浏览器‘休眠’的时候,即使渲染停止了,但是计时器不会休息,仍然会顽强的跑着!这样会加大浏览器的负担影响页面性能。
第二个不同在于callback队列的不同:
我们假设这里有3个循环计数器的实现,A是利用RAF的递归调用做的,B是用setInterval + 16ms做的,C是用setTimeout + 16ms + 递归调用实现的。
然后用这3个计步器来做一个callback的循环调用。同时假设这个callback执行消耗的时间固定为100ms。
那么我们可以大致猜想一下 B在做这件事情的具体过程:
B从时间零点开始第一次执行callback,16ms之后发现应该执行第二次了,但是发现第一次还没做完,于是还是得继续第一次没做完的事情,把第二次callback排到自己的一个计划队列里面,等到第一次执行完了再执行队列里的第二次…
但是恶性循环,32ms之后,第一次的事情还没做完,第3次的任务又来了。。。
于是,这个任务队列越来越长,越来越长。。。
而对于A而言每一次任务的完成仍然需要100ms,但是浏览器不会在A没有完成当前任务的时候给它下一次的任务。也就是说A总是花100ms完成一次任务,然后再花100ms完成下一次任务。
结论:A完成10此任务的时间应该是1000ms,但是B和C完成10次任务的总时间应该需要>=1000ms,因为他们还要分心去管理他们的任务队列
关于FramePerSecond和deltaTime
- FPS: Frame Per Second 1s的帧数
- dt: Delta Time 1帧与1帧之间的时间间隔
- 结论: 理论上 1s/FPS = dt
|
|
- 通过FPS与dt可以用来反映动画的流畅程度,那对于程序而言dt 可以干什么呢?
程序里dt(deltaTime)的作用?
dt 在我们控制物体移动时有巨大的作用,举个例子:
假设我们在性能好的机器和性能差一些的机器上同时测试一个游戏。好的机器的FPS稳定在60,差的机器FPS稳定在30。
就像上面Canvas实现的bird动画里面,我们在每帧的update如果都给它的纵向移动距离+1
12 > bird.y +=1>
>
那么在性能好的机子上,1s可以达到60帧,60帧以后bird纵向距离移动了60;但是在差的机子上,1s可能只有30帧,30帧以后bird纵向距离移动了30,这显然并不科学!
所以我们只要
12 > bird.y += dt*60>
>
性能好的机子上dt = 1/60 性能差的机子上dt = 1/30 ,性能好的机子上每帧移动1,性能差的机子上每帧移动2,这样最后的位置是一致的