0

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 :)

Werewolve
  • 2,448
  • 5
  • 24
  • 38
  • 1. add more info: is the ball always sliding? or can it jump/free fall to simulate ball inside device while moving it? 2. for first option use circle equation for the second D`Lambert equations + Circle surface collisions (on colision miror speed vector and reduce it by dampening coefficient) for extreme sliding you can also substract the normal direction speed on collision to avoid any jumps – Spektre Oct 06 '14 at 17:58
  • It can free move inside the bigger ball! I don't want bouncing or something like this. Only if you rotate the device and the ball is on the border, that it slides along the inner side. – Werewolve Oct 06 '14 at 18:59
  • from your comment this is not looking like physicaly correct simulation so I would remove the Physics tag and use geometry,math,vector and maybe graphics,circle tags instead but I can be misinterpreting something ... – Spektre Oct 06 '14 at 19:30

1 Answers1

3

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...)

Community
  • 1
  • 1
Spektre
  • 49,595
  • 11
  • 110
  • 380