Мне нужно определить круг столкновений с любой строкой. У меня есть массив с вертиками многоугольника (x, y) и нарисовать этот многоугольник в цикле. Для обнаружения я использую алгоритм, который вычисляет высоту треугольника. Затем я проверю, была ли эта высота < 0, затем круг столкнулся с линией.Столкновение сегментов линии круга
Картину, которые описывают этот метод:
Но у меня есть неожиданный результат. Мой круг сталкивается с прозрачной линией (что?). Я не могу объяснить, как это происходит.
Demo в 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 = [
\t {
\t x: 240,
y: 130
},
{
\t x: 140,
y: 100
},
{
\t x: 180,
y: 250
},
{
\t x: 320,
y: 280
},
{
\t x: 400,
y: 50
}
];
var game = {
\t ball: new Ball()
};
function Ball() {
\t 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() {
\t 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() {
\t 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() {
\t var p = polygonPoints;
\t for (var i = 0, n = p.length; i < n; i++) {
\t 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) {
\t continue;
}
\t \t // 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);
\t for (var i = 1, n = polygonPoints.length; i < n; i++) {
\t 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>
Что проблема? Может быть, мне нужен другой метод обнаружения столкновения? Я пытался использовать this one, но если мой круг имеет высокую скорость, этот метод не работает.
спасибо.
Этот метод работает, если мяч имеет низкую скорость, но если скорость высокая, функция не работает. https://jsfiddle.net/cmx8arz2/ см. консоль. Если приложение пересечения границ круга должно печатать массив точек пересечения, но скорость круга высокая и консольный журнал очищается. – rmpstmp
@rmpstmp Используйте перехват линии, используя траекторию шара в качестве второй линии. Переместите линию вдоль ее нормали к шару радиусом шариков. Если линии пересекаются, используйте эту точку, чтобы проверить, насколько далеко от исходного сегмента линии. если в радиусе (добавить EPSILON) из любой точки на линии или в конечных точках вы попали в мяч. Кросс-продукт будет давать то, что указывает точка на линию + правая-левая и точка-линия. Линия квадратов, выраженная в квадрате, даст единицу dist на линии вдоль ее нормали к точке. Точка и линия должны быть переведены, чтобы положить начало линии в нуле – Blindman67
@rmpstmp Глядя на скрипку. Просто переместите все сегменты линии внутрь радиусом шара (вдоль нормалей линии). Используйте траекторию шара как линию и выполняйте перехват линии/линии. Найдите ближайший перехват текущего местоположения шара, и у вас есть точка перехвата, нет необходимости в перехвате сегмента линии круга. – Blindman67