Phaser动画原理

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);

            }

}

你可能感兴趣的:(Phaser动画原理)