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

HTML5 2D 游戏开发 碰撞检测和 sprite 动画(3)选择碰撞检测的候选 sprite

HTML5 2D 游戏开发 碰撞检测和 sprite 动画(3)选择碰撞检测的候选 sprite

选择碰撞检测的候选 spriteSnail Bait sprite 在满足一下条件时有资格与跑步小人 sprite 碰撞:
  • 该 sprite 不是跑步小人
  • 该 sprite 和跑步小人均可见
  • 该 sprite 或跑步小人均未爆炸
collideBehavior 对象的 isCandidateForCollision() 方法(如 清单 3 中所示)会实现此逻辑。
清单 3. 选择碰撞检测的候选 sprite:isCandidateForCollision()
1
2
3
4
5
6
7
8
9
   var SnailBait =  function () {
   ...
   isCandidateForCollision: function (sprite, otherSprite) {
      return sprite !== otherSprite &&                       // not same
             sprite.visible && otherSprite.visible &&        // visible
             !sprite.exploding && !otherSprite.exploding;    // not exploding
   },
   ...
};




接下来,我们将查看如何检测合格 sprite 之间的碰撞。
检测跑步小人与另一个 sprite 之间的碰撞collideBehavior 对象的 didCollide() 方法确定跑步小人是否已与另一个 sprite 碰撞,如 清单 4 所示。
清单 4. 检查碰撞:didCollide()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var SnailBait =  function () {
...
didCollide: function (sprite,      // runner
                       otherSprite, // candidate for collision
                       context) {   // for context.isPointInPath()
   var left = sprite.left + sprite.offset,
       right = sprite.left + sprite.offset + sprite.width,
       top = sprite.top,
       bottom = sprite.top + sprite.height,
       centerX = left + sprite.width/2,
       centerY = sprite.top + sprite.height/2;

   // All the preceding variables -- left, right, etc. -- pertain to the runner sprite.

   if (otherSprite.type !== 'snail bomb') {
      return this.didRunnerCollideWithOtherSprite(left, top, right, bottom,
                                                      centerX, centerY,
                                                      otherSprite, context);
   }
   else {
      return this.didSnailBombCollideWithRunner(left, top, right, bottom,
                                                    otherSprite, context);
   }
},




didCollide() 方法计算跑步小人的边界框和它的中心,依据另一个 sprite 的身份,二者随后都传递给两个方法中的一个方法。
如果另一个 sprite 不是蜗牛炸弹,那么 didCollide() 会调用 didRunnerCollideWithOtherSprite(),如 清单 5 所示:
清单 5. didRunnerCollideWithOtherSprite()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    didRunnerCollideWithOtherSprite: function (left, top, right, bottom,
                                              centerX, centerY,
                                              otherSprite, context) {
   // Determine if either of the runner's four corners or its
   // center lies within the other sprite's bounding box.

context.beginPath();
context.rect(otherSprite.left - otherSprite.offset, otherSprite.top,
                otherSprite.width, otherSprite.height);
         
   return context.isPointInPath(left,    top)     ||
          context.isPointInPath(right,   top)     ||

          context.isPointInPath(centerX, centerY) ||

          context.isPointInPath(left,    bottom)  ||
          context.isPointInPath(right,   bottom);
},




如果给定了跑步小人的边界框和它的中心坐标,那么 didRunnerCollideWithOtherSprite() 会检查一个边界框的角或它的中心是否位于另一个 sprite 的边界框内。
Canvas 上下文的功能不仅是绘制图形 Canvas 上下文的 isPointInPath() 方法检测一个点是否在当前路径中。Snail Bait 使用它确定某个点是否位于矩形内。但是,当路径是一个不规则形状时,isPointInPath() 才会真正发挥其巨大作用。通过手工计算来确定某个点是否位于不规则形状内非常困难。

确定某个点是否位于一个矩形内,这不需要大量数学敏锐力;但是,HTML5 canvas 元素的 2D 上下文通过 isPointInPath() 方法进一步简化了该操作,如果某个点位于 canvas 上下文的当前路径中,那么该方法将会返回 true。
didRunnerCollideWithOtherSprite() 方法通过调用 beginPath() 和 rect() 创建了一个矩形路径来表示另一个 sprite 的边界框。didRunnerCollideWithOtherSprite() 方法随后调用 isPointInPath() 来确定跑步小人内的 5 个点中是否有 1 个点位于另一个 sprite 的边界框内。
didRunnerCollideWithOtherSprite() 方法能正确识别跑步小人与其他所有 sprite 之间的碰撞,除了蜗牛炸弹之外,如 图 6 中所示。
图 6. 跑步小人和蜗牛炸弹它不适用于蜗牛炸弹,因为蜗牛炸弹非常小,它可穿过跑步小人,而且跑步小人的边界框的任何角或中心都不会与炸弹接触。由于跑步小人大小与炸弹大小的比例不当,当另一个 sprite 是炸弹时, 中的 didCollide() 方法会调用 didSnailBombCollideWithRunner(),如 清单 6 中所示。
清单 6. didSnailBombCollideWithRunner() 方法
1
2
3
4
5
6
7
8
9
10
11
12
   didSnailBombCollideWithRunner : function (left, top, right, bottom,
                                             snailBomb, context) {
   // Determine if the center of the snail bomb lies within
   // the runner's bounding box  

   context.beginPath();
   context.rect(left, top, right - left, bottom - top); // runner's bounding box

   return context.isPointInPath(
                 snailBomb.left - snailBomb.offset + snailBomb.width/2,
                 snailBomb.top + snailBomb.height/2);
},




didSnailBombCollideWithRunner() 方法与 didRunnerCollideWithOtherSprite() 相反:didRunnerCollideWithOtherSprite() 检查跑步小人中的点是否在另一个 sprite 内,而 didSnailBombCollideWithRunner() 检查另一个 sprite(炸弹)的中心是否在跑步小人内。
您已经了解了如何使用边界框实现碰撞检测,但该技术可以更加准确且更有效地执行。在以下各节中,将介绍如何通过修改跑步小人的边界框和分割游戏的空间,细化 Snail Bait 的碰撞检测。
返回列表