美文网首页
Phaser动画原理

Phaser动画原理

作者: 雨中月 | 来源:发表于2018-05-19 18:07 被阅读0次

    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动画原理

          本文链接:https://www.haomeiwen.com/subject/xbviqftx.html