返回“Flash基础理论课 - 目录”
距离碰撞检测
本节开始,我们就摆脱了内置hitTest方法,而是将碰撞检测掌握在自己手里。这就要用两个物体间的距离来判断碰撞的发生。
举个现实中的例子,如果你那辆车与我这辆车有100米的距离,我们就知道这两辆车离得足够远,不可能发生碰撞。然而,如果我们的车都有6米宽和12米长,而我这辆车的中心点与你那辆车的中心点只有5米,那么肯定会有些金属被撞弯,保险单会变长。换句话讲,除非车子的某些部分被撞掉以外,两辆车不可能并到一起。这就是整个距离碰撞检测的思想。我们要确认使两个物体分开的最小距离,再看看当前距离,比较两者的大小。如果当前距离小于最小距离,就知道物体间发生了碰撞。
hitTestObject方法在矩形上使用效果最好,但在处理其它图形时就退化了,而我们这种方法则在处理圆形时效果最好。要是处理的图形与圆形有偏差,则精确度就会有所降低。但是这里会遇到与 hitTest 中矩形边界相反的问题:明明发生了碰撞,确没有响应,这是因为它们的中心点还不够近。
简单的距离碰撞检测
让我们从最理想的状态开始:两个圆形。依然可以使用Ball类。(大家现在也许明白了为什么“重用”一词通常与面向对象编程联系在一起了吧。)
在应用距离碰撞检测时,圆的注册点应该在中心点上,Ball类正好符合要求。先要创建两个小球,并设置其中一个为可拖拽的。然后在 enterFrame函数中进行碰撞检测。到这儿为止,程序与本章的第一个例子相同。只是在判断碰撞时,不是使用if(ball1.hitTestObject(ball2)),而是在 if 语句中判断距离。我们已经学习了计算两个物体间距离的方法,回忆一下第三章的勾股定理。所以,程序开始应该是这样的:
var dx:Number = sprite2.x - sprite1.x;
var dy:Number = sprite2.y - sprite1.y;
var dist:Number = Math.sqrt(dx * dx + dy * dy);
OK,现在距离已经有了,如何进行判断呢?请看图 9-4。
图9-4 碰撞的距离
图中我们看到两个影片发生了碰撞,每个影片都占 60 像素宽,那么每个半径就是30。因此,在它们相互碰撞时,实际相差 60 个像素。啊哈!这就是答案。对于两个大小相同的圆来说,如果距离小于直径,就会产生碰撞。本例代码(Distance.as)与 ObjectHisTest.as 非常相似,设置onEnterFrame方法为:
private function onEnterFrame(event:Event):void {
var dx:Number = ball2.x - ball1.x;
var dy:Number = ball2.y - ball1.y;
var dist:Number = Math.sqrt(dx * dx + dy * dy);
// 默认 ball 的直径为 80 (半径为 40)
if (dist < 80) {
trace("hit");
}
}
测试后,我们发现这回碰撞的结果与接近小球的角度无关。在没有接触到目标球时不会产生碰撞。但是在代码中使用数值表示距离显然不太合适,因为这样的话每次改变 ball 的大小都要重新修改代码。况且,如果两个小球的大小不同怎么办?我们需要将这个方法抽象成可以适应任何情况的公式。
如图 9-5 所示。两个大小不同的ball,相互碰撞。左边的小球 60 像素,右边的40 像素。我们可以用程序检察它们的width 属性。第一个ball 的半径为 30,另一个半径为 20。所以,它们碰撞时的距离实际应为 50。在 Ball类里面,已经设置了半径(radius)属性,可以直接拿来判断。
图9-5 两个不同体积物体的碰撞距离