简体   繁体   中英

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.

图片。

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.

Can you do bouncing off a straight wall of arbitrary angle? That should be the first step. (You may find that a polar representation of the velocity vector is easier to work with.)

Once you've got that working, it should be fairly straightforward: bouncing off a circle is like bouncing off a tangent of that circle that touches it at the point of contact.

You can calculate this tangent by observing that it's perpendicular to the radius vector in the point of contact (that is the vector that points from where the object is to the centre of the circle)

Is there a vector-based implementation of this, without relying on angles?

Yes, see 2-Dimensional Elastic Collisions without Trigonometry , illustrated in this KineticModel . Your implementation appears to be missing the tangential component. See Ensemble#collideAtoms() for details.

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 @nm 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM