Accelerometer - Rolling Ball in Ball


i want to use the phones accelerometer for rolling a Ball in a Ball. The movement works correctly, the problem is that when the ball hits the Wall. How can i get a smooth rolling animation that the ball slides along the inner side of the bigger ball?

Ball in Ball

This is my current code to move the Ball and check the intersection:

    onSuccess: function(acceleration) {
        var xPos = this.xPos + (-1 * (acceleration.x * 0.5));
        var yPos = this.yPos + (acceleration.y * 0.5);

        var intersect = this.intersection(xPos + 32, 
                                          yPos + 32, 
                                          32, 
                                          self.canvas.width * 0.5, 
                                          self.canvas.height * 0.5, 
                                          self.canvas.width * 0.5);
        if (!intersect) {
            this.yPos = yPos;
            this.xPos = xPos;
        }

        this.cnv.clearRect(0.0, 0.0, this.canvas.width, this.canvas.height);    
        this.cnv.drawImage(this.target, this.xPos, this.yPos);
    },

    intersection: function(x0, y0, r0, x1, y1, r1) {

        var a, dx, dy, d, h, rx, ry;
        var x2, y2;

        /* dx and dy are the vertical and horizontal distances between
         * the circle centers.
         */
        dx = x1 - x0;
        dy = y1 - y0;

        /* Determine the straight-line distance between the centers. */
        d = Math.sqrt((dy*dy) + (dx*dx));

        /* Check for solvability. */
        if (d > (r0 + r1)) {
            /* no solution. circles do not intersect. */
            return false;
        }
        if (d < Math.abs(r0 - r1)) {
            /* no solution. one circle is contained in the other */
            return false;
        }

        /* 'point 2' is the point where the line through the circle
         * intersection points crosses the line between the circle
         * centers.  
         */

        /* Determine the distance from point 0 to point 2. */
        a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ;

        /* Determine the coordinates of point 2. */
        x2 = x0 + (dx * a/d);
        y2 = y0 + (dy * a/d);

        /* Determine the distance from point 2 to either of the
         * intersection points.
         */
        h = Math.sqrt((r0*r0) - (a*a));

        /* Now determine the offsets of the intersection points from
         * point 2.
         */
        rx = -dy * (h/d);
        ry = dx * (h/d);

        /* Determine the absolute intersection points. */
        var xi = x2 + rx;
        var xi_prime = x2 - rx;
        var yi = y2 + ry;
        var yi_prime = y2 - ry;

        return [xi, xi_prime, yi, yi_prime];
    }
};

Thanks for Helping :)


Answers:


in just sliding case use parametric circle equation

x=x0+r*cos(a)
y=y0+r*sin(a)

where:

  • x0,y0 is the big circle center
  • r = R0-R1
  • R0 is big circle radius
  • R1 is small circle radius

Now the angle a

the simplest would be to place a=gravity directionso:

a=atanxy(acceleration.x,acceleration.y)

the atanxy is atan2 which is 4-quadrant arcus tangens. If you don't have it use mine

and correct the angle to your coordinate systems (maybe negate and or add some 90degree multiple)

[notes]

If you have compatible coordinate systems between screen and device accelerometer then just scale acceleration vector to size |r| and add (x0,y0) to it and you have the same result without any goniometric function ...

For proper simulation use D'ALembert equations + circle boundary

so the 2D movement is pretty easy:

// in some timer with interval dt [sec]
velocity.x+=acceleration.x*dt;
velocity.y+=acceleration.y*dt;
position.x+=velocity.x*dt;
position.y+=velocity.y*dt;

now if (|position-big_circle_center|>big_circle_radius) an collision occurred so when you do not want any bounce (all energy was absorbed) then:

position-=big_circle_center;
position*=big_circle_radius/|position|;
position+=big_circle_center;

Now you need remove the radial speed and left just tangent speed:

normal=position-big_circle_center; // normal vector to surface
normal*=dot(velocity,normal);      // this is the normal speed part
velocity-=normal;                  // now just tangential speed should be left

enter image description here

so after this just tangent (Yellow) part of velocity remains ... Hope I did not forget something (like make unit vector or +/- somewhere...)