Reputation: 281
Need to code good method for detection and response ball-to-wall collision inside any polygon.
For example, I have a method which draw a ball which fly inside a rectangle.
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
Detect and response that collision very simple.
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
dy = -dy;
}
But I have a polygon: variable with positions (x and y) of each point.
var polygonPoints = [
{
x: 240,
y: 30
},
{
x: 140,
y: 100
},
{
x: 180,
y: 250
},
{
x: 320,
y: 280
},
{
x: 400,
y: 50
}
];
And function wich draw my polygon:
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();
How I can detect and response collisions inside a polygon?
Demo on 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>
Upvotes: 2
Views: 2110
Reputation: 105015
Here's how to test for circle (ball) collisions) versus any line in your polygon.
First, calculate the closes point on a line relative to your ball:
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) });
}
Second, test if the ball is close enough to collide with that line like this:
var dx=ballX-nearestX;
var dy=ballY-nearestY
var isColliding=(dx*dx+dy*dy<ballRadius*ballRadius);
Finally, if the ball collided with that side, calculate the ball's reflection angle (== its outgoing angle):
Here's an illustration of the angles involved in the calculation:
And here's some pseudo-code showing how to do the calculation:
var wallNormalAngle = wallAngle-PI/2; // assuming clockwise angle calculations
var differenceAngle = incidenceAngle - wallNormalAngle;
var reflectionAngle = incidenceAngle + 2 * differenceAngle
Upvotes: 4
Reputation: 1985
this is a broad question. there are many methods to calculate 2d collisions. luckily, circle collisions are quite simple, as it's exactly the same size on each size
you will most likely want to work with movement vectors (dx/dy) and line vectors. try to calculate following movement one step ahead on each iteration and see where the vectors intersect. then calculate necessary forces
needless to say, mathematics and trigonometry computations are necessary. it's not difficult, just people usually get scared when needing to use sinuses and cosinuses
there is a very very good explaining article on this topic from the maker of the N physics engine http://www.metanetsoftware.com/technique/tutorialA.html
Upvotes: 0
Reputation: 781
I may have misread your question, I will update my answer shortly.
Since it's a polygon you only have a finite number of verts(corners) and in the case of a collision with the edge of the screen at least one of the corners will make contact. This means you only need to loop through the list of Polygone points and check if [any] are outside of the screen.
Upvotes: 0