当前位置: 首页 > 文档资料 > HTML5 Canvas 实战 >

5.1 创建Animation类

优质
小牛编辑
130浏览
2023-12-01

由于HTML5的画布API未提供支持动画的方法,我们不得不创建我们自己的Animation类来操作动画。本节,我们将介绍动画的基础,并创建一个Animation类,该类适用于本书后面所有的动画项目。

准备工作

由于浏览器和计算机硬件条件并非完全相同,所以根据浏览器、计算机硬件、及动画算法的不同,每个动画的最佳FPS(Frames Per Second)的值也会不同,理解这点很重要。因此,开发者很难计算出每个用户的最佳FPS。幸运的是,浏览器会调用window对象的requestAnimationFrame方法,可以自动确定动画的最佳FPS(谢天谢地!)。本章后面我们将会看到,对一个平滑的动画,FPS的值一般是40到60之间的某个值。

动画基本原理
图5-1 动画基本原理

请看上图。要创建动画,我们首先需要初始化舞台上的对象。我们可以把画布看做“舞台”,因为我们把画布上可以运动的对象,看做在舞台上表演的“演员”。而且,舞台提供类似这样的感觉,就是画布上的东西是突然出现的,而不是静静呆在那里的。一旦对象初始化完成,我们就可以启动一个动画循环,来更新舞台,清除画布,重绘舞台,再请求下一个新的动画帧。

由于这些特性可以定义任何类型的动画,我们可以创建一个Animation类,由这个类在幕后处理这些过程,这对我们很有意义。

操作步骤

按照以下步骤,来创建一个Animation类,该类将适用于本章的所有动画实例:

1. 定义Animation构造函数,并创建跨浏览器的requestAnimationFrame方法:

var Animation = function(canvasId) {
  this.canvas  = document.getElementById(canvasId); 
  this.context = this.canvas.getContext("2d"); 
  this.t  =  0;
  this.timeInterval  =  0; 
  this.startTime  =  0; 
  this.lastTime  =  0; 
  this.frame  =  0;
  this.animating  = false;
  // 由Paul Irish提供
  window.requestAnimFrame  =  (function(callback){
      return window.requestAnimationFrame  ||
      window.webkitRequestAnimationFrame  ||
      window.mozRequestAnimationFrame  ||
      window.oRequestAnimationFrame  ||
      window.msRequestAnimationFrame  ||
      function(callback){
        window.setTimeout(callback,  1000  /  60);
      };
  })();
};

2. 定义getContext()方法:

Animation.prototype.getContext  = function(){
  return this.context;
};

3. 定义getCanvas()方法:

Animation.prototype.getCanvas  = function(){
  return this.canvas;
};

4. 定义clear()方法,用于清除画布:

 Animation.prototype.clear  = function(){
  this.context.clearRect(0,  0, this.canvas.width, this.canvas. height);
};

5. 定义setStage()方法,用于设置stage()函数。该函数在每个动画帧都会执行:

Animation.prototype.setStage  = function(func){
    this.stage  = func;
};

6. 定义isAnimating()方法:

Animation.prototype.isAnimating  = function(){
    return this.animating;
};

7. 定义getFrame()方法,用于返回帧号:

 Animation.prototype.getFrame  = function(){
   return this.frame;
};

8. 定义start()方法,用于启动动画:

Animation.prototype.start  = function(){
   this.animating  = true;
  var date  = new Date();
  this.startTime  = date.getTime();
  this.lastTime  = this.startTime;
  if  (this.stage  !== undefined)  {
     this.stage();
  }
  this.animationLoop();
};

9. 定义stop()方法,用于停止动画:

Animation.prototype.stop  = function(){
   this.animating  = false;
};

10. 定义getTimeInterval()方法,用于返回上一帧和当前帧间隔的毫秒数:

Animation.prototype.getTimeInterval  = function(){
    return this.timeInterval;
};

11. 定义getTime()方法,用于返回动画已经运行的毫秒数:

Animation.prototype.getTime  = function(){
    return this.t;
};

12. 定义getFps()方法,用于返回动画的当前FPS:

Animation.prototype.getFps  = function(){
  return this.timeInterval  >  0  ?  1000  / this.timeInterval  :  0;
};

13. 定义animationLoop()方法,用于处理动画循环:

 Animation.prototype.animationLoop  = function(){
  var that  = this;
  this.frame++;
  var date  = new Date();
  var thisTime  = date.getTime();
  this.timeInterval  = thisTime  - this.lastTime;
  this.t  += this.timeInterval;
  this.lastTime  = thisTime;
  if  (this.stage  !== undefined)  {
       this.stage();
  }
  if  (this.animating)  {
    requestAnimFrame(function(){
      that.animationLoop();
    });
  }
};

工作原理

Animation类的思想是,通过封装和隐藏动画所需要的所有逻辑,如提供帧间隔、处理动画循环、清除画布等,来简化我们的动画项目。

Animation类的关键在其构造函数中,我们在构造函数中设置了window对象的requestAnimFrame方法,该方法看做是requestAnimationFrame方法的跨浏览器实现,requestAnimationFrame方法允许用户浏览器来决定动画的最佳FPS。FPS完全是动态的,并在整个动画过程中会发生变化。

我们的Animation类也提供了一些方便易用的方法,如getTimeInterval()用于返回上一帧和当前帧间隔的毫秒数,getTime()方法用于返回动画已经运行的毫秒数,stop()方法用于停止动画,clear()方法用于清除画布。

由于我们在第一时间准备好了可以工作的Animation类,本章其余的动画,及将来的动画项目,都将是小菜一碟。