# How can I normalize a vector if I am handling movment of each axis seperatley?

I am writing a 2D tile based game engine in XNA, and I've recently fine-tuned my collision detection using the answers provided here and more specifically here.

The tile based collision detection now works flawlessly and fixed all the small problems I had with my previous code. However, implementing this forced me to rewrite how movement was handled. Instead of moving the player all at once and then resolving each collision along the smallest axis of intersection depth, it now updates and resolves on the X and Y axes separately.

This is fine, but now my diagonal movement is much faster than my horizontal and vertical movement and I am unsure of how to normalize it.

I'm sure I'm just overlooking something simple, is there a straight forward way of doing this?

    public void HandleInput()
{
//Set horizontal and vertical values accordingly based on direction of key presses
int horizontal = InputHelper.IsKeyDown(Keys.A) ? -1 : (InputHelper.IsKeyDown(Keys.D) ? 1 : 0);
int vertical = InputHelper.IsKeyDown(Keys.W) ? -1 : (InputHelper.IsKeyDown(Keys.S) ? 1 : 0);

//If there is movement update sprite position, round the position to nearest pixel and then check for collision
if (vertical != 0)
{
sprite.Position += Vector2.UnitY * sprite.Speed * vertical;
sprite.Position = new Vector2(sprite.Position.X, (float)Math.Round(sprite.Position.Y));
HandleCollisions(Direction.Vertical);
}
if (horizontal != 0)
{
sprite.Position += Vector2.UnitX * sprite.Speed * horizontal;
sprite.Position = new Vector2((float)Math.Round(sprite.Position.X), sprite.Position.Y);
HandleCollisions(Direction.Horizontal);
}
}

private void HandleCollisions(Direction direction)
{
// Get the player's bounding rectangle and find neighboring tiles.
Rectangle playerBounds = sprite.spriteBounds;
int leftTile = playerBounds.Left / Engine.TileSize;
int topTile = playerBounds.Top / Engine.TileSize;
int rightTile = (int)Math.Ceiling((float)playerBounds.Right / Engine.TileSize) - 1;
int bottomTile = (int)Math.Ceiling(((float)playerBounds.Bottom / Engine.TileSize)) - 1;

// For each potentially colliding tile,
for (int y = topTile; y <= bottomTile; ++y)
{
for (int x = leftTile; x <= rightTile; ++x)
{
Vector2 depth;
//If this tile is collidable, and it intersects sprite bounds
if (tileMap.CollisionLayer.GetCellIndex(x, y) == 0 && TileIntersectsPlayer(playerBounds, GetTileBounds(y, x), direction, out depth))
{
//Resolve the collision along the given axis
sprite.Position += depth;

// Perform further collisions with the new bounds.
playerBounds = sprite.spriteBounds;
}
}
}
}


To expand on what Trevor was saying, when you hold down just a vertical or horizontal button then your net movement is only 1 * speed, but if you hold down a vertical plus a horizontal key then your net movement is sqrt(1+1) * speed. So what you need to do is to normalize the horizontal and vertical values by dividing them by the sqrt of the sum of the squares of them. Or you can just put the values into a Vector2 and normalize it.

So change your lines where you retrieve vertical and horizontal and do this instead:

Vector2 move = new Vector2(InputHelper.IsKeyDown(Keys.A) ? -1 : (InputHelper.IsKeyDown(Keys.D) ? 1 : 0) , InputHelper.IsKeyDown(Keys.W) ? -1 : (InputHelper.IsKeyDown(Keys.S) ? 1 : 0));
Vector2.Normalize(move);


Then use move.X wherever you would have horizontal and move.Y wherever you had vertical.

• Thanks, this helped alot. I first put the values into a Vector2 and normalized it as per your code, but the speed seemed unchanged, maybe I over looked something. So I tried the other way you mentioned; dividing both the horizontal and vertical values by the sqrt of the sum of the squares and it now works perfectly. Thanks. Feb 21 '13 at 13:30

Math doesn't care how you store your variables; you normalise vectors in exactly the same way, regardless of whether you put their values into a single object, or separate variables.

Length = sqrt( axisX * axisX + axisY * axisY (... + axisZ * axisZ, etc) ).

Then divide each axis by the length you've calculated.