首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

HTML5 2D 游戏开发 碰撞检测和 sprite 动画(6)监视碰撞检测性能

HTML5 2D 游戏开发 碰撞检测和 sprite 动画(6)监视碰撞检测性能

监视碰撞检测性能90% 空闲?图 10 中所示的表中最顶部的条目表示,Snail Bait 在 90% 的时间里都处于空闲状态。Snail Bait 拥有如此优秀的性能是因为,图 10 中的配置文件源自 Chrome 浏览器(26 版,它像所有现代浏览器一样)对 canvas 元素进行了硬件加速。浏览器供应商通常通过将针对 Canvas API 的调用转换为 WebGL 来实现对 canvas 元素的加速,所以可以同时获得 Canvas API 的便捷性和 WebGL 的高性能。

碰撞检测很容易成为性能瓶颈,尤其是对于数学计算更加密集的碰撞检测算法,比如分离轴定理。本文介绍了一些可用来提高性能的简单技术,比如细化边界框和空间分割。但不断监视游戏的性能也是一个不错的想法,这样您就可以在出现性能问题后尽快发现和修复它们。
所有现代浏览器都附带了复杂的开发环境;例如,Chrome、Safari、Firefox、Internet Explorer 和 Opera 都允许您分析正在运行的代码。图 10 显示了 Chrome 的探查器,该探查器描绘了您在各个方法中花费的时间与总时间的相对比例。
图 10. 碰撞检测性能在   中可以看到,Snail Bait 的 didCollide() 方法仅花了游戏时间的 0.05%。(Self 列的 didCollide() 值为 0.01%,只表示直接花费在一个方法中的时间,不包括花费在该方法调用的方法中的时间。)
当跑步小人与坏东西碰撞时,就会发生爆炸。接下来看看如何实现该爆炸。
Sprite 动画图 11(从上到下)演示了在跑步小人遇到坏东西(比如一只蜜蜂)时,Snail Bait 显示的爆炸动画。
图 11. 跑步小人在一次碰撞后爆炸Snail Bait 使用 sprite 动画生成器 实现 sprite 动画,如   中所示的动画。sprite 动画生成器更改一个 sprite 的一段被指定持续时间绘制的单元。例如,爆炸 sprite 动画生成器在 500 毫秒内将跑步小人的动画单元更改为 图 12 中所示的单元。
图 12. 来自 Snail Bait 的 spritesheet 的爆炸单元sprite 动画生成器对象的构造函数如 清单 12 中所示。
清单 12. Sprite 动画生成器构造函数
1
2
3
4
5
6
7
// Sprite Animators...........................................................

var SpriteAnimator = function (cells, duration, callback) {
   this.cells = cells;
   this.duration = duration || 1000;
   this.callback = callback;
};




SpriteAnimator 构造函数接受 3 个参数。第一个参数是 Snail Bait 的 spritesheet 中的一个边界框数组;这些边界框是临时动画单元,该参数是强制性的。第二和第三个参数是可选的。第二个参数是动画持续时间,第三个参数是一个回调函数,在超过动画持续时间时,sprite 动画生成器会调用该函数。
SpriteAnimator 方法在对象的原型中定义,如 清单 13 中所示。
清单 13. Sprite 动画生成器方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SpriteAnimator.prototype = {
   start: function (sprite, reappear) {
      var originalCells = sprite.artist.cells,
          originalIndex = sprite.artist.cellIndex,
          self = this;

      sprite.artist.cells = this.cells;
      sprite.artist.cellIndex = 0;
      
      setTimeout(function() {
         sprite.artist.cells = originalCells;
         sprite.artist.cellIndex = originalIndex;

         sprite.visible = reappear;

         if (self.callback) {
            self.callback(sprite, self);
         }
      }, self.duration);
   },
};




SpriteAnimator 的 start() 方法会启动动画,保存原始动画单元和指向当前单元的索引,分别将它们替换为临时单元和 0。然后,在动画持续时间过去后,start() 方法将 sprite 的动画单元和原始索引恢复到动画发生之前的状态。
清单 14 显示了 Snail Bait 如何使用一个 sprite 动画生成器让跑步小人爆炸。
清单 14. 创建爆炸动画生成器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
var SnailBait =  function () {
   this.canvas = document.getElementById('game-canvas'),
   this.context = this.canvas.getContext('2d'),
   ...

   this.RUN_ANIMATION_RATE = 17,     // frames/second
   this.EXPLOSION_CELLS_HEIGHT = 62, // pixels
   this.EXPLOSION_DURATION = 500,    // milliseconds

   this.explosionCells = [
      { left: 1,   top: 48, width: 50, height: this.EXPLOSION_CELLS_HEIGHT },
      { left: 60,  top: 48, width: 68, height: this.EXPLOSION_CELLS_HEIGHT },
      { left: 143, top: 48, width: 68, height: this.EXPLOSION_CELLS_HEIGHT },
      { left: 230, top: 48, width: 68, height: this.EXPLOSION_CELLS_HEIGHT },
      { left: 305, top: 48, width: 68, height: this.EXPLOSION_CELLS_HEIGHT },
      { left: 389, top: 48, width: 68, height: this.EXPLOSION_CELLS_HEIGHT },
      { left: 470, top: 48, width: 68, height: this.EXPLOSION_CELLS_HEIGHT }
   ],
   ...

   this.explosionAnimator = new SpriteAnimator(
      this.explosionCells,          // Animation cells
      this.EXPLOSION_DURATION,      // Duration of the explosion

      function (sprite, animator) { // Callback after animation
         sprite.exploding = false;

         if (sprite.jumping) {
            sprite.stopJumping();
         }
         else if (sprite.falling) {
            sprite.stopFalling();
         }

         sprite.visible = true;
         sprite.track = 1;
         sprite.top = snailBait.calculatePlatformTop(sprite.track) - sprite.height;
         sprite.artist.cellIndex = 0;
         sprite.runAnimationRate = snailBait.RUN_ANIMATION_RATE;
      }
   );
};




Snail Bait 使用   中所示的动画调用创建了一个 sprite 动画生成器。该动画的持续时间为 500ms,在结束爆炸时,sprite 动画生成器调用爆炸动画生成器的回调函数,后者将跑步小人放在最底层的平台堆栈上。不幸的是,在以后的一篇文章中,我们将重新实现这个回调函数,减去一条命并重新启动当前级别。
清单 15 显示了跑步小人的 explode() 方法(有点虎头蛇尾)。
清单 15. Snail Bait 的 explode() 方法
1
2
3
4
5
6
7
8
9
10
11
12
13
SnailBait.prototype = {
   ...

   explode: function (sprite, silent) {
      if (sprite.runAnimationRate === 0) {
         sprite.runAnimationRate = this.RUN_ANIMATION_RATE;
      }
               
      sprite.exploding = true;

      this.explosionAnimator.start(sprite, true);  // true means sprite reappears
   },
};




当跑步小人跳跃时,没有动画效果,因为她的动画速率为 0。explode() 方法将她的动画速率设置为标准值,以便她能够以动画形式进入爆炸单元。然后,explode() 方法将跑步小人的 exploding() 属性设置为 true 并启动爆炸动画生成器。
返回列表