EDIT: Rotation and dynamics is a go. If you guys are interested in the how, let me know.
I say to you, Yo.
Its been awhile since Ive been by TGC, but I figured I'd stop by and say hello, and share a neat little physics project Im working on. Its not in DBP, because I've found that object oriented languages work better for these massive scale projects.
Anyhoo, if you would like to take a physics journey with me, and explore the secrets of the universe, than read along! If you think physics is stupid and have no interest whatsoever in learning fun and exiting new things, then shove off.
I have set out to construct a physics engine to be able to boot up for any project I want to. The language I chose was C# utilizing the xna framework. Basically, I started by writing a polygon class, made up of Line classes, made up in turn by Vector2 classes (I actually rewrote the class as a Point class, but I think that was a stupid move). The first hurtle was to get polygon collision working, which wasn't too too bad. Ill post the code, but for those of you who don't read C lingo, Ill explain as well.
This is a method that determines if two line segments are intersecting. Using this, its pretty simple to see if a polygon made up of lines are intersecting. You just loop through all the lines in each one, checking for collision with the lines of the other.
The way this works, is to simply call a line by its definition of y = mx+b. Now, if you take one line's x, and plug it into the other line's equation, and the outcome is similar to what that equation would output with its own x, then the lines are intersecting. Ive given mine a .0001 margin of error I think, just by subtracting the test value from the real value, and if their difference is zero, then they are the same, but if they're only .00001 off, then there close enough.
Then you can just take the x and y coord and see if they lay withing the line segment bounds.
This method is really cool because there is no looping at all, which means its not that hard on the cpu. There is a special case for vertical lines at the bottom, because vertical lines have a slope of infinity.
public Boolean intersectWith(Line l)
{
float smallX, bigX;
if (points[0].data.X > points[1].data.X)
{
smallX = points[1].data.X;
bigX = points[0].data.X;
}
else
{
smallX = points[0].data.X;
bigX = points[1].data.X;
}
float smallXl, bigXl;
if (l.points[0].data.X > l.points[1].data.X)
{
smallXl = l.points[1].data.X;
bigXl = l.points[0].data.X;
}
else
{
smallXl = l.points[0].data.X;
bigXl = l.points[1].data.X;
}
float testX = -(b - l.b) / (slope - l.slope);
if (testX >= smallX && testX <= bigX && testX >= smallXl && testX <= bigXl)
{
if (Math.Abs(((slope * testX) + b) - ((l.slope * testX) + l.b)) < .0001f)
{
return true;
}
}
float smallY, bigY;
if (points[0].data.Y > points[1].data.Y)
{
smallY = points[1].data.Y;
bigY = points[0].data.Y;
}
else
{
smallY = points[0].data.Y;
bigY = points[1].data.Y;
}
float smallYl, bigYl;
if (l.points[0].data.Y > l.points[1].data.Y)
{
smallYl = l.points[1].data.Y;
bigYl = l.points[0].data.Y;
}
else
{
smallYl = l.points[0].data.Y;
bigYl = l.points[1].data.Y;
}
if (Math.Abs(slope).ToString().Equals("Infinity"))
{
if (points[0].data.X <= bigXl && points[0].data.X >= smallXl)
{
float testY = (l.slope * points[0].data.X) + l.b;
if (testY >= smallY && testY <= bigY)
return true;
}
}
return false;
}
Now that my polygons can intersect with one another, I need a good way to bounce them off each other. I started testing this using discs and such, or hockey pucks (as I like to call them). When two hockey pucks hit each other, they should bounce off at odd angles, sort of like pool balls. This is where the physics comes in.
in the simple case, lets ignore spinning, because that gets really funky. So for right now, were just going to be concerned with translational (linear) motion. The key to solving these collision problems is momentum! Momentum is a fundamental property of an object, and it is solved by multiplying the mass by the velocity. The symbol for momentum is P.
P = mv
The wonderful thing about momentum is that within a system, it is ALWAYS conserved. That is to say, the initial sum of momentum equals the final sum of momentum. So if we have two discs, then this equation stands true.
(initial velocities are noted with an 'i' and finals with an 'f')
m1v1i + m2v2i = m1v1f + m2v2f
This equation gives us two unknowns, the final velocities of both objects. We'll need another equation to solve for it. We can turn to another awesome part of physics to get it.
Like momentum, within a system, Energy is ALWAYS conserved. In our case, were going to ignore friction and say that no energy is lost during the collision. In this case, there is no gravity either, so the only energy quantity we care about is the energy of motion, which is called kinetic energy. Kinetic energy (K) is defined by
K = .5mv^2
so, using the same principle as momentum, we can say that
.5m1v1i^2 + .5m2v2i^2 = .5 m1v1f^2 + .5m2v2f^2
and now we can cancel out the .5 because it is in every term, leaving us with two equations.
m1v1i^2 + m2v2i^2 = m1v1f^2 + m2v2f^2
m1v1i + m2v2i = m1v1f + m2v2f
Looky Looky! Two equations, two unknowns! Now we should be able to substitute and solve out for V2f and V1f. However, the algebra is
horribly nasty, so Ill just take a shortcut through wolframalpha.com and tell you that the contents of the code box are the two equations in C# speak. They should be pretty easy to read, but if you don't know, the e1. or the e2. means object 1's whatever, or object 2's whatever.
(for people who know C# and xna, I took out the variable declarations for readability, but they are Vector2's)
V1f = ((e1.mass * e1.velocity) - (e2.mass * e1.velocity) + (2 * e2.mass * e2.velocity)) / (e1.mass + e2.mass);
V2f = ((2*e1.mass * e1.velocity) - (e1.mass * e2.velocity) + (e2.mass * e2.velocity)) / (e1.mass + e2.mass);
The above gives us a great way to find the final MAGNITUDE of the final velocity, but we still don't know in what direction that magnitude will point. So know we need a bit more physics and a bit of geometry to figure out in what direction the discs will bounce off of each other.
We can find the direction of the velocity because we know that it will have the same direction as the final momentum. Momentum and velocities are both vectors, and since p = mv, and mass is just a scalar, the direction of p and v must be equal. The final momentum can be found by this equation
pf = pi + deltaP.
All that means is that the final momentum is equal to the initial momentum PLUS the change in momentum.
Now let me clue you in a little tid bit. The direction of deltaP (change in momentum) is something we can solve for with a bit of geometry. We know that it must point PERPENDICULAR to the TANGENT of collision. That sounds a bit harsh, but its not that bad. There is a tangent of collision, which means the line that only touches each object ones, and passes through the intersection point. So if you dropped a ball on the floor, the tangent of collision would run Parrnell to the floor. The way to find this line, or really just the angle of this line, because that's all we need from it, is to find the intersection points between the object, and draw a line between them. You can draw it out on paper, but you'll see that drawing a line between the two points of intersection for two polygons will give the tangent. And consequently, the direction of the deltaP will be perpendicular to it. To find out which way its going to be perpendicular, as in, weather to add 90 degrees, or subtract 90 degrees, just comes down to looking at the lines slope and if its negative, subtracting, and if its positive, adding. The trick is that each object needs its own tangent of collision, because they should be opposite of one another. As in, one would be 0, and the other would be 180.
Now that we know the direction of the deltaP, we can find its magnitude via a little math. Follow along, its not that complex.
(note, the d means "delta", and is in no way talking about calc)
pf = mvf
pi = mvi
dp = pf - pi = mvf - mvi = m(vf-vi)
dv = vf - vi
dp = mdv
Now we can apply the magnitude we just found to the direction we found earlier, and BAM, we got our change in momentum. Now it stands to reason that if we know the initial momentum, and change in momentum, then the final momentum should be a piece a cake to solve for. And when we solve for it, it will give us a direction, since both the initial and the change in momentum have directions.
Now we just take the direction of the change in momentum, and apply it to our previously found velocities.
AND PRESTO!
The discs are now acting like fancy pool balls, and flying off of each other at fantastic angles.
The whole business about tangent of collision will make sure that if you heave a disc at a rectangle, then the correct bounce will also occur.
The next big step is to bring in spinning.
... But Im still working that one out myself, so if you guys have any thoughts, let me know, and when I figure it out, Ill let YOU know.
So I hope that you enjoyed that fun little spin through physics land. When I get spinning up and running, Ill post a tech demo of my engine, because at that point, I think it'll almost be done. Just need to work in gravity (easy as pie), and pivot points (not as easy).
Tootals.