早先 Flash 中的影片剪辑都有内置 hitTest 方法,这个方法有很多种用途。而现在已
经将它划分为两种方法,这样做更加合理。hitTestObject 方法用于判断两个显示对象间是
否发生了碰撞,而 hitTestPoint 方法用于判断某个点与显示对象间是否发生了碰撞。
碰撞检测两个影片
使用 hitTestObject 判断两个影片是否碰撞也许是最简单的碰撞检测方法。调用这个
函数作为影片的方法,将另一个影片的引用作为参数传入。注意,虽然我说的是影片,但这
两种方法都是 DisplayObject 类的成员,对于所有继承自显示对象类的子类, MovieClip,
如
Bitmap, Video, TextField 等都可以使用。格式如下:
sprite1.hitTestObject(sprite2)
通常于在 if 语句中使用:
if(sprite1.hitTestObject(sprite2)) {
// 碰撞后的动作
}
如果两个影片发生了碰撞则返回 true,并执行 if 语句块的内容。一切事物都是把双
刃剑。碰撞检测方法越简单,其精确度就越低;相反,检测的精确度越高,则实现起来就越
复杂。因此,这个最简单的方法,精确度也是最差的。
那么在碰撞检测中精确度意味着什么呢?不就是判断两个物体有没有冲突吗?我也希
望问题只有这么简单。
回过头来看问题:知道两个影片的位置,如何判断它们是否碰撞?最简单的判断方法是
这样执行的:拿来一个物体,绕着它画一个矩形。再复制出一个相同的影片,两个之间进行
碰撞检测。最后判断两个矩形之间是否有相交的地方。如果有,则发生碰撞。用矩形包围物
体就是我们所熟知的矩形边界(bounding box)。当我们在 Flash IDE 中点击一个舞台元
件时,就会看到一圈蓝色的轮廓线,如图 9-1 所示。
图 9-1 矩形边界
当然,在 Flash 播放器中,并非先画上一个矩形再进行判断。一切都是根据影片的位
置和大小计算出来的。
为什么这种方法不精确?因为,一旦两个矩形边界相交,则必然会产生碰撞。下面请见
图 9-2,这几对图形中,哪两个相交了?
图 9-2 哪一对相交了?
很明显,只有那两个正方形碰到了,对吧?好的,下面为它们画上矩形边界,再从 Flash
的视角观察一下。结果如图 9-3 所示。
图 9-3 并非我们希望的结果
对于 Flash 来说,每对图形是相交的。大家不相信的话,请看下面这个文档类
ObjectHitTest.as,用到了我们前面创建的 Ball 类,请确认这个类存在于类路径中:
package {
import flash.display.Sprite;
import flash.events.Event;
public class ObjectHitTest extends Sprite {
private var ball1:Ball;
private var ball2:Ball;
public function ObjectHitTest() {
init();
}
private function init():void {
ball1 = new Ball();
addChild(ball1);
ball1.x = stage.stageWidth / 2;
ball1.y = stage.stageHeight / 2;
ball2 = new Ball();
addChild(ball2);
ball2.startDrag(true);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(event:Event):void {
if (ball1.hitTestObject(ball2)) {
trace("hit");
}
}
}
}
本例创建了两个 Ball 类的实例,并将其中一个设置为可拖拽的。在每帧中使用
hitTestObject 方法判断两个影片是否发生了碰撞。注意,当我们从上,下,左,右靠近目
标时,结果都是正确的。但是如果倾斜着靠近物体,就有问题了。当然,如果物体都是矩形
的话,不会有什么问题。但物体要是越不规则,那么结果就越不准确。所以,当发生碰撞的
物体不是矩形时,大家就要格外小心。
下面举一个使用 hitTestObject 判断矩形物体的例子。这里要用到一个崭新的 Box
类,与 Ball 类的非常相似,相信大家理解起来一定没有问题,代码如下:
package {
import flash.display.Sprite;
public class Box extends Sprite {
private var w:Number;
private var h:Number;
private var color:uint;
public var vx:Number = 0;
public var vy:Number = 0;
public function Box(width:Number=50,
height:Number=50,
color:uint=0xff0000) {
w = width;