Domanda

I'm trying to write a java mobile application (J2ME) and I got stuck with a problem: in my project there are moving circles called shots, and non moving circles called orbs. When a shot hits an orb, it should bounce off by classical physical laws. However I couldn't find any algorithm of this sort.

The movement of a shot is described by velocity on axis x and y (pixels/update). all the information about the circles is known: their location, radius and the speed (on axis x and y) of the shot.

Note: the orb does not start moving after the collision, it stays at its place. The collision is an elastic collision between the two while the orb remains static

here is the collision solution method in class Shot:

public void collision(Orb o)
{
    //the orb's center point
    Point oc=new Point(o.getTopLeft().x+o.getWidth()/2,o.getTopLeft().y+o.getWidth()/2);
    //the shot's center point
    Point sc=new Point(topLeft.x+width/2,topLeft.y+width/2);

    //variables vx and vy are the shot's velocity on axis x and y
    if(oc.x==sc.x)
    {
        vy=-vy;
        return ;
    }

    if(oc.y==sc.y)
    {
        vx=-vx;
        return ;
    }

    // o.getWidth() returns the orb's width, width is the shot's width

    double angle=0;  //here should be some sort of calculation of the shot's angle
    setAngle(angle);
}

public void setAngle(double angle)
{
    double v=Math.sqrt(vx*vx+vy*vy);
    vx=Math.cos(Math.toRadians(angle))*v;
    vy=-Math.sin(Math.toRadians(angle))*v;
}

thanks in advance for all helpers

È stato utile?

Soluzione

At the point of collision, momentum, angular momentum and energy are preserved. Set m1, m2 the masses of the disks, p1=(p1x,p1y), p2=(p2x,p2y) the positions of the centers of the disks at collition time, u1, u2 the velocities before and v1,v2 the velocities after collision. Then the conservation laws demand that

0 = m1*(u1-v1)+m2*(u2-v2)
0 = m1*cross(p1,u1-v1)+m2*cross(p2,u2-v2)
0 = m1*dot(u1-v1,u1+v1)+m2*dot(u2-v2,u2+v2)

Eliminate u2-v2 using the first equation

0 = m1*cross(p1-p2,u1-v1)
0 = m1*dot(u1-v1,u1+v1-u2-v2)

The first tells us that (u1-v1) and thus (u2-v2) is a multiple of (p1-p2), the impulse exchange is in the normal or radial direction, no tangential interaction. Conservation of impulse and energy now leads to a interaction constant a so that

u1-v1 = m2*a*(p1-p2)
u2-v2 = m1*a*(p2-p1)
0 = dot(m2*a*(p1-p2), 2*u1-m2*a*(p1-p2)-2*u2+m1*a*(p2-p1))

resulting in a condition for the non-zero interaction term a

2 * dot(p1-p2, u1-u2) = (m1+m2) * dot(p1-p2,p1-p2) * a

which can now be solved using the fraction

b = dot(p1-p2, u1-u2) / dot(p1-p2, p1-p2)

as

a = 2/(m1+m2) * b

v1 = u1 - 2 * m2/(m1+m2) * b * (p1-p2)
v2 = u2 - 2 * m1/(m1+m2) * b * (p2-p1)

To get the second disk stationary, set u2=0 and its mass m2 to be very large or infinite, then the second formula says v2=u2=0 and the first


v1 = u1 - 2 * dot(p1-p2, u1) / dot(p1-p2, p1-p2) * (p1-p2)


that is, v1 is the reflection of u1 on the plane that has (p1-p2) as its normal. Note that the point of collision is characterized by norm(p1-p2)=r1+r2 or

dot(p1-p2, p1-p2) = (r1+r2)^2

so that the denominator is already known from collision detection.


Per your code, oc{x,y} contains the center of the fixed disk or orb, sc{x,y} the center and {vx,vy} the velocity of the moving disk.

  1. Compute dc={sc.x-oc.x, sc.y-oc.y} and dist2=dc.x*dc.x+dc.y*dc.y

    1.a Check that sqrt(dist2) is sufficiently close to sc.radius+oc.radius. Common lore says that comparing the squares is more efficient. Fine-tune the location of the intersection point if dist2 is too small.

  2. Compute dot = dc.x*vx+dcy*vy and dot = dot/dist2

  3. Update vx = vx - 2*dot*dc.x, vy = vy - 2*dot*dc.y

The special cases are contained inside these formulas, e.g., for dc.y==0, that is, oc.y==sc.y one gets dot=vx/dc.x, so that vx=-vx, vy=vy results.

Altri suggerimenti

Considering that one circle is static I would say that including energy and momentum is redundant. The system's momentum will be preserved as long as the moving ball contains the same speed before and after the collision. Thus the only thing you need to change is the angle at which the ball is moving.

I know there's a lot of opinions against using trigonometric functions if you can solve the issue using vector math. However, once you know the contact point between the two circles, the trigonometric way of dealing with the issue is this simple:

dx = -dx; //Reverse direction
dy = -dy;
double speed = Math.sqrt(dx*dx + dy*dy);
double currentAngle = Math.atan2(dy, dx);

//The angle between the ball's center and the orbs center
double reflectionAngle = Math.atan2(oc.y - sc.y, oc.x - sc.x);
//The outcome of this "static" collision is just a angular reflection with preserved speed
double newAngle = 2*reflectionAngle - currentAngle;

dx = speed * Math.cos(newAngle); //Setting new velocity
dy = speed * Math.sin(newAngle);

Using the orb's coordinates in the calculation is an approximation that gains accuracy the closer your shot is to the actual impact point in time when this method is executed. Thus you might want to do one of the following:

  1. Replace the orb's coordinates by the actual point of impact (a tad more accurate)
  2. Replace the shot's coordinates by the position it has exactly when the impact will/did occur. This is the best scenario in respect to the outcome angle, however may lead to slight positional displacements compared to a fully realistic scenario.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top