# How to avoid movement speed stacking when multiple keys are pressed?

I've started a new game which requires no mouse, thus leaving the movement up to the keyboard. I have tried to incorporate 8 directions; up, left, right, up-right and so on. However when I press more than one arrow key, the movement speed stacks (http://gfycat.com/CircularBewitchedBarebirdbat). How could I counteract this?

Here is relevant part of my code:

var speed : int = 5;

function Update () {
if (Input.GetKey(KeyCode.UpArrow)) {
transform.Translate(Vector3.forward * speed * Time.deltaTime);
} else if (Input.GetKey(KeyCode.UpArrow) && Input.GetKey(KeyCode.RightArrow)) {
transform.Translate(Vector3.forward * speed * Time.deltaTime);
} else if (Input.GetKey(KeyCode.UpArrow) && Input.GetKey(KeyCode.LeftArrow)) {
transform.rotation = Quaternion.AngleAxis(315, Vector3.up);
}
if (Input.GetKey(KeyCode.DownArrow)) {
transform.Translate(Vector3.forward * speed * Time.deltaTime);
}
}

• tangent: The indentation in your code was a little messed up so I didn't notice at first, but the conditions in your code will prevent most of it from running. Like, if(UpArrow) else if(UpArrow && RightArrow) will never run the 'else' branch. – jhocking Aug 23 '14 at 15:46

Separate your direction selection code from actual movement code.

1. Choose Direction by checking which keys are pressed. Store it as a unit (normalized) vector.
2. Multiply your Direction with Speed and with DeltaTime.
3. Apply resulting transform to your object/camera.

You need to take the sum of the directions, normalize that, then multiply by the speed.

I tangentially answered this as part of my response to Preventing diagonal movement

Specifically:

velX = 0;
velY = 0;

if(keyLeft) velX += -1;
if(keyRight) velX += 1;
if(keyUp) velY += -1;
if(keyDown) velY += 1;

// Normalize to prevent high speed diagonals
length = sqrt((velX * velX ) + (velY * velY ));
if (length != 0)
{
velX /= length;
velY /= length;
}

velX *= speed;
velY *= speed;


The "normalized direction vector" is how this task is usually approached, and how I often do it, but lately I've simply been clamping the resulting movement vector. It usually achieves the same end result and the code is a lot simpler:

var moveSpeed = 6.0f;
function Update() {
var movement = Vector3.zero;
movement.x = Input.GetAxis("Horizontal") * moveSpeed;
movement.z = Input.GetAxis("Vertical") * moveSpeed;
movement = Vector3.ClampMagnitude(movement, moveSpeed);
movement *= Time.deltaTime;
transform.Translate(movement);
}


Simpler code is almost always better :E

• What does ClampMagnitude do, isn't it the same code as Normalize * Constant in disquise? – Kromster says support Monica Aug 21 '14 at 13:02
• Not quite. "Clamping" a value makes sure it stays within a range/below the maximum, while normalizing sets the value to a constant. With Unity at least, GetAxis() returns slightly accelerating values, giving you a smoother movement. Normalizing the vector overrides that acceleration, while clamping allows the acceleration to happen. It's subtle but looks nicer. The end effect is pretty much the same though. – jhocking Aug 21 '14 at 13:20
• +1 for being the only answer written directly in the context of Unity. The API provides all kinds of useful Vector/Quaternion math methods with this sort of situation in mind, no reason to roll your own. – Selali Adobor Aug 21 '14 at 15:24
• I'd clamp to 1 and only multiply with moveSpeed after clamping and possibly merge it with the multiplication by deltaTime. – CodesInChaos Aug 21 '14 at 15:38
• Does that change gain more than just removing one multiplication operation? Like, does clamping 1 operate differently from clamping 6? wondering what your change does... – jhocking Aug 21 '14 at 19:43