It is common when writing JavaScript games to need to calculate if a line will intersect with a given rectangle, circle or another line. In the chapter on Ray Casting in my book on learning JavaScript programming the code required to test for an intersection between a "ray" and a game world wall or sprite proved straightforward as the problem was deliberately simplified by the overall structure. In other projects some more general functions might prove helpful.
Interactive demo web page here
Demo code available for download here
The demo page features three intersection functions. All three functions are based upon Internet research and I am grateful for all of the very useful suggestions I found for each.
1. Line intersection with a rectangle
2. Line intersection with a circle
3. line intersection with a line
Interactive demo web page here
Demo code available for download here
The demo page features three intersection functions. All three functions are based upon Internet research and I am grateful for all of the very useful suggestions I found for each.
1. Line intersection with a rectangle
function lineIntersectsRect(lStart, lEnd, rect) {
let minX = lStart.x;
let maxX = lEnd.x;
if(lEnd.x < lStart.x) {
maxX = lStart.x;
minX = lEnd.x;
}
maxX = Math.min(maxX, rect.x + rect.width);
minX = Math.max(minX, rect.x);
if(minX > maxX) {return false;}
let minY = lStart.y;
let maxY = lEnd.y;
let dx = lEnd.x - lStart.x;
if(dx) { // there is a horizontal slope
let a = (lEnd.y - lStart.y)/dx;
let b = lStart.y - a * lStart.x;
minY = a * minX + b;
maxY = a * maxX + b;
}
if(minY > maxY) {
[minY, maxY] = [maxY, minY]; // ES6 Destructuring Assignment swaps values
}
if(Math.max(minY, rect.y) > Math.min(maxY, rect.y + rect.height)){
return false;
}
return true;
}
2. Line intersection with a circle
function lineIntersectsCircle(lStart, lEnd, center, radius) {
let dist;
const dx1 = lEnd.x - lStart.x;
const dy1 = lEnd.y - lStart.y;
const dx2 = center.x - lStart.x;
const dy2 = center.y - lStart.y;
// get the unit distance along the line of the closest point to circle center
const u = (dx2 * dx1 + dy2 * dy1) / (dy1 * dy1 + dx1 * dx1);
// if the point is on the line segment get the distance squared to circle center
if(u >= 0 && u <= 1){
dist = Math.pow((lStart.x + dx1 * u - center.x), 2) + Math.pow((lStart.y + dy1 * u - center.y), 2);
} else {
// use the u distance to determine which end is closest and get dist squared to circle
dist = u < 0 ?
Math.pow((lStart.x - center.x), 2) + Math.pow((lStart.y - center.y), 2) :
Math.pow((lEnd.x - center.x), 2) + Math.pow((lEnd.y - center.y), 2);
}
return dist < Math.pow(radius, 2);
}
3. line intersection with a line
function lineIntersectsLine(p0, p1, p2, p3) {
let dx1 = p1.x - p0.x;
let dy1 = p1.y - p0.y;
let dx2 = p3.x - p2.x;
let dy2 = p3.y - p2.y;
let d = dx1 * dy2 - dx2 * dy1;
if(!d) { return false;}
let dIsPositive = d > 0;
let xd1 = p0.x - p2.x;
let yd1 = p0.y - p2.y;
let s_numer = dx1 * yd1 - dy1 * xd1;
if((s_numer < 0) === dIsPositive) {
return false; // watch logic = both true or both false returns false
}
let t_numer = dx2 * yd1 - dy2 * xd1;
if((t_numer < 0) === dIsPositive) {
return false;
}
if((s_numer > d) === dIsPositive ||
(t_numer > d) === dIsPositive) {
return false;
}
return true;
}
No comments:
Post a Comment