I'm trying to make a ball bounce off some obstacles after a bounding box + pixel by pixel collision. Somehow, sometimes the ball is not going in the direction it is supposed to be.
If the ball is following the red arrow, it is supposed to follow the green arrow after that. What happens is that sometimes it just goes back around (orange arrow). The same happens when going up on this wall, or even in the left wall.
Here is the collision and reflection code
isPixelCollision(element) {
var x = Math.round(this.pos.x),
y = Math.round(this.pos.y),
x2 = Math.round(element.pos.x),
y2 = Math.round(element.pos.y);
var w = this.width,
h = this.height,
w2 = element.width,
h2 = element.height;
// find the top left and bottom right corners of overlapping area
var xMin = Math.max(x, x2),
yMin = Math.max(y, y2),
xMax = Math.min(x + w, x2 + w2),
yMax = Math.min(y + h, y2 + h2);
// Sanity collision check, we ensure that the top-left corner is both
// above and to the left of the bottom-right corner.
if (xMin >= xMax || yMin >= yMax) {
return false;
}
var xDiff = xMax - xMin,
yDiff = yMax - yMin;
// get the pixels out from the images
var pixels = this.imgData.data,
pixels2 = element.imgData.data;
// if the area is really small,
// then just perform a normal image collision check
if (xDiff < 4 && yDiff < 4) {
for (var pixelX = xMin; pixelX < xMax; pixelX++) {
for (var pixelY = yMin; pixelY < yMax; pixelY++) {
if ((pixels[((pixelX - x) + (pixelY - y) * w) * 4 + 3] !== 0) && (pixels2[((pixelX - x2) + element.width * (element.actual - 1) + (pixelY - y2) * w2 * element.total) * 4 + 3] !== 0)) {
console.log("Small Collision\n");
var vector = {
x: (pixelX - Math.floor(this.pos.x + (this.width / 2))),
y: -(pixelY - Math.floor(this.pos.y + (this.height / 2)))
};
if (element.constructor.name != 'Light')
this.angle = (Math.atan2(vector.y, vector.x) - Math.PI) * (180 / Math.PI);
else {
this.speed += 50;
}
return true;
}
}
}
} else {
var incX = xDiff / 3.0,
incY = yDiff / 3.0;
incX = (~~incX === incX) ? incX : (incX + 1 | 0);
incY = (~~incY === incY) ? incY : (incY + 1 | 0);
for (var offsetY = 0; offsetY < incY; offsetY++) {
for (var offsetX = 0; offsetX < incX; offsetX++) {
for (var pixelY = yMin + offsetY; pixelY < yMax; pixelY += incY) {
for (var pixelX = xMin + offsetX; pixelX < xMax; pixelX += incX) {
if ((pixels[((pixelX - x) + (pixelY - y) * w) * 4 + 3] !== 0) && (pixels2[((pixelX - x2) + element.width * (element.actual - 1) + (pixelY - y2) * w2 * element.total) * 4 + 3] !== 0)) {
var vector = {
x: (pixelX - Math.floor(this.pos.x + (this.width / 2))),
y: -(pixelY - Math.floor(this.pos.y + (this.height / 2)))
};
console.log("Big Collision");
if (element.constructor.name != 'Light')
this.angle = (Math.atan2(vector.y, vector.x) - Math.PI) * (180 / Math.PI);
else {
if (this.speed < 500) this.speed += 50;
}
return true;
}
}
}
}
}
}
return false;
}
This is a more mathematical way of doing it that I tried, but works even worse than the one before
//Normal Vector
var normal = {
x: (pixelX - (this.imgData.width / 2)),
y: -(pixelY - (this.imgData.height / 2))
};
//Normalize the vetor
var norm = Math.sqrt(normal.x * normal.x + normal.y * normal.y);
if (norm != 0) {
normal.x = normal.x / norm;
normal.y = normal.y / norm;
}
var n_rad = Math.atan2(normal.y, normal.x);
var n_deg = (n_rad + Math.PI) * 180 / Math.PI;
console.log("Vetor Normal -> (" + normal.x + ", " + normal.y + ") , Angulo: " + n_deg);
//Velocity vector
var velocity = {
x: Math.cos((this.angle * Math.PI / 180) - Math.PI),
y: Math.sin((this.angle * Math.PI / 180) - Math.PI)
};
console.log("Vetor Velocidade -> (" + velocity.x + ", " + velocity.y + ") , Angulo: " + this.angle);
//Vetor Reflexao
var ndotv = normal.x * velocity.x + normal.y * velocity.y;
var reflection = {
x: -2 * ndotv * normal.x + velocity.x,
y: -2 * ndotv * normal.y + velocity.y
};
var r_rad = Math.atan2(reflection.y, reflection.x);
var r_deg = (r_rad + Math.PI) * 180 / Math.PI;
console.log("Vetor Reflexao -> (" + reflection.x + ", " + reflection.y + ") , Angulo: " + r_deg);
this.angle = r_deg;