Games have been trying replicate the feel of Tribes 1 for almost as long as it’s been out (Tribes 2 started development in mid-1999) and every single one of them has failed, usually miserably.

Tribes 2 physics are an abomination, although in hindsight it should have come as no surprise after the Base+ mod Dynamix play-tested in Tribes 1 to massive disdain. It’s as if they were trying to build on the success of Tribes 1 when it was 2 weeks old, not 2 years. Unfortunately for the majority of the community not in the beta, we didn’t find this out until after the game was paid for. Further mods such as Base++, Team Rabbit 2, and Classic attempted to rectify the situation yet were still only a pale ghost of Tribes 1.

Legends has always felt wrong despite how often they tweaked and twiddled the physics and boasted of having the original physics source code. If they did have the source, they either didn’t know how to implement it or didn’t have enough of the source to properly replicate all of the required physics.

Tribes Vengeance is so far removed from the feel of Tribes that it shouldn’t even enter the discussion. Jetting is wrong, air movement shouldn’t even exist, collisions are wrong, and skiing is a sick joke. I can only hope KineticPoet remembered what used to be and silently winced every time he sat down to work on the game.

The yet-to-be-released Fallen Empire: Legions appears to be following the “We’re not a Tribes 1 clone, so let’s make wacky changes to ram that home” mantra. Ideas like 6 way jetting (jetting down while in the air and laterally while on the ground), non-friction sliding a-la T:V, jetpack overdrive, a charge up sniper rifle, etc., sound like they could easily alter the game beyond good taste.

What all of these games ostensibly want is to appeal to Tribes 1 players, yet they attempt to accomplish this by using a different and/or completely arbitrary physics system, adding something that resembles a jetpack and skiing and hoping everyone likes it. While I don’t know if a carbon copy of Tribes 1 on a modern engine would be a success, I do know that almost any Tribes 1 veteran will be unsatisfied with any Tribes style game that does not replicate the feel of Tribes 1 regardless of how often the developers hide behind the claim of “not Tribes 1”.

These articles will solve that problem. I will provide everything needed for a 99% re-creation of the Tribes 1 physics on any 3d engine. There are a few pieces to the puzzle so I’ll be breaking the topics in to separate articles for movement, collision, and explosions. This article will go over the basics of the engine and document the structures and constants I’ll be using.

Basics

To start off, all units will be in meters, the default unit of Tribes. You will need to provide a separate function to convert the Tribes meters to your engine’s native units, e.g. if 1 unit in your engine of choice is roughly equal to an inch, you will need to convert from Tribes meters to inches, i.e. multiply ~39.37. This will ensure that the authentic Tribes 1 constants are being used and that nothing has been messed up to due to being mis-scaled by hand. I will use MetersToUnits and UnitsToMeters to indicate when a conversion needs to be made.

Tribes runs at 31.25 ticks a second, or 0.032s per tick. Altering the ticks per second will result in slightly different physics as the gravity is accumulated based on the tick length while jumping is a singular impulse, so as the tick length grows, gravity slowly subsumes the jump impulse. There are other less obvious calculations based on the tick length which will be altered as well; some of these can be accounted for, some not.

The coordinate system is Z up, and Vectors are assumed to have overloaded operators.

All code examples will be in a pseudo C-like language and should be easy to translate in to any engine.

Physics Workflow (details omitted)

Tick( Move move, float ticklen ) { if ( jumping and canJump ) velocity += Jump( move.direction ) accel = Gravity.force if ( jetting ) accel += Jet( move.direction ) velocity += ( accel / ticklen ) if ( collisionLastTick ) velocity += Friction( move.speed, ticklen ) position, velocity = UpdatePosition( ticklen ) }

There is nothing special in Tribes 1 physics, skiing is not achieved by “Friction = 0”, and the only feature an engine needs is the ability to properly detect collisions. There are a lot of nuances required to achieve a simulation that doesn’t feel subtly wrong, but none are of the earth-shatteringly unique variety that many claim only the Tribes/Torque engine can replicate. They are, however, nuances that you are highly unlikely to match with pure guesswork.

Structures

These are the structures and values I will be using for detailed explanations of the physics workflow. Don’t worry if you don’t know what a value does just yet.

Gravity { Vector3 force = ( 0, 0, -20 ) Vector3 upNormal = -force.Normalize Vector3 downNormal = force.Normalize } Physics { float TICKBASE = 0.032 float ELASTICITY = 0.001 float CRAWLTOSTOP = 0.1 float MINSPEED = 0.75 float FRICTIONDECAY = 0.6 int MAXJUMPTICKS = 256 } LightArmor : Armor { float MASS = 9 float GROUNDFORCE = 9 * 40 float GROUNDTRACTION = 3 float WALKSPEED = 11 float JUMPIMPULSE = 75 float JUMPSURFACE_MINDOT = 0.2 float MINDAMAGESPEED = 25 float DAMAGESCALE = 0.005 float JETFORCE = 236 float JETSIDEFORCE = 0.8 float JETFORWARD = 22 float MAXENERGY = 60 float JETENERGY_DRAIN = 25 float JETENERGY_CHARGE = 8 + 3 float BOX_WIDTH = 0.5 float BOX_DEPTH = 0.5 float BOX_HEIGHT = 2.3 } Player { Armor armor Vector3 position, velocity float energy bool crawledToStop bool collisionLastTick Vector3 lastJumpableNormal int lastJumpableNormalTimestamp float currentFriction }

Tribes 1 Physics Series

Part One: Overview

Part Two: Movement

Part Three: Collision

Part Four: Explosions