I'm currently working on a 2D camera class for the MonoGame.Extended library. This post describes how it's implemented.

The purpose of having a camera class is to make it easier to move around a game world without having to manually calculate positions or matrices all the time. All the projection and view matrix operations are hidden in the implementation of the camera.

The primary goal of the camera in a 2D game using MonoGame is to create a transformation matrix that can be applied to each SpriteBatch.Begin call.

A basic implementation looks like this:

public class Camera2D
{
    private readonly Viewport _viewport;

    public Camera2D(Viewport viewport)
    {
        _viewport = viewport;

        Rotation = 0;
        Zoom = 1;
        Origin = new Vector2(viewport.Width / 2f, viewport.Height / 2f);
        Position = Vector2.Zero;
    }

    public Vector2 Position { get; set; }
    public float Rotation { get; set; }
    public float Zoom { get; set; }
    public Vector2 Origin { get; set; }

    public Matrix GetViewMatrix()
    {
        return 
            Matrix.CreateTranslation(new Vector3(-Position, 0.0f)) *
            Matrix.CreateTranslation(new Vector3(-Origin, 0.0f)) *
            Matrix.CreateRotationZ(Rotation) *
            Matrix.CreateScale(Zoom, Zoom, 1) *
            Matrix.CreateTranslation(new Vector3(Origin, 0.0f)); 
    }
}

To use it simply create an instance of the class as a member variable an initialize it with the viewport.

protected override void Initialize()
{
    _camera = new Camera2D(GraphicsDevice.Viewport);
    base.Initialize();
}

Then in the Draw method pass it in as the last parameter of each SpriteBatch.Begin call, or use named parameters like I've done here:

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

    var viewMatrix = _camera.GetViewMatrix();
    _spriteBatch.Begin(transformMatrix: viewMatrix);
    ...
    _spriteBatch.End();
}

In the Update method you'll usually want to move, rotate or zoom the camera around somehow.

protected override void Update(GameTime gameTime)
{
    var deltaTime = (float) gameTime.ElapsedGameTime.TotalSeconds;
    var keyboardState = Keyboard.GetState();

    // rotation
    if (keyboardState.IsKeyDown(Keys.Q))
        _camera.Rotation -= deltaTime;

    if (keyboardState.IsKeyDown(Keys.W))
        _camera.Rotation += deltaTime;

    // movement
    if (keyboardState.IsKeyDown(Keys.Up))
        _camera.Position -= new Vector2(0, 250) * deltaTime;

    if (keyboardState.IsKeyDown(Keys.Down))
        _camera.Position += new Vector2(0, 250) * deltaTime;
    
    if (keyboardState.IsKeyDown(Keys.Left))
        _camera.Position -= new Vector2(250, 0) * deltaTime;
    
    if (keyboardState.IsKeyDown(Keys.Right))
        _camera.Position += new Vector2(250, 0) * deltaTime;

    base.Update(gameTime);
}

That's pretty much it for a very basic camera. However, there are many more things you can do with a 2D camera implementation.

  • Look At - moving the camera to look directly at a particular point (e.g. the player)
  • Projection - transforming points between screen space and world space (e.g. mouse picking)
  • Directional movement - moving the camera along it's local direction vector (taking rotation into account)
  • Paralax scrolling - creating the effect of depth by scrolling each layer at a different speed

All of thse are implemented in the MonoGame.Extended library. Take a look how it's done in the source code on github.

Happy coding! :)