Game Development Stack Exchange is a question and answer site for professional and independent game developers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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.

The "bug"

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;
share|improve this question

What you need to do is to calculate the normal of the collision then reflect the impact vel across the collision normal: // r = v - 2 * dot(v, n) * n; r = result vel, v = impact vel, n = normal of collision.

share|improve this answer
    
Yeah, you're right, I kinda know the theory. How do i calculate the r, the v and the n, that's the big question for me. dot(v,n) I assume i do it like this var ndotv = normal.x * velocity.x + normal.y * velocity.y; – Pedro Caseiro May 17 '16 at 10:31
    
r is what you want, vel after bounce, vel is wat the obj vel is before collision. n you get from collision detection. For example, in your picture n is (-1,0). – user80667 May 17 '16 at 21:26

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.