Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

As a Defrag player, I would like to add advanced movements to my (simple) game, in particular strafe jumping. I currently have basic fps movements (WASD and free look to be clear), but how can I add quake-like movement techniques? This article explains very well the theory behind it, but I really don't know where to start to actually implement it.

share|improve this question
1  
You want to implement a bug into your game? –  Mr. Beast Dec 15 '12 at 20:41
2  
But what a bug it is! –  joltmode Dec 15 '12 at 23:08
add comment

1 Answer

up vote 3 down vote accepted

The article you linked to first explains how the game works and then discusses at length how to exploit the way it works to strafe-jump. I believe only a few paragraphs are useful to you: the one about how the engine decides whether to add an acceleration vector times a small amount of time (which amounts to a small variation of the speed vector):

So when we try to apply an acceleration at some angle to the velocity, we will be allowed to accelerate provided that the component of our current velocity in the proposed direction is less than 320ups.

and how it truncates that small variation of speed so the component of the resulting speed vector along the acceleration direction doesn't exceed a predefined maximum:

If your v.cos(delta) is less than 320 but still very close to 320, applying the usual constant acceleration for a single frame would be enough to take you over 320ups in that direction. This is something the engine checks for, and if the situation exists, the applied acceleration will be only enough to take you up to the 320ups limit (so it would be 320 - v.cos(theta) ), and not beyond.

Just to spare you some confusion when actually implementing the thing, note that the author refers to the vector "a" as the "acceleration vector" but throughout the article it is used sometimes as a unit vector having the same direction as the acceleration vector as in

v.a = v.cos(delta)

or as an amount of speed as in

arccos( (320-a)/v )

or even as a distance (length) as in

a = s.T

where "s" is the global maximum speed (the g_speed variable in the engine) and T is the duration of a frame. So be careful when handling such quirky maths. Here's a rundown to make everything clear:

To sum up in physics/applied maths notation: the player has a speed vector v(t) at time t and we want to compute his speed vector v(t+dt) at time t + dt where dt is a small amount of time. Here, dt will be the duration of a frame, or 1/(framerate). There exists a speed constant V used to cap other speeds or something along those lines, and we will use that constant.

We know v(t) and we can deduce the direction u towards which the player wants to move using the currently pressed movement keys. u is a unit vector. The amount of speed we initially want to add to v(t) is A.dt.u where A, a real number, is the unique, global movement acceleration constant, so that v(t+dt) = v(t) + A.dt.u.

Note that A is not a speed, but an acceleration! The engine uses the same variable g_speed for the global acceleration induced by pressing movement keys AND for the maximum speed, because it simplifies the handling of movement when on the ground, hence the confusion we saw earlier.

We want to add that amount of speed A.dt.u, but we need to truncate it if it makes the component of the resulting vector v(t+dt) bigger than V along u. Therefore, we get the following pseudocode:

// what we want to compute
Vector3D nextSpeed;
// the acceleration direction u, which is a unit vector
Vector3D accelDir = computeAccelDir(pressedkeys);
// our dot product, "v.cos(delta)"
float vcosdelta = currentSpeed.dotProduct(accelDir);
// the total speed along the acceleration direction u (unless we truncate it)
float totalSpeedComponent = vcosdelta + A*dt;
// is it small enough?
if (totalSpeedComponent < V)
{
    nextSpeed = currentSpeed.add(accelDir.times(A*dt));
} else { // no! it's too big! We must truncate -_-'
    nextSpeed = currentSpeed.add(accelDir.times(V - vcosdelta));
}

Sorry for the poor variable names. Please have better variable naming habits than mine. Here, I compute and store float totalSpeedComponent even though I could directly use V - vcosdelta - A*dt in the first if statement, but that was for understandability.

I hope I didn't miss anything. Remember you can customize both A (the global movement-induced acceleration) and V (the maximum speed along acceleration direction).

That being said, just translate that and adapt it to your codebase, I think I got most of it right.

major edit: I forgot to add that this only works in the air! Don't forget to make it so that, if the player lands with the jump key pressed, he only touches the ground for 1 frame at most before he jumps again! Special handling of physics might be required during that particular frame. It's 6AM. Bed.

share|improve this answer
    
Thanks for your answer, I'll try it as soon as possible. –  matt Dec 16 '12 at 9:36
    
Reading this also helps. –  matt Dec 16 '12 at 16:12
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.