I don't think so. What you can do though is to break up the path into a
series of discrete chunks. You don't have to do it like Bill97 says
though, checking the position every short interval of time, because the
only time the equation changes will be when it collides with something.
(Though if there are a lot of balls that might be the easiest way.)
Look at just one ball bouncing around for a minute. Let's set up a
couple variables:
- x will be the current x location of the ball (say that x is the
short distance)
- y is the current y position of the ball
- width is the x dimension of the table
- height is the y dimension of the table
- v is the velocity of the ball
- a is the angle the ball is traveling (0 will be positive x and no y;
90 is positive y and no x; I'm actually going to use v and a at the
very beginning then ignore them)
- t is the current time
The table is set with a corner at (0, 0) and extending into the first
quadrant. I'm using real coordinates, not the reversed y axis you see
in CG a lot. ;-)
Furthermore, we assume one of two things: either the ball has zero
radius or the variables width and height should be increased by the
radius, and the whole table offset by r/2 left and down. In other
words, if the ball is sitting at (0,0) it should be touching the left
and bottom sides, and if it is at (width, height) it is touching the
right and top sides.
If we ignore the edges, the position of the ball can be found as
follows (I'm gonna use a bunch of temporary variables from here on to
make this clearer to both me and you):
The x component of the velocity is vx = v*cos(a)
The y component of the velocity is vy = v*sin(a)
Thus x(t) = x + vx*t and y(t) = y + vy*t.
But this only holds until it hits the side, so we have to find when
this will occur:
If the ball will hit the right rail, it will happen at tr = (width -
x)/vx
If the ball will hit the left rail, it will happen at tl = -x/vx
Similarily tt = (height -y)/vy and tb = -y/vy
So we have these equations holding until t reaches reaches the minimum
of the appropriate x choice and the appropriate y choice:
tm = min( (vx > 0) ? tr : tl),
(vy > 0) ? tt : tb) );
At that point, it hits the rail(s) so we bounce it by flipping the
velocity of the appropriate direction(s):
if( tm == tl || tm == tr) vx = -vx;
if( tm == tt || tm == tb) vy = -vy;
(Note that these both might be true if it hits the exact corner, so you
can't use else if)
Then repeat. (You'll need to make allowances for vx or vy being 0.)
So we have an algorithm for computing the position at time t (I'm
assuming height and width are global constants):
pair<double, double> position(double t, double x, double y, double v,
double a)
{
double vx = v * cos(a);
double vy = v * sin(a);
double t_until; // tm above
do
{
if( t_until == t_left || t_until == t_right) vx = -vx;
if( t_until == t_top || t_until == t_bottom) vy = -vy;
double t_right = (width - x)/vx;
double t_left = -x/vx;
double t_top = (height - y)/vy;
double t_bottom = -y/vy;
t_until = min( (vx > 0) ? t_right : t_left),
(vy > 0) ? t_top : t_bottom) );
} while (t + t_until > t_max);
return make_pair( x + vx * t, y + vy * t);
}
(This won't work if a = 0, 90, 180, 270, ..., or if the initial
position is on a rail.)
The case for multiple balls is a (much more complicated) generalized
form of this. Here's an overview:
Instead of keeping just a x, y, v, and a (or alternately a vx and vy),
you will have a vector of each. (This would be a PERFECT use of a
valarray if I remember my STL right.) You'll then compute a vector of
t_right, t_left, t_top, and t_bottoms, and set t_until to the max over
all that. (Actually you don't need to do all that; you just need to
store the minimum as you compute them.)
But that's not all. Because you have to check collisions. My advice is
to start assuming the balls have radius 0. In addition to checking when
they hit rails, you'll have to check when every ball will hit every
other ball. So for n balls you'll have n(n-1)/2 (easy) systems to
solve. You'll have to consider the cases where they don't intersect
(will only happen once you fix the vx or vy = 0 bug above) or when at
least one ball is traveling away from the point of intersection. I'm
not sure of the equations for what happens when a collision occurs. But
I think what will happen is that the velocities of the balls will swap.
That is, if one ball with velocity vector <vx_1, vy_1> collides with a
ball with velocity vector <vx_2, vy_2>, after the collision the first
ball will have velocity <vx_2, vy_2> and the second <vx_1, vy_1>.
Adding balls that have some size complicates that part there. Because
now they collide before the trajectory lines cross, and you have to
find out how much before. My suggestion is to draw diagrams and try to
figure it out; it'll take a bit of trig. Just remember to consider the
case where the lines meet outside of the table but the balls hit each
other inside the borders. (That is, you can't ignore any of the pairs
because they meet outside the borders until you find out where the
balls actually hit.)
Then you've got the skeleton in of a good billards program. ;-) Next
you need to factor in friction. This will just complicate a couple of
the formulas (you'll have to integrate), and also cause vx and vy to
change from iteration to iteration, but won't substantially change the
solution.You'll have to deal with the situation where balls stop
moving. (With perfect numbers this won't happen, but eventually
roundoff will cause the probably value to be 0.)
Then you need to add English. This will change things quite a bit,
because now the balls don't travel in straight lines.
Anyway, have fun... ;-)