Well, if I ever want to release this on the asset store, Iâ€™m of course a bit hesitant to post any source code for free (as that would sort of defeat the purpose of putting it on the asset store).

That said, I can give a general crash course of sorts about how the physics in Quake worked and how my code did things.

For one, I used Character Controller. Since this is a highly customized physics routine, rigidbodies just wonâ€™t cut it (I also did this in order to have control over exactly when character physics are updated, so that they can be integrated into a client-side prediction system for network games).

Generally, there are two parts to the physics routine: applying acceleration, and applying friction.

First, applying acceleration. This is what my accelerate function looks like:

```
// apply input acceleration to our velocity
// wishDir is the normalized direction we want to move in
// wishSpeed is the speed we want to move in that direction
// accel is how fast we want to accelerate towards wishSpeed
protected void applyAcceleration( Vector3 wishDir, float wishSpeed, float accel )
{
// first, we store the current velocity along Y axis, before applying acceleration.
float y = velocity.y;
float addSpeed, accelSpeed, currentSpeed;
// first, get flat velocity (negating Y component)
Vector3 flatVel = velocity;
flatVel.y = 0f;
// find out how fast we are already moving in the desired direction (this can be done using dot product)
currentSpeed = Vector3.Dot( flatVel, wishDir );
// get the difference between our current speed and our desired speed
addSpeed = wishSpeed - currentSpeed;
// ignore any acceleration that would *reduce* speed instead of increasing it
if( addSpeed <= 0 )
return;
// accelSpeed is the speed we want to move at multiplied by acceleration factor
accelSpeed = accel * wishSpeed;
// if that exceeds the delta between current and desired speed, clamp it (so that we don't over-accelerate)
if( accelSpeed > addSpeed )
{
accelSpeed = addSpeed;
}
// now add it to velocity
velocity += accelSpeed * wishDir;
// and restore what the Y velocity was prior to adding acceleration
velocity.y = y;
}
```

The dot product there is where a lot of the magic happens, itâ€™s what allows strafe jumping to occur because it only considers velocity in the desired direction (if velocity is perpendicular to the desired input direction, that value becomes 0 and an acceleration is applied, net result is that velocity actually increases).

Next is friction, because we definitely want the player to come to a stop when on solid ground

Friction is actually super simple. In a nutshell, you just subtract a friction value from velocity speed every frame, that friction term depends on whether youâ€™re in air or on ground (or even what surface youâ€™re on, if you want to support slippery surfaces for example). Higher = faster to stop, lower = slower to stop (in air, you will probably set this to zero because air friction is negligible)

```
// apply friction to our velocity
// vel is the current velocity which we will be applying friction to
// drop is how much to reduce speed each frame
protected Vector3 applyFriction( Vector3 vel, float drop )
{
// store Y velocity prior to applying friction
float y = vel.y;
// negate Y velocity
vel.y = 0f;
// get the speed we're currently moving at in the X-Z plane
float speed = vel.magnitude;
// subtract a value from speed
float newSpeed = speed - drop;
// clamp speed to 0
if( newSpeed < 0f )
newSpeed = 0f;
// later we're actually going to be multiplying the old velocity by this value
// this is just a shortcut to normalizing the vector, this way I only have to divide one value instead of dividing
// all three X, Y, and Z components of the vector (which is what Normalize does internally)
// basically, highscool algebra / rearranging terms ;)
newSpeed /= speed;
// if newSpeed is 0 the result will now be NaN so we need to handle that case
if( float.IsNaN( newSpeed ) )
{
return Vector3.up * y;
}
// multiply the velocity by the new speed value to set the speed of the vector
Vector3 ret = vel * newSpeed;
// restore the Y value (we don't want friction affecting Y velocity)
ret.y = y;
// return new velocity value
return ret;
}
```

So, that in a nutshell is the core of how Quakeâ€™s character physics work and is the reason strafe and rocket jumping work among other tricks used by veteran players. Thereâ€™s a lot more that has to be built on this of course, which if I polish this up for an asset store package would all be implemented for you (moving platforms, crouching, colliding with rigidbodies, etc).