roadProgram的专栏

一个程序员的路

转 第九章 碰撞检测(as3.0)

  到目前为止,我们已经学习了物体在其空间的内交互运动。接下来研究一下物体之间的
交互运动。这就需要确定物体间何时发生了碰撞,这就是我们所讲的碰撞检测(Collision
detection 或 Hit testing)。
    本章我会尽量将所有需要掌握的相关知识告诉大家。其中包括两个影片的碰撞,影片与
点之间的碰撞,用距离检测碰撞以及多物体碰撞检测方法。首先,来看一下有什么现成的碰
撞检测方法。

碰撞检测方法
    碰撞检测的思想非常非常简单。我们只要知道两个物体是否有在同一时间内某个部分处
在了同一位置上。当然,也许物体不只两个,这就需要知道其中的一个是否和其它的物体发
是了碰撞。
    如本节的题目,检测碰撞的方法有很多:可以是对物体实际像素的检测(Sprite 或
MovieClip),也就是判断两个影片中的图形是否重叠?对于这种检测方法,要以影片内图
形的实际可见像素判断,还是以影片的矩形边界来判断呢?这就涉及到 hitTest 方法中内
置的两个可选项,用来满足不同方面的需求。
    碰撞也可以根据距离来判断。获得两个物体间的距离,然后问“物体间是否近得足够发
生碰撞了?”,应用这种方法时需要计算并判断距离。
    每种方法都有它们各自的用途。具体实现会在本章进行讲解。至于发生碰撞后该做些什
么,本章并不涉及。因为,这些内容我们会在第十一章介绍动量守恒时详细地为大家讲解。


hitTestObject 与 hitTestPoint
    早先 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 所示。

转 <wbr>第九章 <wbr>碰撞检测(as3.0)

图 9-1 矩形边界
    当然,在 Flash 播放器中,并非先画上一个矩形再进行判断。一切都是根据影片的位
置和大小计算出来的。
    为什么这种方法不精确?因为,一旦两个矩形边界相交,则必然会产生碰撞。下面请见
图 9-2,这几对图形中,哪两个相交了?


转 <wbr>第九章 <wbr>碰撞检测(as3.0)

 

图 9-2 哪一对相交了?
    很明显,只有那两个正方形碰到了,对吧?好的,下面为它们画上矩形边界,再从 Flash
的视角观察一下。结果如图 9-3 所示。


转 <wbr>第九章 <wbr>碰撞检测(as3.0)

图 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;
     h = height;
     this.color = color;
     init();
   }
   public function init():void {
     graphics.beginFill(color);
     graphics.drawRect(-w / 2, -h / 2, w, h);
     graphics.endFill();
   }
  }
}
      设计思想是, box 从屏幕上方落到下。 box 落到舞台底部或其它 box 上时,就算放
置好了。下面是代码(文档类 Boxes.as):
package {
  import flash.display.Sprite;
  import flash.events.Event;
  public class  Boxes extends Sprite {
   private var  box:Box;
   private var  boxes:Array;
   private var  gravity:Number = 0.2;
   public function Boxes() {
     init();
   }
   private function init():void {
     boxes = new Array();
     createBox();
     addEventListener(Event.ENTER_FRAME, onEnterFrame);
   }
   private function onEnterFrame(event:Event):void {
     box.vy += gravity;
     box.y += box.vy;
     if (box.y + box.height / 2 > stage.stageHeight) {
      box.y = stage.stageHeight - box.height / 2;
      createBox();
     }
     for (var i:uint = 0; i < boxes.length; i++) {
      if (box != boxes[i] && box.hitTestObject(boxes[i])) {
        box.y = boxes[i].y - boxes[i].height / 2 - box.height / 2;
        createBox();
      }
     }
   }
   private function createBox():void {
     box = new Box(Math.random() * 40 + 10, Math.random() * 40 + 10);
     box.x = Math.random() * stage.stageWidth;
    

阅读更多
个人分类: Flash Flex
想对作者说点什么? 我来说一句

AS3.0简单的弹球flash

2011年12月26日 12KB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭