# How can I achieve smooth animation of sprites between discrete tiles?

I'm currently learning game development with C# and XNA and my current assignment is to create a Pac-Man clone.

The game is partially tile based, which means that the level itself is built out of an array of tiles, but Pac-Man and the ghost just have a position to be drawn at. I've got the basic functionality down, such as building the level with a string and drawing Pac-Man and the ghost on the screen.

Pac-Man is currently represented by two positions: one is where he is in relation to the array of tiles (a Point, for example 9, 11), and one where the sprite is drawn (which is a Vector2). However, when trying to make the player be able to move Pac-Man (and Pac-Man is supposed to "glide" between tiles, not jump between them) it seems that his graphical position can not keep up with his tile position. It sort of lags behind.

This is hard to describe but here's some code to look over:

public PacMan(): base()
{
texture = Game1.pacManTexture;
tilePosition = new Point(9, 11);
position = new Vector2(tilePosition.X * spriteSize.X, tilePosition.Y * spriteSize.Y);


That is the constructor for Pac-Man.

else if (tileManager.playArea[tilePosition.X, tilePosition.Y - 1] is Tile) // if the  tile above Pac-Man is of the type Tile...
{
tilePosition.Y -= 1; // decrement tilePosition by 1
}


That is what happens if the player presses the Up key.

Vector2 tilePos = new Vector2(tilePosition.X * spriteSize.X, tilePosition.Y * spriteSize.Y);
Vector2 direction = tilePos - position;
if (direction.Length() != 0)
direction.Normalize();
position += direction;


And that is where the faulty magic happens. The graphical position of Pac-Man (the sprite) is being updated.

Rectangle pacManRectangle = new Rectangle((int)position.X, (int)position.Y, spriteSize.X, spriteSize.Y);
Game1.spriteBatch.Draw(texture, pacManRectangle, new Rectangle(currentFrame.X * spriteSize.X, currentFrame.Y * spriteSize.Y, spriteSize.X, spriteSize.Y), Color.White);


And lastly, that happens in the Draw method.

• How are you updating currentFrame? The name of this variable probably speaks a lot about the lag. – ChrisC Oct 31 '11 at 14:42

I'm still somewhat new on the XNA scene myself, but I assume if your game is tile based you know the exact points (probably the center of the tiles) that pac-man needs to move to. There is probably some wild vector math you could do to calculate pac-man's speed so that he moves a little bit per update and arrives perfectly at said point, but you might settle on something like this:

position += speed * direction * elapsedGameTime;


This will set your pac-man sprite into motion and have it headed towards the point you want it to be at, at the speed (a float you can adjust?) you want him to walk, or roll, or whatever he does. Each update, you could then check pac-man's position.X and position.Y VS your point.X and point.Y. Once pac-man is going to go beyond that point, set his position directly to the point coordinates. You should probably do this position vs point check so that if pac-man has gone beyond the point, that the position is updated to the point coordinates before your Draw method (else Pac-man might appear to "jump back" a bit).

You probably just want to MathHelper.Lerp two Vector2 values. One value is the original tile, the other is the destination tile. The LERP float (last parameter) will be: (CurrentTime - TimeMovementStarted) / TimeToMoveBetweenTiles

Or, if you move according to deltas, you can set CurrentTime = 0 when the movement starts, then add the delta in each UPDATE according to the UPDATE gameTime. The equation becomes (since we zeroed to start): CurrentTime / TimeToMoveBetweenTiles.

After TimeToMoveBetweenTiles elapses, it's time to check player input again to see which square to go to now. (Or check more often if you want to be able to turn around - though if you do implement turn around, you need to know you're turning around and start subtracting from "CurrenTime" until it gets back to 0)

Note that you still should check the ACTUAL distance between an evil ghost and the player pacman as you don't want a ghost "eating" pacman just because it entered a square pacman is still leaving but mostly already out of (being chased closely).