繁体   English   中英

圆线段碰撞

[英]Circle line segment collision

我需要检测任何一条线的碰撞圈。 我有多边形(x,y)的Verticle数组,并在循环中绘制这个多边形。 为了检测我使用算法,计算三角高度。 然后我检查这个高度是否<0,然后圆与线相撞。

描述这种方法的图片:

在此输入图像描述

但我有意想不到的结果。 我的圆圈与透明线碰撞(什么?)。 我无法解释它是如何发生的。

在jsfiddle演示: https ://jsfiddle.net/f458rdz6/1/

功能,检查碰撞并响应它:

var p = polygonPoints;

for (var i = 0, n = p.length; i < n; i++) {
    var start = i;
    var end = (i + 1) % n;

    var x0 = p[start].x;
    var y0 = p[start].y;
    var x1 = p[end].x;
    var y1 = p[end].y;

    // detection collision
    var dx = x1 - x0;
    var dy = y1 - y0;

    var len = Math.sqrt(dx * dx + dy * dy);
    var dist = (dx * (this.y - y0) - dy * (this.x - x0)) / len;

    if (dist < this.radius) {
        continue;
    }

    // calculate reflection, because collided
    var wallAngle = Math.atan2(dy, dx);
    var wallNormalX = Math.sin(wallAngle);
    var wallNormalY = -Math.cos(wallAngle);

    var d = 2 * (this.velocityX * wallNormalX + this.velocityY * wallNormalY);
    this.x -= d * wallNormalX;
    this.y -= d * wallNormalY;
}

 var canvas = document.getElementById("myCanvas"); var ctx = canvas.getContext("2d"); var polygonPoints = [ { x: 240, y: 130 }, { x: 140, y: 100 }, { x: 180, y: 250 }, { x: 320, y: 280 }, { x: 400, y: 50 } ]; var game = { ball: new Ball() }; function Ball() { this.x = canvas.width / 2; this.y = canvas.height - 100; this.oldX = this.x - 1; this.oldY = this.y + 1; this.velocityX = 0; this.velocityY = 0; this.radius = 8; }; Ball.prototype.draw = function() { ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2); ctx.fillStyle = '#0095DD'; ctx.fill(); ctx.closePath(); }; Ball.prototype.update = function() { var x = this.x; var y = this.y; this.velocityX = this.x - this.oldX; this.velocityY = this.y - this.oldY; this.x += this.velocityX; this.y += this.velocityY; this.oldX = x; this.oldY = y; }; Ball.prototype.collision = function() { var p = polygonPoints; for (var i = 0, n = p.length; i < n; i++) { var start = i; var end = (i + 1) % n; var x0 = p[start].x; var y0 = p[start].y; var x1 = p[end].x; var y1 = p[end].y; // detection collision var dx = x1 - x0; var dy = y1 - y0; var len = Math.sqrt(dx * dx + dy * dy); var dist = (dx * (this.y - y0) - dy * (this.x - x0)) / len; if (dist < this.radius) { continue; } // calculate reflection, because collided var wallAngle = Math.atan2(dy, dx); var wallNormalX = Math.sin(wallAngle); var wallNormalY = -Math.cos(wallAngle); var d = 2 * (this.velocityX * wallNormalX + this.velocityY * wallNormalY); this.x -= d * wallNormalX; this.y -= d * wallNormalY; } }; 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 render() { ctx.clearRect(0, 0, canvas.width, canvas.height); drawPolygon(); game.ball.draw(); game.ball.update(); game.ball.collision(); window.requestAnimationFrame(render); } render(); 
 canvas { border: 1px solid #333; } 
 <canvas id="myCanvas" width="480" height="320"></canvas> 

有什么问题? 也许我需要使用其他方法来检测碰撞? 我尝试使用这个 ,但如果我的圈子速度很快,这种方法就不起作用了。

谢谢。

圆线段截距

UPDATE

此答案包括线条截距,沿其法线移动线,距离点(圆)到线,以及圆线截距。

圆圈是

var circle = {
    radius : 500,
    center : point(1000,1000),
}

线段是

var line = {
    p1 : point(500,500),
    p2 : point(2000,1000),
}

一点是

var point = {
    x : 100,
    y : 100,
}

因此找到一个线段宽度为一个圆的截距的函数

该函数返回线段上最多两个点的数组。 如果找不到任何点,则返回一个空数组。

function inteceptCircleLineSeg(circle, line){
    var a, b, c, d, u1, u2, ret, retP1, retP2, v1, v2;
    v1 = {};
    v2 = {};
    v1.x = line.p2.x - line.p1.x;
    v1.y = line.p2.y - line.p1.y;
    v2.x = line.p1.x - circle.center.x;
    v2.y = line.p1.y - circle.center.y;
    b = (v1.x * v2.x + v1.y * v2.y);
    c = 2 * (v1.x * v1.x + v1.y * v1.y);
    b *= -2;
    d = Math.sqrt(b * b - 2 * c * (v2.x * v2.x + v2.y * v2.y - circle.radius * circle.radius));
    if(isNaN(d)){ // no intercept
        return [];
    }
    u1 = (b - d) / c;  // these represent the unit distance of point one and two on the line
    u2 = (b + d) / c;    
    retP1 = {};   // return points
    retP2 = {}  
    ret = []; // return array
    if(u1 <= 1 && u1 >= 0){  // add point if on the line segment
        retP1.x = line.p1.x + v1.x * u1;
        retP1.y = line.p1.y + v1.y * u1;
        ret[0] = retP1;
    }
    if(u2 <= 1 && u2 >= 0){  // second add point if on the line segment
        retP2.x = line.p1.x + v1.x * u2;
        retP2.y = line.p1.y + v1.y * u2;
        ret[ret.length] = retP2;
    }       
    return ret;
}

UPDATE

线路拦截。

返回一个点,如果找到else返回undefined。

function interceptLines(line,line1){  
    var v1, v2, c, u;
    v1 = {};
    v2 = {};
    v3 = {};
    v1.x = line.p2.x - line.p1.x; // vector of line
    v1.y = line.p2.y - line.p1.y;
    v2.x = line1.p2.x - line1.p1.x; //vector of line2
    v2.y = line1.p2.y - line1.p1.y;
    var c = v1.x * v2.y - v1.y * v2.x; // cross of the two vectors
    if(c !== 0){ 
        v3.x = line.p1.x - line1.p1.x; 
        v3.y = line.p1.y - line1.p1.y;                
        u = (v2.x * v3.y - v2.y * v3.x) / c; // unit distance of intercept point on this line
        return {x : line.p1.x + v1.x * u, y : line.p1.y + v1.y * u};
    }
    return undefined;
}

提升线

沿着法线移动线

function liftLine(line,dist){
    var v1,l
    v1 = {};
    v1.x = line.p2.x - line.p1.x; // convert line to vector
    v1.y = line.p2.y - line.p1.y;
    l = Math.sqrt(v1.x * v1.x + v1.y * v1.y); // get length;
    v1.x /= l;  // Assuming you never pass zero length lines
    v1.y /= l;
    v1.x *= dist; // set the length
    v1.y *= dist;
    // move the line along its normal the required distance
    line.p1.x -= v1.y;
    line.p1.y += v1.x;
    line.p2.x -= v1.y;
    line.p2.y += v1.x;

    return line; // if needed 
}

距线圈(或点)到线段

返回到线段的最近距离。 它只是我正在使用的圆心。 所以你可以用一个点代替圆

function circleDistFromLineSeg(circle,line){
    var v1, v2, v3, u;
    v1 = {};
    v2 = {};
    v3 = {};
    v1.x = line.p2.x - line.p1.x;
    v1.y = line.p2.y - line.p1.y;
    v2.x = circle.center.x - line.p1.x;
    v2.y = circle.center.y - line.p1.y;
    u = (v2.x * v1.x + v2.y * v1.y) / (v1.y * v1.y + v1.x * v1.x); // unit dist of point on line
    if(u >= 0 && u <= 1){
        v3.x = (v1.x * u + line.p1.x) - circle.center.x;
        v3.y = (v1.y * u + line.p1.y) - circle.center.y;
        v3.x *= v3.x;
        v3.y *= v3.y;
        return Math.sqrt(v3.y + v3.x); // return distance from line
    } 
    // get distance from end points
    v3.x = circle.center.x - line.p2.x;
    v3.y = circle.center.y - line.p2.y;
    v3.x *= v3.x;  // square vectors
    v3.y *= v3.y;    
    v2.x *= v2.x;
    v2.y *= v2.y;
    return Math.min(Math.sqrt(v2.y + v2.x), Math.sqrt(v3.y + v3.x)); // return smaller of two distances as the result
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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