检测和响应任何多边形

时间:2016-04-09 22:31:09

标签: javascript canvas html5-canvas

需要编写好的方法来检测和响应任何多边形内的球到墙碰撞。

例如,我有一种方法可以绘制一个在矩形内飞行的球。

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>

3 个答案:

答案 0 :(得分:3)

以下是如何测试圆形(球)碰撞与多边形中的任何线条的对比。

首先,计算相对于球的线上的闭合点:

checkcommand json --if `echo `"all good"` --else `npm install json -g`

第二,测试球是否足够接近与此线相撞:

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) });
}

最后,如果球与那侧碰撞,计算球的反射角(==它的出射角):

以下是计算中涉及的角度的说明:

  • 红线表示球的入射角度。
  • 金线表示球的外出角度。
  • 出射角等于入射角加上差异角的两倍。

enter image description here

这里有一些伪代码显示如何进行计算:

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

答案 1 :(得分:0)

我可能误解了你的问题,我会尽快更新我的回答。

由于它是一个多边形,你只有一个有限数量的顶点(角),并且在与屏幕边缘碰撞的情况下,至少有一个角会接触。这意味着您只需循环遍历Polygone点列表并检查[any]是否在屏幕之外。

答案 2 :(得分:0)

这是一个广泛的问题。有许多方法可以计算2d碰撞。 幸运的是,圆形碰撞非常简单,因为每个尺寸的尺寸完全相同

你很可能想要使用运动矢量(dx / dy)和线矢量。尝试计算每次迭代前一步的跟随运动,并查看向量相交的位置。然后计算必要的力量

不用说,数学和三角计算是必要的。这并不困难,只是人们在需要使用鼻窦和鼻窦时通常会感到害怕

来自N物理引擎制造商的{strong>非常非常良好的解释性文章http://www.metanetsoftware.com/technique/tutorialA.html