Canvas Collisions and Intersections

Canvas Collisions and Intersections
Nikhil
Published on 2021-07-05 09:48:37

Are 2 circles colliding?


// circle objects: { x:, y:, radius: }
// return true if the 2 circles are colliding
// c1 and c2 are circles as defined above
function CirclesColliding(c1, c2) {
    var dx = c2.x - c1.x;
    var dy = c2.y - c1.y;
    var rSum = c1.radius + c2.radius;
    return (dx * dx + dy * dy <= rSum * rSum);
}

 

Are 2 rectangles colliding?


// rectangle objects { x:, y:, width:, height: }
// return true if the 2 rectangles are colliding
// r1 and r2 are rectangles as defined above
function RectsColliding(r1, r2) {
    return !(
        r1.x > r2.x + r2.width ||
        r1.x + r1.width < r2.x ||
        r1.y > r2.y + r2.height ||
        r1.y + r1.height < r2.y
    );
}

 

Are a circle and rectangle colliding?


// rectangle object: { x:, y:, width:, height: }
// circle object: { x:, y:, radius: }
// return true if the rectangle and circle are colliding
function RectCircleColliding(rect, circle) {
    var dx = Math.abs(circle.x - (rect.x + rect.width / 2));
    var dy = Math.abs(circle.y - (rect.y + rect.height / 2));
    if (dx > circle.radius + rect.width / 2) {
        return (false);
    }
    if (dy > circle.radius + rect.height / 2) {
        return (false);
    }
    if (dx <= rect.width) {
        return (true);
    }
    if (dy <= rect.height) {
        return (true);
    }
    var dx = dx - rect.width;
    var dy = dy - rect.height
    return (dx * dx + dy * dy <= circle.radius * circle.radius);
}

 

Are 2 line segments intercepting?


The function in this example returns true if two line segments are intersecting and false if not. The example is designed for performance and uses closure to hold working variables

// point object: {x:, y:}
// p0 & p1 form one segment, p2 & p3 form the second segment
// Returns true if lines segments are intercepting
var lineSegmentsIntercept = (function() { // function as singleton so that closure can be used
    var v1, v2, v3, cross, u1, u2; // working variable are closed over so they do not need
    creation
    // each time the function is called. This gives a significant
    performance boost.
    v1 = {
        x: null,
        y: null
    }; // line p0, p1 as vector
    v2 = {
        x: null,
        y: null
    }; // line p2, p3 as vector
    v3 = {
        x: null,
        y: null
    }; // the line from p0 to p2 as vector
    function lineSegmentsIntercept(p0, p1, p2, p3) {
        v1.x = p1.x - p0.x; // line p0, p1 as vector
        v1.y = p1.y - p0.y;
        v2.x = p3.x - p2.x; // line p2, p3 as vector
        v2.y = p3.y - p2.y;
        if ((cross = v1.x * v2.y - v1.y * v2.x) === 0) { // cross prod 0 if lines parallel
            return false; // no intercept
        }
        v3 = {
            x: p0.x - p2.x,
            y: p0.y - p2.y
        }; // the line from p0 to p2 as vector
        u2 = (v1.x * v3.y - v1.y * v3.x) / cross; // get unit distance along line p2 p3
        // code point B
        if (u2 >= 0 && u2 <= 1) { // is intercept on line p2, p3
            u1 = (v2.x * v3.y - v2.y * v3.x) / cross; // get unit distance on line p0, p1;
            // code point A
            return (u1 >= 0 && u1 <= 1); // return true if on line else false.
            // code point A end
        }
        return false; // no intercept;
        // code point B end
    }
    return lineSegmentsIntercept; // return function with closure for optimisation.
})();

Usage example

var p1 = {x: 100, y: 0}; // line 1
var p2 = {x: 120, y: 200};
var p3 = {x: 0, y: 100}; // line 2
var p4 = {x: 100, y: 120};
var areIntersepting = lineSegmentsIntercept (p1, p2, p3, p4); // true

The example is easily modified to return the point of intercept. Replace the code between code point A and A end with

if (u1 >= 0 && u1 <= 1) {
    return {
        x: p0.x + v1.x * u1,
        y: p0.y + v1.y * u1,
    };
}

Or if you want to get the intercept point on the lines, ignoring the line segments start and ends replace the code between code point B and B end with

return {
    x: p2.x + v2.x * u2,
    y: p2.y + v2.y * u2,
};

Both modifications will return false if there is no intercept or return the point of intercept as {x : xCoord, y : yCoord}

 

Are a line segment and circle colliding?


// [x0,y0] to [x1,y1] define a line segment
// [cx,cy] is circle centerpoint, cr is circle radius
function isCircleSegmentColliding(x0, y0, x1, y1, cx, cy, cr) {
    // 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 ((cx - x) * (cx - x) + (cy - y) * (cy - y) < cr * cr);
}

 

Are line segment and rectangle colliding?


// var rect={x:,y:,width:,height:};
// var line={x1:,y1:,x2:,y2:};
// Get interseting point of line segment & rectangle (if any)
function lineRectCollide(line, rect) {
    // p=line startpoint, p2=line endpoint
    var p = {
        x: line.x1,
        y: line.y1
    };
    var p2 = {
        x: line.x2,
        y: line.y2
    };
    // top rect line
    var q = {
        x: rect.x,
        y: rect.y
    };
    var q2 = {
        x: rect.x + rect.width,
        y: rect.y
    };
    if (lineSegmentsCollide(p, p2, q, q2)) {
        return true;
    }
    // right rect line
    var q = q2;
    var q2 = {
        x: rect.x + rect.width,
        y: rect.y + rect.height
    };
    if (lineSegmentsCollide(p, p2, q, q2)) {
        return true;
    }
    // bottom rect line
    var q = q2;
    var q2 = {
        x: rect.x,
        y: rect.y + rect.height
    };
    if (lineSegmentsCollide(p, p2, q, q2)) {
        return true;
    }
    // left rect line
    var q = q2;
    var q2 = {
        x: rect.x,
        y: rect.y
    };
    if (lineSegmentsCollide(p, p2, q, q2)) {
        return true;
    }
    // not intersecting with any of the 4 rect sides
    return (false);
}
// point object: {x:, y:}
// p0 & p1 form one segment, p2 & p3 form the second segment
// Get interseting point of 2 line segments (if any)
// Attribution: http://paulbourke.net/geometry/pointlineplane/
function lineSegmentsCollide(p0, p1, p2, p3) {
    var unknownA = (p3.x - p2.x) * (p0.y - p2.y) - (p3.y - p2.y) * (p0.x - p2.x);
    var unknownB = (p1.x - p0.x) * (p0.y - p2.y) - (p1.y - p0.y) * (p0.x - p2.x);
    var denominator = (p3.y - p2.y) * (p1.x - p0.x) - (p3.x - p2.x) * (p1.y - p0.y);
    // Test if Coincident
    // If the denominator and numerator for the ua and ub are 0
    // then the two lines are coincident.
    if (unknownA == 0 && unknownB == 0 && denominator == 0) {
        return (null);
    }
    // Test if Parallel
    // If the denominator for the equations for ua and ub is 0
    // then the two lines are parallel.
    if (denominator == 0) return null;
    // test if line segments are colliding
    unknownA /= denominator;
    unknownB /= denominator;
    var isIntersecting = (unknownA >= 0 && unknownA <= 1 && unknownB >= 0 && unknownB <= 1)
    return (isIntersecting);
}

 

Are 2 convex polygons colliding?


Use the Separating Axis Theorem to determine if 2 convex polygons are intersecting

// polygon objects are an array of vertices forming the polygon
// var polygon1=[{x:100,y:100},{x:150,y:150},{x:50,y:150},...];
// THE POLYGONS MUST BE CONVEX
// return true if the 2 polygons are colliding
function convexPolygonsCollide(a, b) {
    var polygons = [a, b];
    var minA, maxA, projected, i, i1, j, minB, maxB;
    for (i = 0; i < polygons.length; i++) {
        // for each polygon, look at each edge of the polygon, and determine if it separates
        // the two shapes
        var polygon = polygons[i];
        for (i1 = 0; i1 < polygon.length; i1++) {
            // grab 2 vertices to create an edge
            var i2 = (i1 + 1) % polygon.length;
            var p1 = polygon[i1];
            var p2 = polygon[i2];
            // find the line perpendicular to this edge
            var normal = {
                x: p2.y - p1.y,
                y: p1.x - p2.x
            };
            minA = maxA = undefined;
            // for each vertex in the first shape, project it onto the line perpendicular to the
            edge
            // and keep track of the min and max of these values
            for (j = 0; j < a.length; j++) {
                projected = normal.x * a[j].x + normal.y * a[j].y;
                if (minA == undefined || projected < minA) {
                    minA = projected;
                }
                if (maxA == undefined || projected > maxA) {
                    maxA = projected;
                }
            }
            // for each vertex in the second shape, project it onto the line perpendicular to the
            edge
            // and keep track of the min and max of these values
            minB = maxB = undefined;
            for (j = 0; j < b.length; j++) {
                projected = normal.x * b[j].x + normal.y * b[j].y;
                if (minB == undefined || projected < minB) {
                    minB = projected;
                }
                if (maxB == undefined || projected > maxB) {
                    maxB = projected;
                }
            }
            // if there is no overlap between the projects, the edge we are looking at separates the
            two
            // polygons, and we know there is no overlap
            if (maxA < minB || maxB < minA) {
                return false;
            }
        }
    }
    return true;
};

 

Is an X,Y point inside an arc?


Tests if the [x,y] point is inside a closed arc.

var arc = {
    cx: 150,
    cy: 150,
    innerRadius: 75,
    outerRadius: 100,
    startAngle: 0,
    endAngle: Math.PI
}

function isPointInArc(x, y, arc) {
    var dx = x - arc.cx;
    var dy = y - arc.cy;
    var dxy = dx * dx + dy * dy;
    var rrOuter = arc.outerRadius * arc.outerRadius;
    var rrInner = arc.innerRadius * arc.innerRadius;
    if (dxy < rrInner || dxy > rrOuter) {
        return (false);
    }
    var angle = (Math.atan2(dy, dx) + PI2) % PI2;
    return (angle >= arc.startAngle && angle <= arc.endAngle);
}

 

Is an X,Y point inside a wedge?


Tests if the [x,y] point is inside a wedge.

// wedge objects: {cx:,cy:,radius:,startAngle:,endAngle:}
// var wedge={
// cx:150, cy:150, // centerpoint
// radius:100,
// startAngle:0, endAngle:Math.PI
// }
// Return true if the x,y point is inside the closed wedge
function isPointInWedge(x, y, wedge) {
    var PI2 = Math.PI * 2;
    var dx = x - wedge.cx;
    var dy = y - wedge.cy;
    var rr = wedge.radius * wedge.radius;
    if (dx * dx + dy * dy > rr) {
        return (false);
    }
    var angle = (Math.atan2(dy, dx) + PI2) % PI2;
    return (angle >= wedge.startAngle && angle <= wedge.endAngle);
}

 

Is an X,Y point inside a circle?


Tests if an [x,y] point is inside a circle.

// circle objects: {cx:,cy:,radius:,startAngle:,endAngle:}
// var circle={
// cx:150, cy:150, // centerpoint
// radius:100,
// }
// Return true if the x,y point is inside the circle
function isPointInCircle(x, y, circle) {
    var dx = x - circle.cx;
    var dy = y - circle.cy;
    return (dx * dx + dy * dy < circle.radius * circle.radius);
}

 

Is an X,Y point inside a rectangle?


Tests if an [x,y] point is inside a rectangle.

// rectangle objects: {x:, y:, width:, height: }
// var rect={x:10, y:15, width:25, height:20}
// Return true if the x,y point is inside the rectangle
function isPointInRectangle(x, y, rect) {
    return (x > rect.x && x < rect.x + rect.width && y > rect.y && y < rect.y + rect.height);
}

ATutorialHub Related Guide

Comments (8)

Leave a Comment

Your email address will not be published. Required fields are marked*

User Comments

html tutorial comments

panduranga gupta

2021-07-05 07:03:13

good website for learning and help me a lot

html tutorial comments

raju

2021-09-25 14:58:47

The awsome website i am looking like for a long time, good work atutorialhub team keep doing

html tutorial comments

Shivani

2021-09-01 15:03:56

Learning a lot from the courses present on atutorialhub. The courses are very well explained. Great experience

html tutorial comments

Harshitha

2021-09-10 15:05:45

It is very helpful to students and easy to learn the concepts

html tutorial comments

Sowmya

2021-09-14 15:06:41

Great job Tutorials are easy to understand Please make use of it

html tutorial comments

Zain Khan

2021-09-18 15:07:23

Great content and customized courses.

html tutorial comments

Rudrakshi Bhatt

2021-09-09 15:08:10

Well structured coursed and explained really well!

html tutorial comments

Pavana Somashekar

2021-09-11 15:09:08

Good platform for beginners and learn a lot on this website