Search code examples
javacollision-detectiongame-physics

Wanted to make an object bounce inside a circle, ended up making the object move along the rim of the circle


Here's the code in question:

public void calculate() {
        // Center of circle is at (250, 250).
        //THIS ALGORITHM IS NOW PROVEN TO BE WORSE THAN I FEARED...

        /*      What it does:
         *          Moves object around in a circle.
         *          Does not move the object towards the center.
         *          Object always stays on the rim of the circle.
         * 
         *      Algorithm I used. (DOES NOT WORK):
         *          N is normalized vector. 
         *          R = -2*(V dot N)*N + V
         */

        vx += Accelero.X * 0.1;
        vy += Accelero.Y * 0.1;
        double nx = x - 250;
        double ny = y - 250;
        double nd = Math.hypot(nx, ny);
        if (nd == 0)
            nd = 1;
        nx /= nd;
        ny /= nd;
        double dotProduct = vx * nx + vy * ny;
        vx += (float) (-2 * dotProduct * nx);
        vy += (float) (-2 * dotProduct * ny);
        x -= vx * 2;
        y -= vy * 2;
        vx *= 0.99;
        vy *= 0.99;
    }

And this is what happens.

Picture.

The black line you see is where the purple object (box) moves. It just so happens to be right on the circle line I drew with Canvas.drawCircle().

I don't understand why reflection didn't work. If an object is to hit a circular wall, shouldn't it reflect the object's direction of velocity, which is what the algorithm was meant to be? Or I used the wrong algorithm?

Any help is appreciated. Thanks in advance.


Solution

  • This is what I've got, and I'm going to share my findings to all of you.

    public void calculate() {
        // Center of circle is at (250, 250). Radius is 40.
        //THIS ALGORITHM IS PROVEN TO BE BETTER THAN I FEARED...
    
        /*      What it does:
         *          Moves object around in a circle, if object is 
         *              inside of circle.
         *          Does not move the object towards the center, 
         *              nor outwards. This is crucial.
         *          Object always stays on the rim of the circle, 
         *              if the collision detection allows it to.
         * 
         *      Algorithm I used. (DOES WORK, NOT EXPECTING THIS THOUGH.):
         *          N is normalized vector. 
         *          R = -2*(V dot N)*N + V
         */
    
    
    
        double nx = x - 250;
        double ny = y - 250;
        double nd = Math.hypot(nx, ny);
        if (nd < 40){
            vx += Accelero.X * 0.1;
            vy += Accelero.Y * 0.1;
            x -= vx;
            y -= vy;
            vx *= 0.9;
            vy *= 0.9;
            return;
        }
    
        vx += Accelero.X * 0.1;
        vy += Accelero.Y * 0.1;
    
    
        if (nd == 0)
            nd = 1;
        nx /= nd;
        ny /= nd;
        double dotProduct = vx * nx + vy * ny;
        vx += (float) (-2 * dotProduct * nx);
        vy += (float) (-2 * dotProduct * ny);
        x -= vx * 2;
        y -= vy * 2;
        vx *= 0.99;
        vy *= 0.99;
    }
    

    I embedded a collision detection inside my function, basically making this function not as efficient as possible. Ignore that, for it's not the main focus.

    The circle's radius is 40, the (x,y) position is (250,250).

    Only when the object is either on the circle, or further away from the center of circle, should we calculate the collision response, which is given by the algorithm R = -2*(V dot N)*N + V, where normal vector N is already normalized.

    The algorithm is indeed correct, it's the boolean condition of my collision detection is what causes the object to stay on the rim of the circle and go round-a-bout on it.

    I didn't say the other algorithm, which @trashgod had provided is wrong. It's because of some weird issue that somehow causes the object to move unusually. I would guess it's the API I'm using's fault, which it didn't allow doubles, but I may be incorrect. I just couldn't find the source of the problem. Which I'm also happy to not look into it further anymore.

    The collision detection boolean condition itself could change everything, if it was slightly altered. If it wasn't for @n.m. pointing that I somehow seemed to forget a minus sign (in this case, a NOT sign), I probably would never realized how trivial it would be.