簡體   English   中英

在任何多邊形內部檢測和響應球壁碰撞

[英]Detection and response ball-to-wall collision inside any polygon

需要編寫好的方法來檢測和響應任何多邊形內的球壁碰撞。

例如,我有一個方法可以繪制一個在矩形內飛行的球。

ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();

檢測和響應該碰撞非常簡單。

if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
    dx = -dx;
}

if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
    dy = -dy;
}

但是我有一個多邊形:每個點的位置(x和y)是變量。

var polygonPoints = [
{
    x: 240,
    y: 30
},
{
    x: 140,
    y: 100
},
{
    x: 180,
    y: 250
},
{
    x: 320,
    y: 280
},
{
    x: 400,
    y: 50
}

]。

和函數來繪制我的多邊形:

ctx.beginPath();
ctx.strokeStyle = '#333';
ctx.moveTo(polygonPoints[0].x, polygonPoints[0].y);
for (var i = 1, n = polygonPoints.length; i < n; i++) {
    ctx.lineTo(polygonPoints[i].x, polygonPoints[i].y);
}
ctx.lineTo(polygonPoints[0].x, polygonPoints[0].y);
ctx.stroke();
ctx.closePath();

如何檢測和響應多邊形內部的碰撞?

jsfiddle上的演示。

 var canvas = document.getElementById("myCanvas"); var ctx = canvas.getContext("2d"); var ballRadius = 10; var x = canvas.width/2; var y = canvas.height-30; var dx = 2; var dy = -2; var polygonPoints = [ { x: 240, y: 30 }, { x: 140, y: 100 }, { x: 180, y: 250 }, { x: 320, y: 280 }, { x: 400, y: 50 } ]; function drawBall() { ctx.beginPath(); ctx.arc(x, y, ballRadius, 0, Math.PI*2); ctx.fillStyle = "#0095DD"; ctx.fill(); ctx.closePath(); } function drawPolygon() { ctx.beginPath(); ctx.strokeStyle = '#333'; ctx.moveTo(polygonPoints[0].x, polygonPoints[0].y); for (var i = 1, n = polygonPoints.length; i < n; i++) { ctx.lineTo(polygonPoints[i].x, polygonPoints[i].y); } ctx.lineTo(polygonPoints[0].x, polygonPoints[0].y); ctx.stroke(); ctx.closePath(); } function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); drawBall(); drawPolygon(); if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) { dx = -dx; } if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) { dy = -dy; } x += dx; y += dy; window.requestAnimationFrame(draw); } draw(); 
 canvas { border: 1px solid #333; } 
 <canvas id="myCanvas" width="480" height="320"></canvas> 

這是測試多邊形中任何線與圓(球)碰撞的方法。

首先,計算相對於您的球的直線上的閉合點:

function calcClosestPtOnSegment(x0,y0,x1,y1,cx,cy){

    // calc delta distance: source point to line start
    var dx=cx-x0;
    var dy=cy-y0;

    // calc delta distance: line start to end
    var dxx=x1-x0;
    var dyy=y1-y0;

    // Calc position on line normalized between 0.00 & 1.00
    // == dot product divided by delta line distances squared
    var t=(dx*dxx+dy*dyy)/(dxx*dxx+dyy*dyy);

    // calc nearest pt on line
    var x=x0+dxx*t;
    var y=y0+dyy*t;

    // clamp results to being on the segment
    if(t<0){x=x0;y=y0;}
    if(t>1){x=x1;y=y1;}

    return({ x:x, y:y, isOnSegment:(t>=0 && t<=1) });
}

其次,測試球是否足夠靠近以與該直線碰撞,如下所示:

var dx=ballX-nearestX;
var dy=ballY-nearestY
var isColliding=(dx*dx+dy*dy<ballRadius*ballRadius);

最后,如果球與該側碰撞,請計算球的反射角(==它的出射角):

這是計算中涉及的角度的說明:

  • 紅線表示球的進入角度。
  • 金線表示球的射出角度。
  • 出射角等於入射角加兩倍擴散角。

在此處輸入圖片說明

這是一些偽代碼,顯示了如何進行計算:

var wallNormalAngle = wallAngle-PI/2; // assuming clockwise angle calculations
var differenceAngle = incidenceAngle - wallNormalAngle;
var reflectionAngle = incidenceAngle + 2 * differenceAngle

我可能誤解了您的問題,我會盡快更新答案。

由於它是多邊形,因此您只有有限數量的頂點(角),並且在與屏幕邊緣發生碰撞的情況下,至少有一個角會接觸。 這意味着您只需要遍歷Polygone點列表並檢查[any]是否在屏幕之外。

這是一個廣泛的問題。 有很多計算2d碰撞的方法。 幸運的是,圓形碰撞非常簡單,因為每種尺寸的碰撞尺寸都完全相同

您很可能希望使用運動矢量(dx / dy)和線矢量。 嘗試在每次迭代中向前計算一步,然后查看向量相交的位置。 然后計算必要的力量

不用說,數學和三角學計算是必要的。 這並不困難,只是人們通常在需要使用鼻竇和余弦時會感到害怕

N物理引擎的制造商對此主題很好的解釋文章, 網址為http://www.metanetsoftware.com/technique/tutorialA.html

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM