2010-04-30 82 views
8

我想檢查HTML5畫布中兩個Sprites之間的碰撞。所以爲了討論的緣故,我們假設這兩個精靈都是IMG對象,碰撞意味着alpha通道不是0.現在這兩個精靈都可以圍繞對象的中心旋轉,但是沒有其他變換,以防止這樣做任何更容易。HTML5畫布中的像素完美碰撞檢測

現在顯而易見的解決方案,我想出了會是這樣:

  • 計算變換矩陣兩種
  • 揣摩出的代碼應該測試(如偏移兩者的面積粗略估算+計算用於旋轉的額外空間)
  • 對於相交矩形中的所有像素,變換座標並在alpha通道的計算位置(舍入到最近的鄰居)測試圖像。然後在第一次擊中時放棄。

我看到的問題是,a)JavaScript中沒有矩陣類,這意味着我必須在JavaScript中這樣做,這可能會很慢,我必須測試碰撞的每一幀,這使得這漂亮昂貴。此外,我必須複製一些我在繪圖時必須做的事情(或者畫布爲我設置矩陣)。

我在想這裏是否缺少任何東西,以及是否有更簡單的碰撞檢測解決方案。

+0

我無法找到答案,我問這個問題太:( – super 2013-12-26 14:27:38

回答

6

我不是一個JavaScript代碼編寫人員,但我想象同樣的優化技巧對於JavaScript來說也同樣適用於C++。

只需旋轉精靈的角落而不是每個像素。實際上你會做類似軟件紋理映射的事情。您可以使用各種梯度信息計算給定像素的x,y位置。查看軟件紋理映射以獲取更多信息。

如果四叉樹將精靈分解爲「命中」和「非命中」區域,則可以有效檢查給定的四叉樹分解是否全部爲「未命中」,「全部命中」或「可能命中「(即包含點擊和非點擊像素,前兩個點是微不足道的,在最後一個例子中,您將進入下一個分解點並重複測試,這樣您只需檢查您需要的像素, 「無創」和「打」的大片,你不必做這麼複雜的檢查。

反正那只是一對夫婦的想法。

7

我要複製我的東西已經 必須在繪製

那麼做,你可以做一個新的渲染環境,情節一個旋轉的白色背景面膜時,設定合成操作lighter和在給定偏置曲線之上彼此旋轉的面具。

現在,如果還有一個非白色的像素,就會有一個命中。你仍然需要getImageData,並通過像素篩選找出。通過向下縮放合成圖像(依靠抗鋸齒將某些像素保持爲非白色),您可能會稍微減少一些工作量,但我認爲它可能仍然會很慢。

我必須測試碰撞每個幀,這使得這非常昂貴。

是的,我認爲你會使用預先計算的碰撞表。如果你有足夠的空間,你可以爲精靈a,精靈b,相對旋轉,相對x歸一化到旋轉和相對y歸一化到旋轉的每個組合存儲一個命中/不命中位。根據你有多少個精靈以及多少個旋轉或移動步驟,這可能會變得相當大。

一個妥協方法是將每個精靈的預先旋轉的掩碼存儲在一個JavaScript數組中(數字,給你32位/像素的容易&&可用數據,或者作爲一個字符在Sring中,給你16位)和&&每行相交的精靈蒙版一起。或者,放棄像素,開始看例如。路徑。

2

同樣的問題,一種替代解決方案。首先,我使用getImageData數據來查找圍繞精靈的多邊形。這裏要小心,因爲該實現適用於具有透明背景且具有單個實體對象的圖像。像一艘船。下一步是Ramer Douglas Peucker Algorithm以減少多邊形中頂點的數量。我最終得到了一個很少頂點的多邊形,它很容易便宜地旋轉,並檢查每個精靈與其他多邊形的碰撞。

http://jsfiddle.net/rnrlabs/9dxSg/

var canvas = document.getElementById("canvas"); 
var context = canvas.getContext("2d"); 
var img = document.getElementById("img"); 

context.drawImage(img, 0,0); 
var dat = context.getImageData(0,0,img.width, img.height); 
// see jsfiddle 
var startPixel = findStartPixel(dat, 0); 
var path = followPath(startPixel, dat, 0); 
// 4 is RDP epsilon 
map1 = properRDP(path.map, 4, path.startpixel.x, path.startpixel.y); 

// draw 

context.beginPath(); 
context.moveTo(path.startpixel.x, path.startpixel.x); 
for(var i = 0; i < map.length; i++) { 
    var p = map[i]; 
    context.lineTo(p.x, p.y); 
} 
context.strokeStyle = 'red'; 
context.closePath(); 
context.stroke();