XNA Camera 2d with zoom and rotation

07/01/2011 – By popular request updated to XNA 4.0, xna 3.1 code is still there too

One of the things I keep finding is people asking how to do a simple camera 2d in XNA. Today I decided to contribute with my own solution.

Most of the time the solution given is to have a class camera with a Vector2 position and when drawing the sprite batch to subtract the camera position to the sprite position itself. Although this work from my point of view it’s not elegant and you can’t have neat features like zooming and rotation.  So for my tutorial I’ll do all transformations using a Matrix.
Start off by creating the basic class Camera2d

public class Camera2d
   {
        protected float          _zoom; // Camera Zoom
        public Matrix             _transform; // Matrix Transform
        public Vector2          _pos; // Camera Position
        protected float         _rotation; // Camera Rotation
 
        public Camera2d()
        {
            _zoom = 1.0f;
            _rotation = 0.0f;
            _pos = Vector2.Zero;
        }
 
  }

Now that we have the basic setup onto the variables it’s time to create a couple of functions to manipulate the variables

// Sets and gets zoom
public float Zoom
        {
            get { return _zoom; }
            set { _zoom = value; if (_zoom < 0.1f) _zoom = 0.1f; } // Negative zoom will flip image
        }
 
 public float Rotation
        {
            get {return _rotation; }
            set { _rotation = value; }
        }
 
        // Auxiliary function to move the camera
        public void Move(Vector2 amount)
        {
           _pos += amount;
        }
       // Get set position
        public Vector2 Pos
        {
             get{ return  _pos; }
             set{ _pos = value; }
        }

And now for the function that calculates all the transformations

public Matrix get_transformation(GraphicsDevice graphicsDevice)
        {
            _transform =       // Thanks to o KB o for this solution
              Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) *
                                         Matrix.CreateRotationZ(Rotation) *
                                         Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) *
                                         Matrix.CreateTranslation(new Vector3(ViewportWidth * 0.5f, ViewportHeight * 0.5f, 0));
            return _transform;
        }

So now how can we use it?
Simple on your sprite batch begin you must add the camera transformation.

Camera2d cam = new Camera2d();
cam.Pos = new Vector2(500.0f,200.0f);
// cam.Zoom = 2.0f // Example of Zoom in
// cam.Zoom = 0.5f // Example of Zoom out
 
//// if using XNA 3.1
spriteBatch.Begin(SpriteBlendMode.AlphaBlend,
                        SpriteSortMode.Immediate,
                        SaveStateMode.SaveState,
                        cam.get_transformation(device /*Send the variable that has your graphic device here*/));
 
//// if using XNA 4.0
spriteBatch.Begin(SpriteSortMode.BackToFront,
                        BlendState.AlphaBlend,
                        null,
                        null,
                        null,
                        null,
                        cam.get_transformation(device /*Send the variable that has your graphic device here*/));
 
// Draw Everything
// You can draw everything in their positions since the cam matrix has already done the maths for you 
 
spriteBatch.End(); // Call Sprite Batch End

Found any errors? Please let me know.

More Reading

Post navigation

  • Hi, I think that I solved the problem with camera delay. I just added this line: graphics.PreferMultiSampling = true; and camera is working fine in full screen too. Thanks for this awesome tutorial!

  • Hi David,

    Thanks a lot for the tutorial. I have a question regarding zooming at a specific spot and camera size.

    I am making an RTS and I want the camera to zoom at the point on the screen where the cursor is. I am using a touch interface of windows phone, so I want the camera to zoom at the point where the user has put his fingers and performed the pinch gesture.

    In other words, I want the center of the camera to shift to the point where the zoom is being performed.

    Another problem is that, I have limited the camera in a rectangle. It works well as long as I am zoomed out and drag the camera around. Say that I drag and reach the top-right corner in the zoomed out state. now when I zoom in, I can no longer see what is present at the top right corner as the camera size remains the same, but it has zoomed in to the center.

    I gather that I will need to change the size of the camera as I zoom in. How can this best be done?

  • Great code, saved me ages and opened up lots of possabilities. Thanks. But I’ve had a problem where if at ANY time I switch rendertarget, then return to the default rendertarget, either in a component, class or in the main loop the screen goes purple. I’ve only had this problem when using the camera and cant figure it out. Any idea?

  • Forget my previous post, I was switching renderTarget in the Draw call, I’m now doing it in the update loop, creating the texture and then drawing the result it in the draw call. it’s now working as I’d intended. Thanks again though for the great blog!

  • Great post, helped me figure out the glitch in the code I was using (it was calculating the middle of the screen after transformations were performed, creating a ghost image whenever I zoomed in for one frame)

  • hey,
    thank you for the tutorial (=
    but I have a question:
    I use a Leveleditor to create the game-levels.
    You can choose “blocks” and you can set them somewhere in the editor. Then you save this file and open it while playing the current level in game.
    The problem: When you want to zoom / rotate the “blocks” the level starts “flashing” – so there are white lines that are blinking the whole time while you are zooming (on the border of every tile-block)
    In an other forum I asked for this and sb. told me to render the level or I should try to create “overlapping tiles” (so that the tiles overlap each other). I tried that but It doesn´t work…
    do you know what the problem is.. because I don´t know how to render my level- so maybe there is an other way to solve the problem?!
    thank you (=

  • i am just learning c#/xna!

    There is an error:
    The name “ViewportWidth” in the current context does not exist.
    The name “ViewportHeight” in the current context does not exist.

  • I noticed that the coordinate system doesn’t change when you zoom in the camera.
    I made a tweak and now works: in the function “get_transformation”, change:
    “new Vector3(-_pos.X, -_pos.Y, 0))”
    in “new Vector3(-_pos.X * Zoom, -_pos.Y * Zoom, 0))”
    (notice the *Zoom). You may want to change the code in the example.

  • @lolxdfly
    public Matrix get_transformation(GraphicsDevice graphicsDevice)
    {
    Viewport viewPort= graphicsDevice.Viewport;
    // Name of Graphics device, from the function get_

    // rename the ViewportWidth to call the new viewPort.Width; we just added.
    Matrix.CreateTranslation(new Vector3(viewPort.Width * 0.5f, viewPort.Height * 0.5f, 0));

    Alternatively you do something like
    var ViewportWidth = graphicsDevice.Viewport.Width;

  • Hi can u explain what is this graphic device? in you parameter ing cam.get_transformation? Sorry im just a noooobie in xna

  • Excellent! It works!
    I just need the zoom to zoom in on the centre instead of the top-left.

    Thank you, David.

  • Hi David,

    Thanks for the great tutorial, you really helped out with my project!

    I see in your video that the bottom left text does not zoom with the rest of the game. Could you please show how this can be done? So far I can make the text move next to the camera, but if the Camera.Zoom 1.0f then the text is out of place.

    Many thanks in advance for your assistance!

  • I’m learning XNA by creating my own RPG game from scratch and thought that I was “too far” into the process to add camera stuff, thinking I’d need to rewrite a bunch of code. But nope, this tutorial was incredibly simple and straightforward, and I only needed to change one line after writing up a camera class.

    Thanks for posting this, it certainly demystified a bunch of XNA stuff for me!

Leave a Reply

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