DEFCOM1  
 

XNA Level 2 Lesson 2

Translation and Rotation

  1. Adding Key Control
  2. Time Based Movement
  3. Translation Maths

 

In our last game we simply used the keys to add values to the X and Y coordinates (Position) to move out sprite up, down and across the screen. That is all well and good unless we want to move at a specific angle.

To do that we simply need a bit of trigonometry :)

We take the current position and multiply the velocity by the Cos and Sin of the anlgle, it looks something like this.

X += Velocity * Cos(angle)

Y += Velocity * SIn(angle)

 

So let’s say your tank was currently 100 pixels across and 100 pixels down, traveling at 10 pixels per frame at an angle of 15 degrees

New X = 100 + (10 * Cos(15))

New Y = 100 + (10 * Sin(15))

New X = 109.65

New Y = 102.58

 

Adding Key Control and Time based Movement

Go to the Update Function and add the following code. It is practically the same except for one new line, the new elapsed variable. Elapsed is the calculation of how much time has passed since the last time the update function was called.

This will allow us to move our sprite based on the amount of time between frames

KeyboardState key = Keyboard.GetState();
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

if (key.IsKeyDown(Keys.Left))
{
                
}
if (key.IsKeyDown(Keys.Right))
{

}
if (key.IsKeyDown(Keys.Up))
{
                
}
if (key.IsKeyDown(Keys.Down))
{
                
}

 

Rotation

Simply update the rotation value when pressing Left and Right

if (key.IsKeyDown(Keys.Left))
{
    rotation -= 1.0f * elapsed;
}
if (key.IsKeyDown(Keys.Right))
{
    rotation += 1.0f * elapsed;
}

 

Press F5, you should now be able to rotate the tank using the arrow keys

 

Translation

Now we have a rotation angle, we can use the formula

X += Velocity * Cos(angle)

Y += Velocity * SIn(angle)

to move our tank the direction it is heading.

 

Important

Computers will nearly always use ‘Radians’ not ‘Degrees

As I am sure you are aware there are 360 degrees in a circle

There are 2pi radians in a circle (approximately 6.284 radians)

Don’t worry too much about this, it simply means if you are trying to move along a heading of 180 degrees, you actually need to go along a heading of approximately 3.142

So if you entered 180 when it expected radians, it would in fact be 565 degrees!!!

 

Add the following code to your Keyboard Up command, please note that I like to create temporary X and Y variables and the add them to the position.

if (key.IsKeyDown(Keys.Up))
{
    float x, y;

    x = (100 * elapsed) * (float)Math.Cos(rotation);
    y = (100 * elapsed) * (float)Math.Sin(rotation);

    position.X += x;
    position.Y += y;
}

 

Can you make your tank reverse?

 

 

Completed Listings

public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    //Global Variables
    protected Texture2D SpriteSheet;
        
    protected Vector2 position;
    protected float rotation;



    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }


    protected override void Initialize()
    {
        // TODO: Add your initialization logic here

        position = new Vector2();
        rotation = 0;

        position.X = 200;
        position.Y = 200;

        base.Initialize();

    }


    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);

        // TODO: use this.Content to load your game content here

        SpriteSheet = Content.Load<Texture2D>("TankSpriteSheet");
    }


    protected override void UnloadContent()
    {
        // TODO: Unload any non ContentManager content here
    }


    protected override void Update(GameTime gameTime)
    {
        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();

        // TODO: Add your update logic here

        KeyboardState key = Keyboard.GetState();
        float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;


        if (key.IsKeyDown(Keys.Left))
        {
            rotation -= 1.0f * elapsed;
        }
        if (key.IsKeyDown(Keys.Right))
        {
            rotation += 1.0f * elapsed;
        }
        if (key.IsKeyDown(Keys.Up))
        {
            float x, y;

            x = (100 * elapsed) * (float)Math.Cos(rotation);
            y = (100 * elapsed) * (float)Math.Sin(rotation);

            position.X += x;
            position.Y += y;
        }

        if (key.IsKeyDown(Keys.Down))
        {
            float x, y;

            x = (-100 * elapsed) * (float)Math.Cos(rotation);
            y = (-100 * elapsed) * (float)Math.Sin(rotation);

            position.X += x;
            position.Y += y;
        }
            
            

        base.Update(gameTime);
    }


    protected override void Draw(GameTime gameTime)
    {

        GraphicsDevice.Clear(Color.SeaGreen);

        spriteBatch.Begin();

        spriteBatch.Draw(SpriteSheet, position, new Rectangle(0, 0, 128, 128), 
                 Color.White, rotation, new Vector2(64, 64), 1.0f, SpriteEffects.None, 1);

        spriteBatch.End();


        base.Draw(gameTime);
    }