Making your own WP7 Angry Birds – Part 5 – Camera? Action!

Up until now our world was restricted to a 800×480 view. We’d like our game to have a slightly larger playing field however, especially on the horizontal axis.

To achieve this we need to introduce a camera, which can pan horizontally. The only tricky part is that the camera will affect our input handling system: when we click on a certain position on the screen, it is no longer an absolute position in our world, but a position relative to the camera’s position.

Our camera will only do horizontal panning, but vertical panning as well as zooming in and out are easy to support later on.

This will be our goal for now: we start with the camera pointed at the left most part of the level. When we catapult our pig, the camera will start travelling to the right, keeping the pig in center view. It will continue to do so until the tower of boxes comes into the center view of the camera. At this point the camera stops panning and we see the impact happening.
See this video which shows a demo of our camera: http://www.youtube.com/watch?v=V4j6y0iNUVs.

1. Initializing the camera

During LoadContent we will initialize our camera and define the horizontal range it can cover. The left most point on the horizontal axis is zero in all cases.
As right most point we choose the to not pan farther than the center of our target: the tower of boxes. We will call this the CenterPointTarget and can be a different value for each level.
Finally, we will also instruct the camera to track our Projectile.

protected override void LoadContent()
{
	...
	Camera.Current.CenterPointTarget = 620f;
	Camera.Current.StartTracking(_projectile.Body);
}

2. Keeping the camera up-to-date

In the Game.Update method we will need to call an Update method on our Camera instance. In this method it will perform the required panning in order to keep our pig centered and stay within our level’s range.

/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
	Camera.Current.Update(gameTime);
	...
}

3. Taking the camera into account when handling input

In our Projectile’s HandleInput method we convert our touch position to a simulated world coordinate by changing this line:

Vector2 touchPositionSim = touchLocation.Position / Constants.Scale;

to:

Vector2 touchPositionSim = Camera.Current.ScreenToSimulation(touchLocation.Position);

4. Seeing the world through the camera’s point of view

Finally, in the Game.Draw method we need to take the camera into account in order to render our level according to the current camera’s panning value.
We will expose a Matrix property on our Camera, which defines the translation. Matrices can be used for translations, rotations, scaling and much more.
One of the overloads of SpriteBatch.Begin accepts such a Matrix.  This transformation matrix will cause our sprites to be rendered by a certain offset on the screen, without having to change their position.

/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
	GraphicsDevice.Clear(Color.CornflowerBlue);

	spriteBatch.Begin(0, null, null, null, null, null, Camera.Current.TransformationMatrix);
	...
}

5. Camera implementation

And here is our implementation of the Camera:

public class Camera
{
	private float _offsetX;
	private Body _trackingBody;

	public Matrix TransformationMatrix { get; private set; }
	public float CenterPointTarget { get; set; }

	public static readonly Camera Current = new Camera();

	private Camera()
	{
	}

	public void Update(GameTime gameTime)
	{
		if (_trackingBody != null)
		{
			// if tracking body is not located in the center of the view (half screen width + current offset)
			if (_trackingBody.Position.X * Constants.Scale != Constants.HalfScreenWidth + _offsetX)
			{
				// move camera's offset so tracking body is dead center again
				_offsetX = Clamp(_trackingBody.Position.X * Constants.Scale - Constants.HalfScreenWidth);
			}
		}

		TransformationMatrix = Matrix.CreateTranslation(-_offsetX, 0f, 0f);
	}

	private float Clamp(float value)
	{
		// Camera's offset is not allowed to move beyond the centerpoint of our target
		return MathHelper.Clamp(value, 0, CenterPointTarget - Constants.HalfScreenWidth);
	}

	public void StartTracking(Body body)
	{
		_trackingBody = body;
	}

	public void StopTracking()
	{
		_trackingBody = null;
	}

	/// <summary>
	/// Converts a location on the screen to a location in our world, taking care of the current camera settings and physics scale.
	/// </summary>
	/// <param name="touchPosition"></param>
	/// <returns></returns>
	public Vector2 ScreenToSimulation(Vector2 touchPosition)
	{
		return Vector2.Transform(touchPosition, Matrix.Invert(TransformationMatrix)) / Constants.Scale;
	}
}

And here’s the glorious result:

Here’s my twitter: http://www.twitter.com/jodegreef

Advertisements

6 Responses to Making your own WP7 Angry Birds – Part 5 – Camera? Action!

  1. Hasan says:

    Really awesome man…thanks for sharing your expertise 🙂

  2. sander says:

    hello guy
    great easy implementation of camera movement.
    why don’t you use camera2d class inside farseer example.
    This class implement all functions that you need (pan, zoom, traking…ect)

    • jodegreef says:

      for the tutorial I try to stay clear from the farseer sample code in order to keep the dependencies to a minimum and to keep the required code for what we want to achieve to a minimum

  3. Pingback: ??? ?? ????? ????? 29-?? ????! ?? ??????? «????????» ????! - MSDN Blogs

  4. loyalpenguin says:

    Hey jodegreef,

    Excellent job creating this Camera class. I wanted to know if you can you provide some guidance on how to further develop this camera class. I was able to implement vertical scrolling with the projectile, but not able to implement manual scrolling. Any suggestions on where I can go to learn how to implement manual horizontal scrolling?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: