轉 第九章 碰撞檢測(as3.0)

來源:互聯網
上載者:User

  到目前為止,我們已經學習了物體在其空間的內互動運動。接下來研究一下物體之間的
互動運動。這就需要確定物體間何時發生了碰撞,這就是我們所講的碰撞檢測(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 所示。

圖 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;
     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);
   

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.