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.

180 Comments

  1. Koja

    Thank you so much for quick reply. My game is running in full screen mode.

    graphics.PreferredBackBufferWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;

    graphics.PreferredBackBufferHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;

    graphics.IsFullScreen = true;

    When I remove graphics.IsFullScreen = true; camera works fine but then players can see taskbar, buttons for minimize, maximize, close and I don’t like that.//graphics.IsFullScreen = true; Do you have any suggestion how to solve this? Thanks again!

  2. Koja

    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!

  3. Umair

    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?

  4. Steve

    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?

  5. Steve

    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!

  6. 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)

  7. Mo

    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 (=

  8. lolxdfly

    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.

  9. Alex

    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.

  10. @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;

  11. nelz

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

  12. Janus

    This is awesomely simple and well explained. Thank you!

  13. apophis117

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

    Thank you, David.

  14. xnaGuy

    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!

  15. goshohib

    it’s very useful. thanks alot sir

  16. Rob

    Thank you so so so so mcuh!

  17. Pingback: XNA to libGDX: 2D Rendering – Part 8 - JKs Games

Leave a Reply