1.动画原理
动画是根据人的视觉停留,屏幕每秒N次画面渲染来达到快速画面切换的效果,如果每秒渲染的次数N大于人体所能感知视觉停留的速度,人就可以感觉画面在平滑的移动,就是动画效果,如果次数N太小,就会有卡顿的感觉,不同的显示器每秒渲染次数不一致,也就是帧率,可通过右键->显示设置->显示适配器属性->监视器来查看帧率,一般电脑显示器为60帧。人体视觉暂留时间一般0.1s-0.4s,按照60帧计算,大约16.7ms屏幕刷新一次,大大超出了人体感知的范围。
用代码实现查看本机的帧率
2.实现动画的方式
2.1 setTimeout
根据动画原理,我可以用setTimeout来不断改变图像的位置,达到动画的效果
var point=0;
function animation(){
point+=1;
setTimeout(Math.floor(1000/60),animation)
}
2.2 window.requestAnimationFrame
var vendors = [
'ms',
'moz',
'webkit',
'o'
];
for(var i=0;i
window.requestAnimationFrame = window[vendors[i] + 'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[i] + 'CancelAnimationFrame'] || window[vendors[i] + 'CancelRequestAnimationFrame'];
}
var point=0;
function animation(){
point+=1;
window.requestAnimationFrame(animation)
}
3.对比setTimout和window.requestAnimationFrame
setTimout是固定时间进行渲染,如上代码中是固定是一秒60次渲染,那问题来了,假设显示器帧率为50,也是就是20ms刷新一次,由时间线来说明
![image]("https://github.com/wangybg/Phaser/blob/master/src/img/%E6%97%B6%E9%97%B4%E8%BD%B4.png");
如图示,60s到80s的时间内setTimeout执行了两侧,但是屏幕渲染只有渲染了一次,中间这一次不但造成cpu和内存资源浪费,而且因为一次渲染移动了两个单位,会出现跳帧的情况。而且在页面未激活的状态下setTimeout也会继续执行,而这种执行相对动画来说没有意义。
window.requestAnimationFrame是根据显示器的帧率来动态的调整,由系统来决定什么时候执行callback,保证在屏幕刷新前callback只会被执行一次,并且在页面未激活的情况下会暂停渲染,这样既保证性能也不会丢帧。
综上所述,从cpu资源或者节流防抖的角度出发,尽量使用window.requestAnimationFrame来进行动画处理。
4.处理window.requestAnimationFrame兼容性的问题,可使用如下方式代替
var vendors = [
'ms',
'moz',
'webkit',
'o'
];
for(var i=0;i
window.requestAnimationFrame = window[vendors[i] + 'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[i] + 'CancelAnimationFrame'] || window[vendors[i] + 'CancelRequestAnimationFrame'];
}
if(!window.requestAnimationFrame){
var lastTime = 0;
window.requestAnimationFrame = function(callback) {
var currTime = new Date().getTime();
//如果timeToCall=0,按照浏览器规定setTimeout最小时间我4ms,所以为零时实际上为4ms
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame){
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
}
}
}
5.Phaser动画更新原理
game的时间线
game.raf= new Phaser.RequestAnimationFrame(game, forceSetTimeOut)
if(game.cahe.isReady){
raf.start();
}
raf.start=function(){
if (!window.requestAnimationFrame || this.forceSetTimeOut)
{
this._isSetTimeOut = true;
this._onLoop = function () {
return _this.updateSetTimeout();
};
this._timeOutID = window.setTimeout(this._onLoop, 0);
}
else
{
this._isSetTimeOut = false;
this._onLoop = function (time) {
return _this.updateRAF(time);
};
this._timeOutID = window.requestAnimationFrame(this._onLoop);
}
}
raf.updateRAF()=function(){
if (this.isRunning)
{
this.game.update(Math.floor(rafTime));
this._timeOutID = window.requestAnimationFrame(this._onLoop);
}
}
//由上述代码中可以看出,按照帧率调用game.update(time),time为每帧播放的时间,由系统确定
game.time=new Phaser.Time()
game.update=function(time){
//更新time
game.time.update(time)=function(){
//更新事件
game.time.events.update(time)
}
}
game.time.events=new Phaser.Timer(game,false);
//轮询调用Timers中得events函数
game.time.events.update=function(){
if (event.loop === true)
{
event.tick = this._newTick;
event.callback.apply(event.callbackContext, event.args);
}
else if (event.repeatCount > 0)
{
event.repeatCount--;
event.tick = this._newTick;
event.callback.apply(event.callbackContext, event.args);
}
else
{
this._marked++;
event.pendingDelete = true;
event.callback.apply(event.callbackContext, event.args);
}
}
网友评论