ID:153973
 
I've been fiddling with handling a ball bouncing arround the screen (and off of flat surfaces that are sides of rectangles where the rectangles are always larger than the ball). I have come up with several solutions to calculating if the ball needs to bounce, and where it needs to bounce but all of them require a lot of hard coding for each possible case which makes debugging painful.

I'm basically looking for a simpler way to do it or some tricks I can use.

My first approach was to take the circles current position and then draw two lines from it's edges to where it will be in its new position. I tried to use an estimation by using one of two sets of lines:
    A
__
/ \
D | | B
\__/
C

either I would make a line connecting the circles A points and another connecting their C points, or I would make a line connecting their two B points and two D points. A and C would be chosen if abs(dx) > abs(dy).

I then would then plug in the y and x values for the sides of the rectangle into those lines equations to see where they intersect, then test to make sure the intersections are within the bounds of the rectangle.

Testing those bounds depends on the side I chose, whether dx > 0, whether dy > 0 and whether abs(dx) > abs(dy), creating a decent sized headache for me.

A more accurate alternative would be to select the lines based upon the direction the circle is headed. If it were headed in the dy/dx direction then a point on the circle at dx/dy from it's center would be chosen instead of A,B,C, or D. That would have most of the same problems.

Another way is just to see if the closest part of the circles new position is inside the rectangle by making sure it's x coordinates are greater than the left side of the rectangle and less than the right side of the rectangle, then the same for the y. That creates the problem of telling which side to bounce off of and where on that side to bounce off of, which is doable, but also a headache.
English wrote:
I've been fiddling with handling a ball bouncing arround the screen (and off of flat surfaces that are sides of rectangles where the rectangles are always larger than the ball). I have come up with several solutions to calculating if the ball needs to bounce, and where it needs to bounce but all of them require a lot of hard coding for each possible case which makes debugging painful.

Welcome to my world.

I'm basically looking for a simpler way to do it or some tricks I can use.

My first approach was to take the circles current position and then draw two lines from it's edges to where it will be in its new position. I tried to use an estimation by using one of two sets of lines:
     A
__
/ \
D | | B
\__/
C

either I would make a line connecting the circles A points and another connecting their C points, or I would make a line connecting their two B points and two D points. A and C would be chosen if abs(dx) > abs(dy).

I then would then plug in the y and x values for the sides of the rectangle into those lines equations to see where they intersect, then test to make sure the intersections are within the bounds of the rectangle.

Testing those bounds depends on the side I chose, whether dx > 0, whether dy > 0 and whether abs(dx) > abs(dy), creating a decent sized headache for me.

A more accurate alternative would be to select the lines based upon the direction the circle is headed. If it were headed in the dy/dx direction then a point on the circle at dx/dy from it's center would be chosen instead of A,B,C, or D. That would have most of the same problems.

Another way is just to see if the closest part of the circles new position is inside the rectangle by making sure it's x coordinates are greater than the left side of the rectangle and less than the right side of the rectangle, then the same for the y. That creates the problem of telling which side to bounce off of and where on that side to bounce off of, which is doable, but also a headache.

Because you're only working with circles, your problem is actually a lot simpler than the ones I was having. I think you'll find this site handy:

http://www.gamedev.net/reference/articles/article1026.asp

It didn't help me a whole lot (except dealing with wall corners), but it could be just what you need.

Lummox JR
In response to Lummox JR
I'll have to read through it again and go through the steps myself on paper, but it looks like that is exactly what I needed. It should even be simpler than what they present because I only have to worry about horizontal and vertical lines so the vectors should become simpler.

Anyway, I feel a small portion of your pain :p
In response to English
English wrote:
I'll have to read through it again and go through the steps myself on paper, but it looks like that is exactly what I needed. It should even be simpler than what they present because I only have to worry about horizontal and vertical lines so the vectors should become simpler.

Glad I could help.
The vectors will indeed be much simpler for you with horizontal and vertical lines.

I didn't find the article of much use to me, because it really glossed over the problem of solving for an ellipse; it treated the ellipsoid as merely stretched, but not rotating. Since all the equations were based on solving for the time of intersection, this wouldn't work. (The equation is quite complex for a rotating ellipse.) But it did help in figuring out how to handle wall collisions.

Lummox JR
In response to Lummox JR
Well, I had the general idea then tried to pick apart his examples and understand the psuedo code calculations, but his descriptions of how to actually perform the calculations (and why they work) are vague at best.

Here is his first example:

Before we can really dig in, we’ll need to determine the intersection of a ray with a plane. Here’s some pseudo code:

// Inputs: plane origin, plane normal, ray origin ray vector.
// NOTE: both vectors are assumed to be normalized


double intersect(Point pOrigin, Vector pNormal, Point rOrigin, Vector rVector)
{
double d = -(planeNormal * planeOrigin);
double numer = planeNormal * rayOrigin + d;
double denom = planeNormal * rayVector;
return -(numer / denom);
}


I sketched out an example plane and ray, then checked the projections etc. but it is far from obvious that this should work. Do you have any other resources that explain those sorts of calculations using vectors? I can do the calculations using lines and such but that is the ugliness I am hoping to avoid (not ugly in this case, but gets semi-ugly when the circle is involved).
In response to English
English wrote:
Well, I had the general idea then tried to pick apart his examples and understand the psuedo code calculations, but his descriptions of how to actually perform the calculations (and why they work) are vague at best.

Indeed. The code at the end should be a little more robust, but I know what you mean.

double intersect(Point pOrigin, Vector pNormal, Point rOrigin, Vector rVector)
{
double d = -(planeNormal * planeOrigin);
double numer = planeNormal * rayOrigin + d;
double denom = planeNormal * rayVector;
return -(numer / denom);
}

I sketched out an example plane and ray, then checked the projections etc. but it is far from obvious that this should work. Do you have any other resources that explain those sorts of calculations using vectors? I can do the calculations using lines and such but that is the ugliness I am hoping to avoid (not ugly in this case, but gets semi-ugly when the circle is involved).

I would guess his Vector class is using * as a dot product. In this case, he's working from the plane equation and getting this:
nx*x + ny*y + nz*z + d = 0
The calculation for numer is then (sphere center - plane origin) . (plane normal). That is, the distance (* length of normal vector) from the plane to the sphere center in the direction of the plane normal is numer. Curious that he calculates d in a separate step; it makes a lot more sense to go with (center - origin).normal directly.
denom is calculated much the same way, except it's a "ray direction" vector in the direction of the plane normal, * the normal vector length.

Actually I follow his calculations pretty well here, but I think he's solving the wrong problem when he says the ray direction and plane normal are normalized. They don't have to be. The result of his calculations is this:
t = -(rOrigin-pOrigin).pNormal / rVector.pNormal
t = -(c-o).n / v.n
I replaced these so that o and n represent the plane origin and normal, while c and v represent the sphere center and velocity.
We actually care about the size of the v vector because that influences the time of impact, so normalizing it would be useless. And the size of the plane normal n doesn't matter, because it cancels out.

Now this equation solves for when the center touches the plane, not when the edge touches. So I'm going to introduce a new var, r, for the circle/sphere radius. The goal is that (c+vt-o).n/|n| (distance from the plane, using a unit normal vector) should equal ±r. The vt term is because the center of your sphere/circle is moving, and we want to solve for t. Thus:
(c+vt-o).n = r*sqrt(n.n)
[(c+vt-o).n]^2 = r^2*n.n
[(c-o).n+t(v.n)]^2 = r^2*n.n
(v.n)^2t^2 + 2(v.n)[(c-o).n]t + [(c-o).n]^2-r^2*n.n = 0
After calculating a few of these constants, we can solve for t.
var/vn = v.x*n.x + v.y*n.y + v.z*n.z
var/cn = (c.x-o.x)*n.x + (c.y-o.y)*n.y + (c.z-o.z)*n.z
var/nn = n.x*n.x + n.y*n.y + n.z*n.z
var/rnsq = r*r*nn
// quadratic equation constants ax^2+bx+c=0
// in this case we'll just find b/2 since it's easier
var/a = vn*vn
var/b2 = vn*cn
var/c = cn*cn - rnsq
var/disc = b2*b2 - a*c // (b^2-4ac)/4
if(disc<0)
... // no intersection
var/cons = -b2/a // = -(b/2)/a = -b/2a
disc = sqrt(disc)/a // = sqrt(b^2-4ac)/2a
var/t0 = cons - disc
var/t1 = cons + disc
That should give you the points in time where a circle intersects a line, or a sphere a plane. You should ignore any case where t0<0, since that means the circle is past the line or already intersecting it.

To find where the circle intersects the line, use your t:
P = (c+vt)-r*n/|n|
P = (c+vt)-r*n/sqrt(nn)

var/nlen = sqrt(nn)
P.x = (c.x + v.x*t) - r*n.x/nlen
P.y = (c.y + v.y*t) - r*n.y/nlen
P.z = (c.z + v.z*t) - r*n.z/nlen
This information is useful for knowing if you're on the line segment or not.

Also helpful will be to solve for the time where a circle touches a particular point. That's not hard, though, since all you have to do is put the point on the circle:
|c+vt-o| = r
(c+vt-o).(c+vt-o) = r*r
(v.v)t^2 + 2[v.(c-o)]t + (c-o).(c-0) - r*r = 0

Lummox JR