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

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 的碰撞检测。 |
|
|
|
|
|