我需要检测任何一条线的碰撞圈。我有多边形(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();
&#13;
canvas {
border: 1px solid #333;
}
&#13;
<canvas id="myCanvas" width="480" height="320"></canvas>
&#13;
有什么问题?也许我需要使用其他方法来检测碰撞?我尝试使用this one,但是如果我的圈子速度很快,这种方法无效。
谢谢。
答案 0 :(得分:8)
<强>更新强>
此答案包括直线截距,沿法线移动直线,距离点(圆)到直线,以及圆线截距。
圈子是
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;
}
<强>更新强>
线路截距。
如果找到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
}