Jump to content
  • Advertisement
Sign in to follow this  
TAkAw

Collision in a pinball style game

This topic is 4746 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey Guys! This is my first post. well here it goes: I have been working on this 2D graphics demo/game that is similar to a pinball machine. I have pinballs that bounce around and they collide with the window border and other polygons. I have now wanted to add collision between pinballs and cirle primitives, and eventually with other pinballs. I was just wondering if anyone has any good algorithms for calculating vector collision between a movin circle, and a stationary circle, as well as between 2 moving circles. When collision occurs the pinball should be reflected off the surface. Methods that include the trivial rejection of objects that obviously aren't going to be collided with would be preffered. Thanks a lot! [Edited by - TAkAw on July 22, 2005 11:08:04 PM]

Share this post


Link to post
Share on other sites
Advertisement
Quote:
I have been working on this 2D graphics demo/game that is similar to a pinball machine. I have pinballs that bounce around and they collide with the window border and other polygons. I have now wanted to add collision between pinballs and cirle primitives, and eventually with other pinballs. I was just wondering if anyone has any good algorithms for calculating vector collision between a movin circle, and a stationary circle, as well as between 2 moving circles. When collision occurs the pinball should be reflected off the surface. Methods that include the trivial rejection of objects that obviously aren't going to be collided with would be preffered. Thanks a lot!
Collision between moving circles and spheres is a pretty easy problem to solve. Call the circle center C, the radius r, and the velocity V. The circle center traces out the path C+tV over time, where t is the time parameter.

We are interested in the squared distance between the centers of two circles, 0 and 1. The function is:

f(t) = (D+tV)2

Where D = C0-C1 and V = V0-V1. Expanding gives:

f(t) = (V.V)t2+2(D.V)t+(D.D)

We are interested in the times at which the squared distance between the circles is exactly the squared sum of their radii. Thus we have:

(V.V)t2+2(V.D)t+(D.D) = (r0+r1)2

A quadratic which can be solved for the first time of intersection, if any. The coefficients also have geometric significance, which can be used for early outs. For further efficiency you could add a broad-phase step, but for a pinball game I doubt you'd need it.

You should probably double-check my math (I may have switched something around somewhere), but that's the general idea. Here's a simple example of swept circles in action:




[Edited by - jyk on August 15, 2005 12:00:33 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by jyk

(V.V)t2+(V.D)t+(D.D) = (r0+r1)2

A quadratic which can be solved for the first time of intersection, if any. The coefficients also have geometric significance, which can be used for early outs.


So I have this quadratic, and that gives me the time if intersection in the frame if there is one, but the quadratic gives a number that isn't necessarily between 0 and 1. which is needed to calc the new position. Mabye I just don't understand, please clarify if you can.

Share this post


Link to post
Share on other sites
Collisions outside the range [0, 1] can be ignored, as they occur either before or after the timestep.

I should clarify that this assumes V is the displacement vector for that frame. Another way to do it is to have V be in units per second, and use a time range of [0, frameTime] instead of [0, 1].

Does that help at all? Let me know if you need further clarification...

Share this post


Link to post
Share on other sites
ok so say the pinball moves 10 pixels per frame, and that time, t, is the result of the quadratic equation, and a collision has been confirmed, would the t you plug into the parametric position equation be scaled at all for how far the ball moves per frame, or should I just trivialy reject times that are outside [0, 1]?

Share this post


Link to post
Share on other sites
Let me try explaining it in a slightly different way. Forget for the moment about what V actually represents. The t you get from solving the quadratic tells you how far along V you got before a collision occured. If t < 0, the collision occured along negative V; in terms of time it occured 'in the past' and can be ignored. If t = .5, the circle made it halfway along V before colliding. If t = 1, it made it all the way along V before colliding. And so on.

In all cases you can ignore t < 0, so the lower bound for your time interval is always 0. The upper bound depends on what V represents.

If V is in units per second, then the upper bound is the elapsed time for that frame. For example, if your game runs at 60hz, the valid interval for t would be [0, 1/60]. In this case t is the 'actual' time at which the collision occured.

If V only represents the displacement over that frame, then the upper bound is 1, and the valid interval for t is [0, 1]. In this case t is the 'normalized' time of intersection.

In either case, as long as you use V consistently you can just plug t as-is into the parametric equation for motion to get your new position.

Now that I try to explain it, it is a little confusing. From your example (10 pixels per frame), it sounds like V is a displacement vector, in which case you should reject collisions outside the range [0, 1]. You can then simply update your position like this:

ball.position += t*V;

I don't know that I've explained this very well, so I'll be glad to offer further help if needed.

Share this post


Link to post
Share on other sites
yea that's great and I was able to implement collision with stationary circular pillars. I am still having trouble understanding how to determine collision between 2 moving pinballs. I assume it's similar to what I've already done, but not sure how to take it to the next step.

Share this post


Link to post
Share on other sites
Quote:
yea that's great and I was able to implement collision with stationary circular pillars. I am still having trouble understanding how to determine collision between 2 moving pinballs. I assume it's similar to what I've already done, but not sure how to take it to the next step.
You might go back and take another look at my first reply in this thread; the equation I gave actually does incorporate the velocities of both circles (that is, they can both be moving).

Share this post


Link to post
Share on other sites
Ok so i have pinball collision but It's still not quite right, It will work if both balls are going twoards one another (a head on collision) but if only one of the balls is colliding (from behind) I need to change the velocity of the ball that was collided into accordingly. I included my current source for the function, any suggestions?


void Pinball::PinballCollision(std::list<Pinball> balllist, bool& collision)
{
for (std::list<Pinball>::iterator iter = balllist.begin(); iter != balllist.end(); ++iter)
{

Vector2D b0(mCircle.GetCenter().GetX(), mCircle.GetCenter().GetY());
Vector2D q(iter->GetCircle().GetCenter().GetX(), iter->GetCircle().GetCenter().GetY());
Vector2D v(mVelocity);
Vector2D d(q - b0);

//parts of the quadratic
float r(mCircle.GetRadius() + iter->GetCircle().GetRadius());
float a(v * v);
float b(v * d * -2.0f);
float c(d * d - std::pow(r, 2));
float b2_4ac(std::pow(b, 2) - 4.0f * a * c);

if (b2_4ac >= 0)//the pinball does collide with the circle.
{
float pt = (-b + std::sqrt(b2_4ac)) / (2 * a);
float mt = (-b - std::sqrt(b2_4ac)) / (2 * a);
float t;
if (pt < mt)
{
//pt is the closest intersection of the circle.
t = pt;
}
else
{
//mt is the closest intersection of the circle, or the circle is grazed.
t = mt;
}
if ((t > 1) || t < 0)
{
continue;
}
Vector2D bh(b0 + v * t);
//reflect the ball
Vector2D n(bh - q);
mVelocity = (n * ((-2.0f * (v * n)) / (n * n))) + v;
collision = true;
}
}
}

Share this post


Link to post
Share on other sites
Here's some code you can look at for comparison. It doesn't actually adjust the objects' velocities, but returns all the information you need to do it yourself. It also returns valid information for both the swept and static case, which can be useful.


// --------------------------------------------------------------------------------------
template <class T> struct Sweep2
{
enum {STATIC,
STATIC_INVALID_NORMAL,
SWEPT};

int type;
T t;
Vector2<T> normal;
T distance;
int numPoints;
Vector2<T> points[2];
};
// --------------------------------------------------------------------------------------
template <class T> bool Circle2Circle2(
const Vector2<T> C0, // Circle 0 center
T r0, // Circle 0 radius
const Vector2<T> V0, // Circle 0 velocity
const Vector2<T> C1, // Circle 1 center
T r1, // Circle 1 radius
const Vector2<T> V1, // Circle 1 velocity
T tMax, // Max time
Sweep2<T>& sweep, // Output info
T epsilon = Math<T>::EPSILON) // Epsilon
{
// 0 is moving and 1 is stationary, and the normal points from 1 to 0
Vector2<T> d = C0 - C1;
T r = r0 + r1;
T c = d.Dot(d) - r * r;

// Swept
if (c > (T)0.0)
{
Vector2<T> V = V0 - V1;
T b = d.Dot(V);
if (b >= (T)0.0) // Circles moving apart
return false;

T a = V.Dot(V);
if (a < epsilon) // Relative velocity too small to solve robustly
return false;

T disc = b * b - a * c;
if (disc < (T)0.0) // Circles do not ever intersect
return false;

sweep.t = -b - Math<T>::Sqrt(disc);
if (sweep.t > tMax * a) // Circles intersect after max time
return false;

sweep.type = Sweep2<T>::SWEPT;
sweep.t /= a;
sweep.normal = Vector2<T>::Normalize(d + sweep.t * V);
sweep.numPoints = 1;
sweep.points[0] = (C0 + C1 + sweep.t * (V0 + V1) + (r1 - r0) * sweep.normal) * (T)0.5;
}
// Static
else
{
T l = d.Length();

// Invalid normal
if (l < epsilon)
{
sweep.type = Sweep2<T>::STATIC_INVALID_NORMAL;
sweep.distance = r;
}
// Valid normal
else
{
sweep.type = Sweep2<T>::STATIC;
sweep.normal = d / l;
sweep.distance = r - l;
}
}

return true;
}
// --------------------------------------------------------------------------------------

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!