Page 1 of 1

2D Camera in XNA

#1 bonyjoe

• D.I.C Addict

Reputation: 178
• Posts: 548
• Joined: 08-September 10

Posted 03 July 2011 - 12:35 PM

POPULAR

Many people when creating 2D games will struggle to simulate a camera, sometimes moving all objects in the game world during the update, or other times using an offset value to calculate the position at draw time. While both these solutions work, they can become fiddly in more complex situations and do not allow for camera rotation or zooming.

This tutorial will show you how to create a simple camera class that allows for movement, rotation and zoom. It will also give an example input class and method to transform the mouse coordinates so that object picking can still work correctly.

Fields
```  protected float _zoom; //Camera Zoom Value
protected Matrix _transform; //Camera Transform Matrix
protected Matrix _inverseTransform; //Inverse of Transform Matrix
protected Vector2 _pos; //Camera Position
protected float _rotation; //Camera Rotation Value (Radians)
protected Viewport _viewport; //Cameras Viewport
protected MouseState _mState; //Mouse state
protected KeyboardState _keyState; //Keyboard state
protected Int32 _scroll; //Previous Mouse Scroll Wheel Value
```

Some general fields are needed for the camera, most are self explanatory and the last 3 are only needed if you wish to control the camera from within this class. The InverseTransform is needed if you use any kind of mouse interaction with objects that are being transformed by the camera.

Properties
```public float Zoom
{
get { return _zoom; }
set { _zoom = value; }
}
/// <summary>
/// Camera View Matrix Property
/// </summary>
public Matrix Transform
{
get { return _transform; }
set { _transform = value; }
}
/// <summary>
/// Inverse of the view matrix, can be used to get objects screen coordinates
/// from its object coordinates
/// </summary>
public Matrix InverseTransform
{
get { return _inverseTransform; }
}
public Vector2 Pos
{
get { return _pos; }
set { _pos = value; }
}
public float Rotation
{
get { return _rotation; }
set { _rotation = value; }
}
```

The protected fields need public properties so that they can be accessed from outside of the class. I have kept the properties simple and not included any logic, all the logic is handled in the update method below.

Update Method
```        public void Update()
{
//Call Camera Input
Input();
//Clamp zoom value
MathHelper.Clamp(_zoom, 0.01f, 10.0f);
//Clamp rotation value
_rotation = ClampAngle(_rotation);
//Create view matrix
_transform =    Matrix.CreateRotationZ(_rotation) *
Matrix.CreateScale(new Vector3(_zoom, _zoom, 1)) *
Matrix.CreateTranslation(_pos.X, _pos.Y, 0);
//Update inverse matrix
_inverseTransform = Matrix.Invert(_transform);
}
```

The update is fairly straight forward, but I will explain some things. The zoom is clamped because if a negative value is used to scale the scene then the scene will be flipped as well as scaled, this is not what we want. The ClampAngle function just ensures that the angle will be between pi and -pi, the source can be found in the class code at the bottom of the tutorial.

The main part of this update is calculating the transform matrix, I won't go into the maths too much but it basically creates a matrix by combining a rotation matrix, scale matrix and translation matrix. The translation is done last as this means that the scene will rotate around (0,0) in object coordinates.

Constructor
```  public Camera2D(Viewport viewport)
{
_zoom = 1.0f;
_scroll = 1;
_rotation = 0.0f;
_pos = Vector2.Zero;
_viewport = viewport;
}
```

The constructor is basic and just sets the camera values.

Using the Camera to Draw

XNA 4.0
```spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null, cam.Transform);
//Draw Any Scene Stuff Here
spriteBatch.End();
```

XNA 3.1
```spriteBatch.Begin(SpriteBlendMode.AlphaBlend,
SpriteSortMode.Immediate,
SaveStateMode.SaveState,
cam.Transform);
//Draw Any Scene Stuff Here
spriteBatch.End();
```

Drawing is simple, anything that you want to be manipulated by the camera should go between these begin and end calls. If you want a GUI or anything that won't be affected by the camera view you can draw between standard Begin() and End() calls.

Transforming Mouse to Object Coordinates
```      mState = Mouse.GetState();
Vector2 mouse = new Vector2(mState.X, mState.Y);
mouse = Vector2.Transform(mouse, cam.InverseTransform);
```

To use the mouse to interact with objects that are shown using the camera, first the mousestate should be captured, the x and y coordinates must then be used to populate a Vector2. This Vector2 can then be transformed using the inverse of the camera transform matrix. Now the X and Y of the Vector2 are the X and Y coordinates of the Mouse in object space. You can use these coordinates in the same way you normally use the mouse X and Y coordinates.

That's pretty much all there is to it, this can be used in pretty much any 2D game that needs to scroll, zoom or rotate and as you can see it is fairly easy to implement. Here is the full class code including the ClampAngle method and an example Input method.

Full Class Code
```#region Version History (1.0)
// 03.07.11 ~ Created
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace CameraTest
{
public class Camera2D
{
#region Fields

protected float _zoom;
protected Matrix _transform;
protected Matrix _inverseTransform;
protected Vector2 _pos;
protected float _rotation;
protected Viewport _viewport;
protected MouseState _mState;
protected KeyboardState _keyState;
protected Int32 _scroll;

#endregion

#region Properties

public float Zoom
{
get { return _zoom; }
set { _zoom = value; }
}
/// <summary>
/// Camera View Matrix Property
/// </summary>
public Matrix Transform
{
get { return _transform; }
set { _transform = value; }
}
/// <summary>
/// Inverse of the view matrix, can be used to get objects screen coordinates
/// from its object coordinates
/// </summary>
public Matrix InverseTransform
{
get { return _inverseTransform; }
}
public Vector2 Pos
{
get { return _pos; }
set { _pos = value; }
}
public float Rotation
{
get { return _rotation; }
set { _rotation = value; }
}

#endregion

#region Constructor

public Camera2D(Viewport viewport)
{
_zoom = 1.0f;
_scroll = 1;
_rotation = 0.0f;
_pos = Vector2.Zero;
_viewport = viewport;
}

#endregion

#region Methods

/// <summary>
/// Update the camera view
/// </summary>
public void Update()
{
//Call Camera Input
Input();
//Clamp zoom value
_zoom = MathHelper.Clamp(_zoom, 0.0f, 10.0f);
//Clamp rotation value
_rotation = ClampAngle(_rotation);
//Create view matrix
_transform =    Matrix.CreateRotationZ(_rotation) *
Matrix.CreateScale(new Vector3(_zoom, _zoom, 1)) *
Matrix.CreateTranslation(_pos.X, _pos.Y, 0);
//Update inverse matrix
_inverseTransform = Matrix.Invert(_transform);
}

/// <summary>
/// Example Input Method, rotates using cursor keys and zooms using mouse wheel
/// </summary>
protected virtual void Input()
{
_mState = Mouse.GetState();
_keyState = Keyboard.GetState();
//Check zoom
if (_mState.ScrollWheelValue > _scroll)
{
_zoom += 0.1f;
_scroll = _mState.ScrollWheelValue;
}
else if (_mState.ScrollWheelValue < _scroll)
{
_zoom -= 0.1f;
_scroll = _mState.ScrollWheelValue;
}
//Check rotation
if (_keyState.IsKeyDown(Keys.Left))
{
_rotation -= 0.1f;
}
if (_keyState.IsKeyDown(Keys.Right))
{
_rotation += 0.1f;
}
//Check Move
if (_keyState.IsKeyDown(Keys.A))
{
_pos.X += 0.5f;
}
if (_keyState.IsKeyDown(Keys.D))
{
_pos.X -= 0.5f;
}
if (_keyState.IsKeyDown(Keys.W))
{
_pos.Y += 0.5f;
}
if (_keyState.IsKeyDown(Keys.S))
{
_pos.Y -= 0.5f;
}
}

/// <summary>
/// Clamps a radian value between -pi and pi
/// </summary>
/// <param name="radians">angle to be clamped</param>
/// <returns>clamped angle</returns>
protected float ClampAngle(float radians)
{
while (radians < -MathHelper.Pi)
{
radians += MathHelper.TwoPi;
}
while (radians > MathHelper.Pi)
{
radians -= MathHelper.TwoPi;
}
return radians;
}

#endregion
}
}

```

Is This A Good Question/Topic? 8

Replies To: 2D Camera in XNA

#2 stayscrisp

• フカユ

Reputation: 1037
• Posts: 4,305
• Joined: 14-February 08

Posted 07 July 2011 - 02:41 AM

Good work! This is extremely useful stuff Keep it up.
Was This Post Helpful? 0

#3 Kilorn

• XNArchitect

Reputation: 1358
• Posts: 3,528
• Joined: 03-May 10

Posted 07 July 2011 - 05:34 AM

Well done, bonyjoe! Now if only I could convince Chris to create a separate section for XNA Tutorials.
Was This Post Helpful? 0

#4 KingofSpace

• New D.I.C Head

Reputation: 1
• Posts: 9
• Joined: 04-August 13

Posted 06 December 2013 - 06:11 PM

Hello,
I hate to bump an old thread, but I am really thankful for this.
This was the only 2D camera tutorial that helped me get my game going. It was a really big leap for me, I was having lots of issues with implementing a camera system.
Was This Post Helpful? 0

#5 LithiumBeach

• New D.I.C Head

Reputation: 0
• Posts: 1
• Joined: 11-November 14

Posted 11 November 2014 - 12:34 PM

It's a few years after the post, but man this was extremely helpful and easy to implement. Quick note: if you want to use this, pass in GraphicsDevice.Viewport to the Camera constructor.

```Camera2D cam = new Camera2D(GraphicsDevice.Viewport);
```

Thank you bonyjoe!
Was This Post Helpful? 0

Page 1 of 1

 .related ul{list-style-type:circle;font-size:12px;font-weight:bold;}.related li{margin-bottom:5px;background-position:left 7px!important;margin-left:-35px;}.related h2{font-size:18px;font-weight:bold;}.related a{color:blue;}