繁体   English   中英

圆形碰撞检测HTML5画布

[英]Circle Collision Detection HTML5 Canvas

我想检查圆圈是否相互碰撞。

我知道我可以通过在圆圈的两个中心之间获得距离并从该距离减去每个圆的半径并查看“距离”是否> 1来做到这一点。

我怎么能有效地做到这一点,比如1000圈? 也许我可以以某种方式得到最近的20个圆圈或类似的东西并检查这些? 我不知道如何开始有效地开展这项工作。

有任何想法吗?

这是一个例子:

http://experiments.lionel.me/blocs/

在开始计算距离的精确差异之前,您至少可以比较中心的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM