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

5.11 增强画布并显示FPS值

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

看了上一节的例子后,你可能会想“微生物的数量是有限制的吗?”,对该问题直截了当的回答是“是”。由于HTML5的画布上下文没有硬件加速,并且我们的动画完全由JavaScript来驱动,如果长时间工作,肯定有这么一个点,当过了这个点,浏览器就会歇菜。为了说明这个,我们可以显示动画的FPS,并观察屏幕上微生物的数目和FPS之间的关系。

增强画布并显示FPS值
图5-11 增强画布并显示FPS值

操作步骤

按照以下步骤,为画布加压,并显示FPS的值:

1. 链接到Animation类:

<head>
<script src="animation.js"> </script>

2. 定义drawFps()函数,该函数把FPS的值绘制到画布的右上角:

function drawFps(anim, fps){
  var canvas  = anim.getCanvas();
  var context  = anim.getContext();
  context.fillStyle  = "black";
  context.fillRect(canvas.width  -  100,  0,  100,  30);
  context.font  = "18pt Calibri";
  context.fillStyle  = "white";
  context.fillText("fps: "  + fps.toFixed(1), canvas.width  -  93,  22);
}

3. 定义getRandColor()函数,该函数返回一个随机的颜色:

<script>
function getRandColor(){
  var colors  =  ["red", "orange", "yellow", "green",  "blue", "violet"];
  return colors[Math.floor(Math.random()  * colors.length)];
}

4. 定义getRandTheta()函数,该函数返回一个随机的角度:

function getRandTheta(){
  return Math.random()  *  2  * Math.PI;
}

5. 定义updateMicrobes()函数,该函数使用随机产生的角度为每个微生物添加一个新的头段,再把去掉其尾段来更新microbe对象:

function updateMicrobes(anim, microbes){
  var canvas  = anim.getCanvas();
  var angleVariance  =  0.2;
  for  (var i  =  0; i  < microbes.length; i++)  {
    var microbe  = microbes[i];
    var angles  = microbe.angles;
    /*
    * good numNewSegmentsPerFrame values: *  60fps  ->  1
    *  10fps  ->  10
    *
    * for a linear relationship, we can use the
    equation:
    * n  = mf  + b, where n  = numNewSegmentsPerFrame and f
    = FPS
    * solving for m and b, we have: * n  =  (-0.18)f  +  11.8
    */
    var numNewSegmentsPerFrame  = Math.round(-0.18  *  anim.getFps()  +  11.8);
    for  (var n  =  0; n  < numNewSegmentsPerFrame; n++)  {
      // create first angle if no angles
      if  (angles.length  ==  0)  {
        microbe.headX  = canvas.width  /  2;
        microbe.headY  = canvas.height  /  2;
        angles.push(getRandTheta());
      }
      var headX  = microbe.headX;
      var headY  = microbe.headY;
      var headAngle  = angles[angles.length  -  1];
      // create new head angle
      var dist  = anim.getTimeInterval()  /  (10  *  numNewSegmentsPerFrame);
      // increase new head angle by an amount equal  to
      //  -0.1 to  0.1
      var newHeadAngle  = headAngle  +  ((angleVariance /  2)  - Math.random()  * angleVariance);
      var newHeadX  = headX  + dist  * Math.cos(newHeadAngle);
      var newHeadY  = headY  + dist  * Math.sin(newHeadAngle);
      // change direction if collision occurs
      if  (newHeadX  >= canvas.width  || newHeadX  <=  0
       || newHeadY  >= canvas.height  || newHeadY  <=  0)  {
        newHeadAngle  += Math.PI  /  2;
        newHeadX  = headX  + dist  * Math.cos(newHeadAngle);
        newHeadY  = headY  + dist  * Math.sin(newHeadAngle);
      }
      microbe.headX  = newHeadX;
      microbe.headY  = newHeadY;
      angles.push(newHeadAngle);
      // remove tail angle
      if  (angles.length  >  20)  {
           angles.shift();
      }
    }
   }
}

6. 定义drawMicrobes()函数,该函数绘制所有微生物:

function drawMicrobes(anim, microbes){
  var segmentLength  =  2;  // px
  var context  = anim.getContext();
  for  (var i  =  0; i  < microbes.length; i++)  {
    var microbe  = microbes[i];
    var angles  = microbe.angles; context.beginPath();
    context.moveTo(microbe.headX, microbe.headY);
    var x  = microbe.headX;
    var y  = microbe.headY;
    // start with the head and end with the tail
    for  (var n  = angles.length  -  1; n  >=  0; n--)  {
      var angle  = angles[n];
      x  -= segmentLength  * Math.cos(angle); 
      y  -= segmentLength  * Math.sin(angle); 
      context.lineTo(x, y);
    }
    context.lineWidth  =  10;
    context.lineCap  = "round";
    context.lineJoin  = "round";
    context.strokeStyle  = microbe.color; 
    context.stroke();
  }
}

7. 实例化一个Animation对象,并得到画布上下文对象:

window.onload  = function(){
  var anim  = new Animation("myCanvas"); 
  var canvas  = anim.getCanvas();
  var context  = anim.getContext();

8. 初始化1,500个微生物:

  // init microbes
  var microbes  =  [];
  for  (var n  =  0; n  <  1500; n++)  {
    // each microbe will be an array of angles 
    microbes[n]  =  {
      headX:  0,
      headY:  0,
      angles:  [],
      color: getRandColor()
    };
  }

9. 设置stage()函数,该函数更新微生物,每10帧更新一次FPS的值,清除画布,然后绘制微生物和FPS的值:

  var fps  =  0;
  anim.setStage(function(){
  // update
  updateMicrobes(this, microbes);
  if  (anim.getFrame()  %  10  ==  0)  {
    fps  = anim.getFps();
  }
  // clear
  this.clear();
  // draw
  drawMicrobes(this, microbes); drawFps(this, fps);
});

10. 启动动画:

  anim.start();
};
</script>
</head>

11. 在HTML文档的body部分嵌入canvas标签:

<body>
<canvas id="myCanvas" width="600" height="250" style="border:1px solid black;">
</canvas>
</body>

工作原理

要绘制动画的FPS,我们可以创建drawFps()函数,该函数把FPS的值作为输入,在画布的右上角绘制一个黑色盒子,并在盒子里输出FPS的值。为了避免FPS更新太过频繁,我们可以把FPS的值保存到变量FPS中,并每10帧更新一次。用这种方法,FPS的值最多6秒钟更新一次。

要给画布增加压力,我们可以简单的初始化更多的微生物。本节,我们初始化了1,500个微生物。如果你自己试验本示例代码,你可以使用不同的值,看它如何影响FPS。

了解更多

前面已经提到,一般动画的运行速率应该在40到60 FPS之间。如果FPS降低到30,你将会注意到动画稍微有点滞后。当用Google Chrome在32位、2.2 GHzAMD处理器、2 GB内存(是的,我知道,我需要更新电脑了)的Windows 7机器上测试,观察1,500个微生物在5 FPS的情况。看上去还不是那么差,但不是非常好。当微生物数目增加到2,000或更多时,动画走走停停,让人无法接受。

我们在2D上下文中创建的几乎所有动画,在台式机和笔记本电脑上都表现良好。然而,如果你发现在计算非常复杂的情况下,2D上下文表现就不够好,你可能考虑使用WebGL来代替(我们将在第9章WebGL介绍中介绍WebGL)。与2D上下文不同,WebGL会使用硬件加速。然而,使用WebGL确实需要付出代价,因为开发和维护WebGL动画,要比创建2D动画难得多。

相关参考

  • 第1章 处理文本
  • 第1章 绘制弹簧
  • 第6章 创建绘图应用