avorum
avorum

Reputation: 2293

error with collision detection in a scribble game

So I'm trying to get collision detection between a circular player and a line in a scribble game (using as3). For this I know 3 points, the endpoints of the line and the top-left of the image containing the circle.

//Detects collision between a given player and a given line
public function detectCollision(p:Player, l:Line): Boolean{
    //First create a line running parallel to l that runs through the center of p
    //p hereby referred to by "the player"
    //l hereby referred to by "the offending line"
    //start by finding the center of p
    var pCenter:Point = new Point(p.x + 38, p.y + 38); //38 = radius
    //now find the angle of the offending line (in Q1 or Q2)
    var theta:Number = Math.atan2(l.y2 - l.y1, l.x2 - l.x1);
    //now make a line within the player that conforms to this angle
    var paraLine:Line = new Line(pCenter.x - Math.cos(theta) * 38, pCenter.y - Math.sin(theta) * 38, pCenter.x + Math.cos(theta) * 38, pCenter.y + Math.sin(theta) * 38);

    //Next we're going to create a perpendicular line in the circle pointing at the offending line
    var perpenLine:Line = new Line(pCenter.x - Math.cos(theta) * 38, pCenter.y + Math.sin(theta) * 38, pCenter.x + Math.cos(theta) * 38, pCenter.y + Math.sin(theta) * 38);
    var closestOnCircle:Point = new Point(pCenter.x - Math.cos(theta) * 38, pCenter.y + Math.sin(theta) * 38); //this is the point on the circle closest to the offending line

    //Now to find where the line running perpendicular to the offending line through the center of the player intersects with the offending line
    //this is done by using algebra
    //y = mx + b (perpenLine)
    //y = nx + c (offending line)
    //mx + b = nx + c
    //b - c = (n - m)x
    //x = (b - c) / (n - m)
    var xIntercept:Number = (perpenLine.getOffset() - l.getOffset()) / (l.getSlope() - perpenLine.getSlope());
    var pointOnLine:Point = new Point(xIntercept, xIntercept * l.getSlope() + l.getOffset()); //point on the line where the intersection happens

    //Finally whether a collision has occurred is calculated
    //this is done by seeing if both pCenter and closestOnCircle are on the same side of pointOnLine
    if((pCenter.y > pointOnLine.y && closestOnCircle.y > pointOnLine.y) || (pCenter.y < pointOnLine.y && closestOnCircle.y < pointOnLine.y))
        return false;
    else
        return true;
}

The code is somewhat complex and I'm not great at trigonometry and I've been unable to find out why it's not working. The player starts at the top of the screen and the moment the line appears it registers a collision. If there's any questions please ask, I'd really like to figure this out. Thanks in advance.

Upvotes: 0

Views: 132

Answers (1)

Mikeb
Mikeb

Reputation: 6361

Seems like you could skip a couple of steps - there may be a more clever approach out there, but I don't think you need to calculate the angle theta.

The line from (x1, y1) to (x2, y2) has the slope m = (y2-y1)/(x2-x1); the line that connects the center of the circle (xc, yc) to the line in closest approach with be perpendicular to that slope (as you say) so it's slope is -1/m. Call the point where those lines meet (xi, yi). We can write yi = (xi - x1)*m + y1 (from the original line) and we can also write yi = (xi -xc)(-1/m) + yc. 2 equations, 2 unknowns, relatively straight forward to solve for xi and yi. Then simply determine the length of the line from the center of the circle to the intersection and if it is less than the radius (38) you are in contact.

Worth noting that this would look like a collision if you are in line with the infinite extension of the line but not on top of it, since we are only using two points to determine the whole line. If you need to not collide with this segment and pass around it, I would start with a simple bounding box collision test between the corners of the box around the circle and the box around the line before calculating the closest approach segment.

Upvotes: 2

Related Questions