javamathgame-physicsbounce

Calculate the bouncing angle for a ball/point


I'm building my own small game engine for learning. So basically pure Java. I have Lines which are defined by a start and endpoint (x and y coordinates)

Now I have a ball with a velocity vector. I want to "bounce" off the wall, which could positioned in any possible angle. How do I find out the new velocity vector after the collision happend? I know the point S, P1 and P2 (see image)

enter image description here

I thought about calculating the angle, and change the x and y components. But I can't find a way how to do this for all possible angles.

I could find many solutions for walls which are parallel to the canvas borders, but no general solution. How do "big" game engines handle this common problem?

edit:

My updated Vector class methods:

public static Vector bounce(Vector normal, Vector velocity) {
    Vector tmp = Vector.multiplication(2*Vector.dot(normal,velocity), normal);
    return Vector.addition(tmp, velocity);
}

public static Vector multiplication(double multi, Vector n) {
    Vector new_vector = new Vector(n.x * multi, n.y * multi);
    return new_vector;
}

public static double dot(Vector a, Vector b) {
    return a.x*b.x + a.y*b.y; // + a.z*b.z if you're in 3D
}

My test function:

@Test
   public void testBounce() {
        Vector normal_vector_corrected = new Vector(0, 1);
        Vector start_velocity = new Vector(3, -3);
        Vector bounced_vector = Vector.bounce(normal_vector_corrected, start_velocity);
        System.out.println("normal vector: "+normal_vector_corrected);
        System.out.println("start_velocity: "+start_velocity);
        System.out.println("bounced_vector "+bounced_vector);
    }

The output is this:

normal vector: <Vector x=0,00, y=1,00>
start_velocity: <Vector x=3,00, y=-3,00>
bounced_vector <Vector x=3,00, y=-9,00>

According to my calculations, bounced_vector should be x=3,y=3 instead. Where is my mistake? (My example as picture:)enter image description here

edit2: I found that it has to be return Vec.add(tmp, v);. Furthermore, I had to inverse the velocity vector.


Solution

  • The "bounced velocity vector" v' is obtained from the original velocity v and the surface normal unit vector n with 2(n . v)n + v where . stands for the vector dot product. This is usually called a reflection; the velocity vector is reflected across the surface normal.

    In case you're not familiar with the terminology, the surface normal is a vector that is perpendicular (at 90-degree angle) to the surface. A unit vector is a vector with length 1.

    enter image description here

    I assume you already have a class to represent vectors, called Vec, with methods to multiply a vector with a scalar and to add two vectors. You could write the bounce operation as:

    static Vec bounce(Vec n, Vec v) {
        Vec tmp = Vec.scalarMultiply(-2*Vec.dot(n,v), n);
        return Vec.add(tmp, v);
    }
    
    static double dot(Vec a, Vec b) {
        return a.x*b.x + a.y*b.y; // + a.z*b.z if you're in 3D
    }
    

    As for how to get the surface normal, that will depend on if you're in 2D or 3D. Assuming 2D, it's simple: if (x,y) is the vector from P1 to P2, then (-y,x) is perpendicular to it, and one unit normal would be:

    n = (-y/sqrt(x*x+y*y), x/sqrt(x*x+y*y))
    

    The other possible unit normal is -n. You would use one or the other depending on which side of the surface you are.

    You should store the normal vector with the geometry of the scene so you don't have to calculate it every time.