Andrew

April 2008 Archives

Tribes 1 Physics, Part Three: Collision

Posted on April 11, 2008 7:47 PM

This article covers the collision physics of Tribes 1, i.e. attempting to actually move the player and what to do when the player runs in to something. This is the most convoluted part of the physics and requires a lot of little touches to get right. Tribes movement and collision handling actually gets a little too low level, so I won't be able to show exactly how it works (it gets down to dealing with the raw triangle lists which I don't think all collision detection systems will let you get at), but it will be detailed enough so that there will be no major differences.

Warning!

Before I get in to the details, a little explanation is required. When Tribes attempts to move an object, it takes the maximum distance the object will cover in the remaining time (X), then divides the remaining time by ceil(X) and does ceil(X) collision detection loops. This is ostensibly to ensure that an object only moves 1m at a time, but for what reason, I don't know. The engine is obviously capable of fairly arbitrary translations (or else Gambase::GetLosInfo would not work) so I can only imagine many short translations proved to be more efficient than a single large translation.

I am going to be using a single translation, and normally this would not make a difference, but Tribes does something a little weird on collisions which necessitates a rather odd fix-up when you are using a single translation versus slicing them up. Instead of adjusting the position based on velocity when there is no collision and adjusting the velocity & setting the position to the collision point on a collision, Tribes adjusts the position based on the velocity no matter what. This means Tribes will attempt to move the player, hit a surface, adjust the velocity based on the collision, and then move the player anyway from their original position based on the new velocity, usually resulting in the player bouncing ever so slightly away from the contacted surface. There is actually a noticeable difference between the correct way and Tribes way of handling collisions, as the correct way feels slightly velcroish while Tribes feels more fluid.

Things get more complicated when you move the player in a single translation instead of sliced up translations as the weird adjustment on collisions is only done for the last fraction of the translation and not the entire thing. I worked around this by calculating some values which let me figure out how many "non-collision" slices have occurred and only do the weird handling on the last slice.

Collision Code

Notes

Ski bugs are caused when the translation loop exceeds the maximum number of collisions. When this happens, Tribes zeros the player's velocity as it is having trouble successfully moving. I think there is something in the velocity bounce that occasionally causes the translation loop to get stuck running in to the surface over and over with no change in velocity. When this happens, there is obviously no right answer as to what to do, but zeroing the velocity is fairly annoying answer. I've found that just ignoring the situation and hoping the next tick results in the player getting dislodged appears to work much better.

Also note that I keep forgetting to add constants (MINDAMAGESPEED and DAMAGESCALE in this post) and need to update the original post to include them. Since nobody is reading this and I am taking a while in getting it together, I do not think anyone will mind.

Tribes 1 Physics Series

Tribes 1 Physics, Part Four: Explosions

Posted on April 29, 2008 12:30 PM

Explosions (or more accurately, knockback), the final piece to the physics puzzle! If you implement all of the previous articles, make a disc launcher, plug in the apparently simple knockback force and radius from baseProjData.cs, and finally attempt to disc jump, you will be greeted with... a nice and wimpy boost. Playing around with the knockback force will only break explosions in new ways. Argh, you were so close! How could Tribes possibly screw this one up?

Basic Knockback

The basic idea for knockbacks from explosions is you want to take the position of the explosion and the object, scale the explosion force, and apply an impulse to the object in the appropriate direction. Generally this is implemented something like so:

power is where the magic happens and while it should be an exponential falloff, it is common to do linear because there is not much of a noticeable difference. It is also where Tribes deviates from the norm in a fairly big way.

Tribes Knockback

What is obvious when you implement the basic knockback is that it packs a much smaller punch than Tribes. What you might not notice is that the Tribes knockback up close, e.g. at your feet from a standstill, is actually weaker than from a bit of a distance, e.g. at your feet while you're in the air after jumping. Whether this was intended as an aid to disc jumping or an accident of a botched formula is impossible to say, but it doubtless would have been harder to gain speed from disc jumps without this odd feature.

If you work out exactly what the Tribes knockback function does (not fun) and re-factor the formula (not fun and also confusing), you come out with a somewhat familiar power calculation. Instead of the basic ( 1 - ( d / r ) ), Tribes uses ( ( d / Max( d - minHitboxDimension, 1 ) ) - ( d / r ) ), i.e. instead of using a constant ( 100% - linear falloff ) for the power, Tribes does some weird calculations which I can only guess are trying to account for the hitbox in some way. This image illustrates the power falloff for Tribes, the power falloff for the basic formula, and the power falloff for the basic formula if it were boosted so players were able to disc jump properly:

This shows why the linear falloff formula cannot be fixed by boosting the knockback force without getting wildly inaccurate up close. Here is the proper formula:

For the Light Armor with a BOX_WIDTH of 0.5, BOX_DEPTH of 0.5, and BOX_HEIGHT of 2.3, minbox equates to Min( Min( BOX_WIDTH * 2, BOX_DEPTH * 2 ), BOX_HEIGHT ), or 1.0. The player origin is at the center of the player's feet and the hitbox dimensions extend out from that, so the width and depth extend out in either direction and need to be doubled while the height goes from the feet to the head. Note that if you increase the smallest hitbox dimension, e.g. increase BOX_WIDTH and BOX_DEPTH to have a value of 2.3 when doubled, the linear ramp leading up to the downward falloff of the power will grow, presumably to account for greater surface contact area with the explosion.

You're Done!

You should have all you need to get authentic Tribes 1 Physics going in your engine of choice! After this you should only need to create some dummy weapons, scale their velocities to whatever units you are using, add two flags, and you can get an honest game of LT going.

What? You don't believe me that it works and you don't want to waste your time implementing the physics only to find out that I lied? Hmmm, here's something that should convince you. This is the full T1 physics running on Raindance in ET:QW. I did this for the ET:QW Tribes mod that was in the works, but unfortunately things kind of fizzled out. The map is authentic Raindance (every crevasse and triangle is there) with an 8192×8192 command map texture overlaid on top with Arcanox's bases and bridge. This is currently the closest thing to Tribes you will ever see in another engine.

You can also download the hi-res version (15mb), although the burps are more apparent since my computer wasn't quite up to spec to run QW. How I got the terrain in and textured will have to wait for another day.

Tribes 1 Physics Series