關於tink的碰撞檢測類【2】

來源:互聯網
上載者:User

分析演算法的思路:

 

Step1:假設stage(黑色)上有4個顯示對象red_mc,green_mc,blue_mc,yellow_mc,層級關係是stage>root>red_mc,stage>root>yellow_mc>blue_mc>green_mc。要檢測碰撞的對象是red_mc和green_mc。

                                  圖1

 

補充約定:為方便表述,這裡約定顯示對象的“初始狀態”為相對父級容器座標系未進行旋轉,縮放,即對象的transform.matrix對象是[a=1,b=0,c=0,d=1]。

 

Step2:一開始,圖1中的4個mc都處於初始狀態。但這樣的碰撞檢測不考驗演算法,因此對它們做縮放,旋轉,平移處理(我直接在flashIDE裡完成的),使得red_mc和green_mc的空間位置足夠複雜。

                                   圖2
補充知識:draw()方法的一個細節

  如下代碼(文檔類):
   varbmd1:BitmapData = new BitmapData(150,150);
   bmd1.draw(red_mc);
   varbmp1:Bitmap = new Bitmap(bmd1);
   this.addChild(bmp1);

  若red_mc處於初始狀態(即圖1中的red_mc),效果如下:

                                   圖3
十分正常。但是,若用同樣地代碼來draw變形後的red_mc(即圖2中的red_mc),會是什麼樣子呢?圖2中red_mc尺寸太大,這塊兒150*150的白色像素會不會只能draw入red_mc的一部分呢?效果如下:

                                   圖4

看來,仍舊是以初始狀態的red_mc為繪製源。

這就是draw(X)方法的一個細節:不管X怎樣變形,平移,都選取X的初始狀態作為繪製源。此外,當X處於層層容器嵌套之下時(green_mc就是這種情況),不管它n多父級的變形操作對X形狀產生怎樣影響,draw也一樣選取X的初始狀態為繪製源。

 

Step3:前兩步作為準備,現在開始碰撞檢測的第一步,利用flash內建的hitTestObject()函數做預判斷。若這一步判斷false肯定沒戲了。

補充知識:

1.hitTestObject()是基於AABB包圍體的碰撞檢測,即檢測虛線框的碰撞。(red_mc的虛線框看似並未僅包住red_mc,這是因為red_mc


                                 圖5

進行過旋轉變換。)

2.hitTestObject()檢測碰撞時,並不關心對象是否在顯示列表內。這點很重要。

 

Step4.通過上步的預判斷,再進一步檢測:擷取兩個包圍體的交疊矩形地區,用rect1儲存相關資訊(x,y,width,height),判斷rect1地區內red_mc和green_mc是否有像素重疊。若true便碰上了。

補充知識:顯示對象的matrix屬性

matrix本身的a,b,c,d沒什麼好說,這裡記下matrix操作的細節。

1.red_mc.transform.matrix,這個記錄矩陣(習慣稱它記錄矩陣,文檔上稱“變換矩陣”),是red_mc相對於父級容器座標系的記錄矩陣。就像通常所說red_mc.x也是red_mc相對於父級座標系的x軸位移。

 

2.要想獲得red_mc相對於再上一級,即parent.parent的記錄矩陣,該如何呢?直接用parent的matrix乘上red_mc的matrix就好了。

 

3.若想擷取red_mc相對於stage的記錄矩陣呢?理論上是root.transform.matrix*........(各級父容器的矩陣逐級相乘)......*red_mc.transform.matrix。很累,flash為此提供了concatenatedMatrix屬性,就是顯示對象相對於stage的記錄矩陣。(矩陣乘法是不能用*號的,應該是concat,我是想寫快點兒)

 

4.假若要擷取red_mc相對於root的記錄矩陣呢?直接逐級相乘沒問題。不過,concatenated屬性提供了一個簡潔思路------varrootM:Matrix=root.transform.matrix.clone();

         var rootM1:Matrix=red_mc.transform.concatenatedMatrix;

         rootM.invert();//取得root的逆矩陣

          rootM1.concatenatedMatrix.concat(rootM);//這樣,rootM1就轉化為相對於root的

 

5.matrix的concat()方法似有bug

當a,d任意為0時,計算的結果就不大對,例如下面兩個矩陣

var A:Matrix=newMatrix(1,1,2,2,0,0);

var B:Matrix=newMatrix(0,0,1,1,1,0);

A.concat(B);

trace(A);//輸出的ty不是2,我用筆算了幾遍,ty都是2

當a,d都不為0時,計算結果沒有問題,以後還是放心用吧,因為a,d任意為0,顯示對象便不存在了,應不會存在這種情況。

自己寫了個矩陣運算類,是很無腦的演算法:行對列相乘。很慢很穩妥。是不是內建的矩陣乘法運算採用另外演算法,才會有這樣的bug呢?

 

6.matrix的concat()方法用起來要小心順序

A.concat(B),對應的數學式為(矩陣B*矩陣A),矩陣乘法不滿足交換律,這個地方跟常規思路又不同(至少跟我想的順序相反),因此操作時應小心。

 

7.不要直接修改顯示對象matrix的a,b,c,d,tx,ty屬性,也不要直接應用scale,rotate等操作。因為任何設定都是無效的。

如:varA:Matrix=red_mc.taransform.matrix;//A引用的是red_mc.taransform.matrix的一份拷貝

   A.scale(0.5,0.5);//編譯不會報錯,但這個操作只修改A,對red_mc.taransform.matrix不造成修改

   A.a=2;//同上

正確的操作是這樣的:

  varA:Matrix=red_mc.transform.matrix.clone();

  //varA:Matrix=red_mc.transform.matrix也行

 A.scale(0.5,0.5);

 A.a=2;

 red_mc.tansform.matrix=A;//建立一個合適矩陣,交付給red_mc.transform.matrix引用。

 

8.想對matrix執行scale操作時,用scale方法:

A.sacle(0.5,0.5);

不要寫:A.a/=A.b/=2;當matrix的b,c屬性不為0,這個操作完成的並不是scale功能。

 

補充知識:BlendMode.DIFFERENCE

文檔講的很清楚:

將顯示對象的原色與背景顏色進行比較,然後從較亮的原色值中減去較暗的原色值。此設定通常用於得到更明亮的顏色。

例如,如果顯示對象的某個像素的 RGB 值為0xFFCC33,背景像素的 RGB 值為 0xDDF800,則顯示像素的結果 RGB 值為 0x222C33(因為 0xFF -0xDD = 0x22,0xF8 - 0xCC = 0x2C,且 0x33 - 0x00 = 0x33)。

 

補充知識:draw()方法的matrix參數有何效果

文檔說:用於縮放、旋轉位元影像或轉換位元影像的座標

下面用代碼和說明:

   varbmd1:BitmapData = new BitmapData(200,200);
   bmd1.draw(red_mc,newMatrix(1,0,0,1,0,0));//先不對繪製源做處理,看看正常的樣子
   varbmp1:Bitmap = new Bitmap(bmd1);
   this.addChild(bmp1);

                                       圖6

很正常,跟圖4吻合

再看:

   varbmd1:BitmapData = new BitmapData(200,200);
   bmd1.draw(red_mc,newMatrix(1,0,0,1,110,110));//讓繪製源沿x,y軸正方向平移了(110,110)的向量
   varbmp1:Bitmap = new Bitmap(bmd1);
   this.addChild(bmp1);

                                       圖7
果然,繪製源相對註冊點位移了(110,110)

再看:

   varbmd1:BitmapData = new BitmapData(200,200);
   bmd1.draw(red_mc,new Matrix(2, 0, 0, 2, 0, 0));
   varbmp1:Bitmap = new Bitmap(bmd1);
   this.addChild(bmp1);


                                            圖8
果然縮放了兩倍

這便是matrix參數的功能。

問:如何才能draw到圖8中舞台下部的red_mc的形貌呢?

答:肉眼看到的red_mc的形貌,是它在stage座標系中的形貌,因此將draw參數設定為red_mc.transform.concatenatedMatrix,這樣繪製源便從初始狀態變換到相對舞台的形貌。

試一下:

   varbmd1:BitmapData = new BitmapData(200, 200);
   //為了便於區分,施加一個colorTransform讓draw到的像素變為藍色
   bmd1.draw(red_mc,a_mc.transform.concatenatedMatrix,newColorTransform(1,1,1,-255,-255,255));
   varbmp1:Bitmap = new Bitmap(bmd1);
   this.addChild(bmp1);


                                         圖9

什麼也沒有?因為像素塊太小了,red_mc經過矩陣變換,已經跑到了它外面去。

將像素塊增大,看看:

   varbmd1:BitmapData = new BitmapData(300, 300);
   //為了便於區分,施加一個colorTransform讓draw到的像素變為藍色
   bmd1.draw(a_mc,a_mc.transform.concatenatedMatrix,newColorTransform(1,1,1,1,-255,-255,255,255));
   varbmp1:Bitmap = new Bitmap(bmd1);
   this.addChild(bmp1);


                                        圖10
這下好啦!很准。

但,假如像素塊兒尺寸因為某種原因不能修改,該怎麼辦?那就再折磨draw()方法的matrix參數,讓red_mc平移到舞台原點:

   varbmd1:BitmapData = new BitmapData(200, 200);
   //為了便於區分,施加一個colorTransform讓draw到的像素變為藍色
   var m1:Matrix= a_mc.transform.concatenatedMatrix;
   m1.tx += 0 -m1.tx;
   m1.ty += 0 -m1.ty;
   bmd1.draw(a_mc,m1,newColorTransform(1,1,1,1,-255,-255,255,255));
   varbmp1:Bitmap = new Bitmap(bmd1);
   this.addChild(bmp1);

效果:

                                           圖11

就是要這個樣子。

 

剛才說到Step4:擷取兩個包圍體的交疊矩形地區,用rect1儲存相關資訊(x,y,width,height),判斷rect1地區內red_mc和green_mc是否有像素重疊。

               

                                           圖12
判斷rect1地區內red_mc和green_mc是否有像素重疊的思路:

new出來一塊兒跟rect1等大的黑色像素塊。用一種colorTransform去drawrect1地區內的red_mc,再用另一種colorTransform去draw rect1地區內的green_mc,同時採用blendMode.DIFFERENCE混合模式,一旦出現特定顏色,則有像素重疊。

 

至於如何準確的draw到rect1地區內的red_mc/green_mc的像素,在補充裡已經給出思路。

現在再看tink的那個類應該很簡單了。並且,個人認為他的類存在一些錯誤,下篇討論

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.