So I have some problems getting 2d collision detection to work. The checking if two objects intersect isn't where my problem is, but rather getting the object to only move up to the obstacle and no further.
My attempt on detecting collision goes like this:
I'm trying to calculate the distance the object can move before hitting an obstacle, and then only move it that far. To do this I take the velocity of my object and couples it with the four corners in the rectangle, resulting in four lines. I then check if any of these lines intersect with the obstacles lines. If there is an intersection, I find which of the lines is shortened the most by this intersection point, and use that to determine the new 'highest possible length before it hits' and replace the objects velocity with that.
Right now the object gets stuck in the obstacles, and I haven't got a clue to where I should start looking for the problem.
The code for finding the intersection is from this: How do you detect where two line segments intersect? - I'm aware that I have a bit of redundancy here.
static linesIntersect(l1: cLine, l2: cLine): boolean { //returns true if the lines intersect.
var s1_x = l1.p2.x - l1.p1.x;
var s1_y = l1.p2.y - l1.p1.y;
var s2_x = l2.p2.x - l2.p1.x;
var s2_y = l2.p2.y - l2.p1.y;
var s = (-s1_y * (l1.p1.x - l2.p1.x) + s1_x * (l1.p1.y - l2.p1.y)) / (-s2_x * s1_y + s1_x * s2_y);
var t = (s2_x * (l1.p1.y - l2.p1.y) - s2_y * (l1.p1.x - l2.p1.x)) / (-s2_x * s1_y + s1_x * s2_y);
if ((s >= 0) && (s <= 1) && (t >= 0) && (t <= 1)) { return true; }
else { return false; }
}
static linesIntersection(l1: cLine, l2: cLine): cPoint { //returns the point in which the lines intersect.
var s1_x = l1.p2.x - l1.p1.x;
var s1_y = l1.p2.y - l1.p1.y;
var s2_x = l2.p2.x - l2.p1.x;
var s2_y = l2.p2.y - l2.p1.y;
var s = (-s1_y * (l1.p1.x - l2.p1.x) + s1_x * (l1.p1.y - l2.p1.y)) / (-s2_x * s1_y + s1_x * s2_y);
var t = (s2_x * (l1.p1.y - l2.p1.y) - s2_y * (l1.p1.x - l2.p1.x)) / (-s2_x * s1_y + s1_x * s2_y);
return new cPoint(l1.p1.x + (t * s1_x), l1.p1.y + (t * s1_y));
}
static possibleIntersectionLines(cElements: cElement[], player: cElement): cLine[] {
var possibleLines: cLine[] = []; //All elements 4 lines (as I'm only working with rectangles at the moment
for (var i = 0; i < cElements.length; i++) { //Run through all elements
if (cElements[i] != player) { //but not itself
var newPossibleLines = possibleLines.concat(cElements[i].sides); //And add these lines to an array.
possibleLines = newPossibleLines;
}
}
return possibleLines;
}
static ModifiedVelocityIfPlayerCollideInNextFrame(cElements: cElement[], player: cElement): Vector { //Return a new vector which indicate how long the player can move before hitting an object.
var cLinesToCheck = Collission.possibleIntersectionLines(cElements, player); //Get all the lines which could be in the way.
var playerLines = [player.lineAB, player.lineBC, player.lineCD, player.lineDA]; //Get the players lines.
var maxVelocity = player.velocity; //Get the current velocity of the player.
for (var i = 0; i < cLinesToCheck.length; i++) { //Check all the element's lines.
for (var j = 0; j < playerLines.length; j++) { //against the player's lines.
if (Collission.linesIntersect(playerLines[j], cLinesToCheck[i])) { //If there is an collission
var collissionPoint = Collission.linesIntersection(playerLines[j], cLinesToCheck[i]); //Get the Collission point
var possibleMaxVelocity = new Vector(collissionPoint.x - playerLines[j].p1.x, collissionPoint.y - playerLines[j].p1.y); //Create a new vector out of it.
if (maxVelocity.Length > possibleMaxVelocity.Length) maxVelocity = possibleMaxVelocity; //If it's shorter than the current velocity, set the current velocity to the new value.
}
}
}
return maxVelocity;
}
I should get my object classes streamlined in some way, but haven't figured out how yet. But for now they look like this:
class cPoint {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
class cLine {
p1: cPoint;
p2: cPoint;
constructor(p1: cPoint, p2: cPoint) {
this.p1 = p1;
this.p2 = p2;
}
}
class cElement extends Particle {
color: string = "white";
width: number;
height: number;
constructor(x: number, y: number, w: number, h: number, color?) {
super(x, y);
if (typeof color !== 'undefined') this.color = color;
this.width = w;
this.height = h;
}
get lowestX() {
if (this.position.X < this.position.X + this.width) return this.position.X;
return this.position.X + this.width
}
get highestX() {
if (this.position.X > this.position.X + this.width) return this.position.X;
return this.position.X + this.width
}
get lowestY() {
if (this.position.Y < this.position.Y + this.height) return this.position.Y;
return this.position.Y + this.height
}
get highestY() {
if (this.position.Y > this.position.Y + this.height) return this.position.Y;
return this.position.Y + this.height
}
get pointA(): cPoint { return new cPoint(this.lowestX, this.lowestY); } //Upper left corner.
get pointB(): cPoint { return new cPoint(this.highestX, this.lowestY); } //Upper right corner.
get pointC(): cPoint { return new cPoint(this.highestX, this.highestY); } //Lower right corner.
get pointD(): cPoint { return new cPoint(this.lowestX, this.highestY); } //Lower left corner.
get lineAB(): cLine { return new cLine(this.pointA, this.pointB); }
get lineBC(): cLine { return new cLine(this.pointB, this.pointC); }
get lineCD(): cLine { return new cLine(this.pointC, this.pointD); }
get lineDA(): cLine { return new cLine(this.pointD, this.pointA); }
get sides(): cLine[] { return [this.lineAB, this.lineBC, this.lineCD, this.lineDA]; } // An array with the 4 sides of the element.
get lineAdA(): cLine { return new cLine(this.pointA, new cPoint(this.pointA.x + this.velocity.X, this.pointA.y + this.velocity.Y)); }
get lineBdB(): cLine { return new cLine(this.pointB, new cPoint(this.pointB.x + this.velocity.X, this.pointB.y + this.velocity.Y)); }
get lineCdC(): cLine { return new cLine(this.pointC, new cPoint(this.pointC.x + this.velocity.X, this.pointC.y + this.velocity.Y)); }
get lineDdD(): cLine { return new cLine(this.pointD, new cPoint(this.pointD.x + this.velocity.X, this.pointD.y + this.velocity.Y)); }
}
Thanks in advance for your time.