[英]Circle Collision Detection HTML5 Canvas
我想檢查圓圈是否相互碰撞。
我知道我可以通過在圓圈的兩個中心之間獲得距離並從該距離減去每個圓的半徑並查看“距離”是否> 1來做到這一點。
我怎么能有效地做到這一點,比如1000圈? 也許我可以以某種方式得到最近的20個圓圈或類似的東西並檢查這些? 我不知道如何開始有效地開展這項工作。
有任何想法嗎?
這是一個例子:
在開始計算距離的精確差異之前,您至少可以比較中心的x / y位置與半徑。 該信息在圓圈中隱含可用,只需要一些簡單的比較和加法/減法。
這樣你就可以比較所有圓圈對之間x / y的簡單距離,並拋棄任何明顯不是碰撞候選者的距離,例如
abs(x2 - x1) > (r2 + r1)
abs(y2 - y1) > (r2 + r1)
...如果圓心之間的X或Y距離大於半徑之和,則它們不會發生碰撞。
一旦你削減了可能的碰撞器,那么你就做了正式的精確笛卡爾距離,這就是“重”乘法/除法物的來源。
考慮將圓心的坐標存儲在四叉樹中,然后您只需要檢查圓是否與該象限或相鄰象限中的其他圓相交。
需要注意的是,您需要確保四叉樹的葉子節點具有最大圓的半徑的最小直徑,否則您將不僅要檢查相鄰節點的交叉點。
http://en.wikipedia.org/wiki/Quadtree
如果您的圓圈分散,那么您可以執行的簡單優化是將您的圓圈存儲在x或y軸上,然后您只需要檢查x或y坐標是否在圓的半徑內的圓圈。
效率將與您正在使用的算法的速度有關 ,例如,您計算距離的平方根算法的速度,除了算法之外,您的數據結構將決定內存的效率。 加速計算的另一種方法是降低距離計算的精度。
如你所說,檢測圓是否碰撞的最佳方法是將圓的中心坐標和半徑存儲在變量中,並計算當減去半徑時中心之間的距離是否等於0。
我強烈推薦Keith Peter的AdvancED ActionScript 3.0動畫書,在這本書中你可以找到Actionscript中Quadtree算法的具體實現。
以下是基本步驟:
首先創建一個二維網格,並將所有球隨機散布在整個場地上。
private function createGrids():void { _grids = new Array(); for (var i:int = 0; i< stage.stageWidth / GRID_SIZE; i++) { _grids[i] = new Array(); for (var j:int = 0; j< stage.stageHeight / GRID_SIZE; j++) { _grids[i][j] = new Array(); } } }
將球分配給網格單元格
private function assignBallsToGrid():void { for (var i:int = 0; i< numBalls; i++) { var ball:Ball = Ball(_balls[i]); var xpos:int = Math.floor(ball.x / GRID_SIZE); var ypos:int = Math.floor(ball.y / GRID_SIZE); _grids[xpos][ypos].push(ball); } }
檢查兩個球是否在一個單元中碰撞,然后檢查相鄰單元中的球。 正如Charles Ma所提到的那樣,網格單元的尺寸必須大於或等於最大的球直徑。
private function checkOneCell(x1:Number, y1:Number):void { var _cell:Array = _grids[x1][y1] as Array; for (var i:int = 0; i< _cell.length-1; i++) { var ballA:Ball = _cell[i] as Ball; for (var j:int = i+1; j< _cell.length; j++) { var ballB:Ball = _cell[j] as Ball; checkCollision(ballA, ballB); } } } private function checkTwoCell(x1:Number, y1:Number, x2:Number, y2:Number):void { if (x2 < 0) { return } if (x2 >= _grids.length) { return } if (y2 >= _grids[x2].length) { return } var _cell0:Array = _grids[x1][y1] as Array; var _cell1:Array = _grids[x2][y2] as Array; for (var i:int = 0; i< _cell0.length; i++) { var ballA:Ball = _cell0[i] as Ball; for (var j:int = 0; j< _cell1.length; j++) { var ballB:Ball = _cell1[j] as Ball; checkCollision(ballA, ballB); } } } private function checkCollision(ballA:Ball, ballB:Ball):void { var dx:Number = ballB.x - ballA.x; var dy:Number = ballB.y - ballA.y; var dist:Number = Math.sqrt(dx*dx + dy*dy); if (dist < ballB.radius + ballA.radius) { // do something } }
以下是它的主要方法:
private function checkBallsCollision():void { for (var i:int = 0; i< _grids.length; i++) { for (var j:int = 0; j< _grids[i].length; j++) { checkOneCell(i, j); checkTwoCell(i, j, i+1, j); checkTwoCell(i, j, i, j+1); checkTwoCell(i, j, i-1, j); checkTwoCell(i, j, i+1, j+1); } } }
注意:
代碼是用Actionscript編寫的,但可以在Javascript中很容易地實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.