Rotating A Sprite Towards An Object In XNA

Often when creating games in 2D you need a sprite to rotate towards another object, whether that be a turret rotating towards an enemy or making something follow your mouse. Regardless of the use of this rotation the principle is the same. In this tutorial I use the basic concept of making something follow the mouse, but the game logic provided should enable you to rotate any sprite towards just about any object on the game screen.

Before we start anything language specific, we should have a think about what exact we want to achieve. We’re going to assume we start with the sprite unrotated, parallel to the X and Y axis (this assumption is just for ease of explanation and doesn’t factor into any calculations). So we begin say, with a sqaure:

Rotation

With the center of rotation at the middle of the square. In order to rotate this towards distant point we need to do some basic trigonometry. I know this seems scary but it’s really easy as pie, any 15 year old could do this (or probably even younger).

The goal is to rotate the object about the center point so that the leading face (the right hand side of our square) points towards the cursor. To this we image the following scenario:

Rotation

Where the circle is the mouse pointer.

Basically we want to rotate through the shown angle to face the leading face at a 90 degree angle to the cursor. We do this by doing some really simple maths. We just take the arctangent of the two angles which is supplied in almost every programming language nowadays as:

Math.Atan2(YDistance, XDistance);

Or something similar.

Now we have the required rotation, to move the object towards the cursor we minus its current position from the speed we want it to travel by frame * the Cos or Sin of the rotation.

For it’s horizontal movement we subtract speed * Cos(rotation).

For it’s vertical movement we subtract speed * Sin(rotation).

Why Sin of one Cos of the other? Simply because you are essentially making smaller and smaller triangles as you go closer to the point and taking Cos of the rotation finds the horizontal distance of said smaller triangle, and take Sin finds the vertical. It’s basic trigonometry!

Here’s an example of the code for the update parameters in C#:

//Store the mouse state
MouseState mouse = Mouse.GetState(); ;
 
//Calculate the distance from the square to the mouse's X and Y position
float XDistance = SquarePosition.X - mouse.X;
float YDistance = SquarePosition.Y - mouse.Y;
 
//Calculate the required rotation by doing a two-variable arc-tan
rotation = (float)Math.Atan2(YDistance, XDistance);
 
//Move square towards mouse by closing the gap 3 pixels per update
SquarePosition.X -= (float)(3 * Math.Cos(rotation));
SquarePosition.Y -= (float)(3 * Math.Sin(rotation));

Hopefully this helped! Any questions just ask.


Source is Here.

Please note that the source is compiled for windows, and is also compiled for XNA 4.0 CTP! You will also need Visual Studio 2010

20 thoughts on “Rotating A Sprite Towards An Object In XNA

  1. Hi, I’m having trouble getting this working, and the the Source code link appears to be broken. Is there any way someone can host the source files?

    Thanks.

  2. Sorry there, I had accidentally put 4 w’s in the URL! The link works now :D

    What trouble are you having and I’ll gladly help clarify?

  3. I was unsure on the paramaters to use in the draw method, namely what the origin paramter should be.Now I see you use the middle of the square as the origin, Thanks.

  4. Oh dude this is Epic, searched so much for the solution, got there calculating an own type of Vector angles, and now the Solution for both (Drawing angle = rotation, moving direction)
    is there in 3 lines of code. Dunno which Blog this is but i start loving the Author :)

  5. I have implemented alot of the code you have provided her but would like to make my soldier shoot bullets. Do you have any advice?

    My code so far:

    namespace LastManDead
    {
    public class Game1 : Microsoft.Xna.Framework.Game
    {
    //Variables

    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    Texture2D soldier;
    Texture2D monster;
    Texture2D aim;
    Texture2D background;
    Vector2 soldierPosition;
    Vector2 monsterPosition;
    Vector2 aimPosition;
    float rotation;
    float mrotation;
    float timer = 0f;
    float mtimer = 0f;
    float interval = 200f;
    float minterval = 200f;
    Point framesize = new Point(60, 60);
    Point mFramesize = new Point(60, 60);
    int currentFrame = 0;
    int mcurrentFrame = 0;

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

    protected override void Initialize()
    {
    //make the mouse invisible!
    this.IsMouseVisible = false;
    base.Initialize();
    }

    protected override void LoadContent()
    {
    spriteBatch = new SpriteBatch(GraphicsDevice);

    soldier = Content.Load(@”Images\Soldier”);
    monster = Content.Load(@”Images\Monster”);
    aim = Content.Load(@”Images\Aim”);
    background = Content.Load(@”Images\skullfield”);
    soldierPosition = new Vector2(GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2);
    }

    protected override void UnloadContent()
    {
    }

    protected override void Update(GameTime gameTime)
    {
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
    this.Exit();

    //Soldier Movement!!!!!

    //Store the mouse state
    MouseState mouse = Mouse.GetState();

    aimPosition.X = mouse.X;
    aimPosition.Y = mouse.Y;

    //Calculate the distance from the square to the mouse’s X and Y position
    float XDistance = soldierPosition.X – mouse.X;
    float YDistance = soldierPosition.Y – mouse.Y;

    //Calculate the required rotation by doing a two-variable arc-tan
    rotation = (float)Math.Atan2(YDistance, XDistance);

    if (XDistance > 20 || XDistance 20 || YDistance interval)
    {
    //If is incrememnt current frame
    ++currentFrame;

    //Check frame is within direction frames, if not set back to standing
    if (currentFrame >= 2)
    {
    currentFrame = 0;
    }
    //Reset timer
    timer = 0f;
    }
    }
    else
    currentFrame = 0;

    //Monster Movement!!!!!!

    Rectangle soldierRect = new Rectangle((int)soldierPosition.X, (int)soldierPosition.Y, framesize.X, framesize.Y);

    float mXDistance = monsterPosition.X – soldierRect.Location.X;
    float mYDistance = monsterPosition.Y – soldierRect.Location.Y;

    //Calculate the required rotation by doing a two-variable arc-tan
    mrotation = (float)Math.Atan2(mYDistance, mXDistance);

    //Move soldier towards mouse by closing the gap 3 pixels per update
    monsterPosition.X -= (float)(1 * Math.Cos(mrotation));
    monsterPosition.Y -= (float)(1 * Math.Sin(mrotation));

    //Incremement timer using paramater
    mtimer += (float)gameTime.ElapsedGameTime.TotalMilliseconds;

    //Check if timer is greater than interval
    if (mtimer > minterval)
    {
    //If is incrememnt current frame
    ++mcurrentFrame;

    //Check frame is within direction frames, if not set back to standing
    if (mcurrentFrame >= 4)
    {
    mcurrentFrame = 0;
    }
    //Reset timer
    mtimer = 0f;
    }

    base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
    graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

    spriteBatch.Begin(SpriteBlendMode.AlphaBlend,SpriteSortMode.FrontToBack,
    SaveStateMode.None);

    spriteBatch.Draw(aim,aimPosition, new Rectangle(0, 0, 20, 20), Color.White,
    0,new Vector2(aim.Height /2,aim.Width/2),1, SpriteEffects.None, 0);

    spriteBatch.Draw(soldier, soldierPosition, new Rectangle(currentFrame * framesize.X,
    0, framesize.X, framesize.Y), Color.White, rotation,
    new Vector2(framesize.X / 2, framesize.Y / 2), .7f, SpriteEffects.None, 0);

    spriteBatch.Draw(background, new Rectangle(0, 0, Window.ClientBounds.Width, Window.ClientBounds.Height),
    Color.White);

    spriteBatch.Draw(monster, monsterPosition, new Rectangle(mcurrentFrame * mFramesize.X,
    0, mFramesize.X, mFramesize.Y), Color.White, mrotation,
    new Vector2(mFramesize.X / 2, mFramesize.Y / 2), .85f, SpriteEffects.None, 0);

    spriteBatch.End();

    base.Draw(gameTime);
    }
    }
    }

  6. You should make your monsters and player as their own class. Reason because, that code you just displayed could get complex. AS for the people new to xna, its good code practices. Ive seen people code like this and get angry a couple months later, as they require to modify 80% of their code to make in function all through the application.

    Learn OOP fast, it helps later on in xna game development, or basicly code 101.

    As for your demo code, its pretty neat.

    – Xna 4.0, windows phone 7 is the future?

  7. Hi,

    This code helped a lot in a project I’m working on.
    But I have a question, is it possible to “Lock” the rotation?

    I’m doing a shoot’em up game, where the player is faced upwards, since he is moving in that direction. Aiming and rotation of the player sprite is controlled by the mouse, but I don’t want the Player to be able to rotate around.

    Basivally I only want him/her to aim in a cone, upwards like: \/

    So can you somehow stop the rotation?
    By lots of “if(){}”?

    Thanks in advance!

  8. I noticed that it bounced back and forth so i messed with the code and came up with a small adjustment :).

    Instead of:
    SquarePosition.X -= (float)(3 * Math.Cos(rotation));
    SquarePosition.Y -= (float)(3 * Math.Sin(rotation));

    Use:
    if (XDistance >= 3 | YDistance >= 3 | XDistance <= -3 | YDistance <= -3 )
    {
    SquarePosition.X -= (float)(3 * Math.Cos(rotation));
    SquarePosition.Y -= (float)(3 * Math.Sin(rotation));
    }
    else
    {
    SquarePosition.X -= (float)(0 * Math.Cos(rotation));
    SquarePosition.Y -= (float)(0 * Math.Sin(rotation));
    }

    Mess around with the = numbers to get a different range. Enjoy.

  9. Nice tutorial. I have one question though. How can I go about shooting a projectile toward the mouse position?

  10. great tut you got here im a bit of a noob and don’t know how to “apply” this to my sprites the input for each sprite is in separate classes and i cant work out how id get his to work, im coding this for the xbox360 in xna 4.0 if anyone can help please email me :) benstovell@live.co.uk im from the uk so someone in the uk would be handy

  11. It works for the most part, but I’ve noticed something. The closer the object, the smoother its trajectory toward its point, but when it is far away it kind of slides along the X-axis then the Y-axis towards its target. I have an array of enemies following the player. Here is the code for the array and the code inside of the enemy object for the moveTowardsPoint method:

    Inside Update:
    foreach (Actor d in dudes)
    {
    d.facePoint(player1.getX(), player1.getY());
    d.moveTowardsPoint(player1.getX(), player1.getY());
    }

    Inside Draw:
    foreach (Actor d in dudes)
    {
    spriteBatch.Draw(d.getSprite(), d.getRect(), null, Color.White, d.getRotation(), d.getOrigin(), SpriteEffects.None, 0.0f);
    }

    spriteBatch.Draw(player1.getSprite(), player1.getRect(), null, Color.White, player1.getRotation(), player1.getOrigin(), SpriteEffects.None, 0.0f);

    facePoint Method:
    public void facePoint(int x, int y)
    {
    int distanceX;
    int distanceY;

    distanceX = x – rect.X;
    distanceY = y – rect.Y;

    rotation = (float)Math.Atan2(distanceY, distanceX);
    }

    moveTowardsPoint method:
    public void moveTowardsPoint(int x, int y)
    {
    float xDistance = getX() – x;
    float yDistance = getY() – y;

    int currentX = getX() + (int)(speed * Math.Cos(rotation));
    int currentY = getY() + (int)(speed * Math.Sin(rotation));

    setPos(currentX, currentY);
    }

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>