Simulating landscape mode with the Windows Phone Developer Tools April CTP

The current CTP for the Windows Phone Developer Tools does not include the final scaling/rotation logic that will automatically handle orientation for XNA Game Studio games. Because of this it can be hard to start working on a landscape game for Windows Phone.

One way to work around this is to utilize a Windows copy of your game, however this removes the ability to use the TouchPanel class for input as well as any phone specific APIs such as the accelerometer or photo chooser, for example.

This post will describe the second way in which you can simulate landscape mode using a RenderTarget2D to handle the graphics as well as a small game component that keeps the TouchPanel class working in landscape mode so you don't have to manually change the touch input coordinates, which will make your life much easier when the automatic orientation functionality is available.

First we'll handle the drawing. You'll want to add a new RenderTarget2D variable to your main game class.

 RenderTarget2D landscapeTarget;

Next we’ll create this render target with a resolution of 800x480 and the same formats as our current backbuffer and depth/stencil buffer. This code should go in LoadContent.

 landscapeTarget = new RenderTarget2D(
    GraphicsDevice, 
    800, 
    480, 
    false, 
    GraphicsDevice.PresentationParameters.BackBufferFormat, 
    GraphicsDevice.PresentationParameters.DepthStencilFormat);

Next we’ll update our Draw method to use this render target for all of our game rendering by setting the rendertarget, performing all game rendering, then unsetting and drawing the render target to the screen, rotated to match the emulator’s portrait mode.

 protected override void Draw(GameTime gameTime)
{
    // set our landscape render target
    GraphicsDevice.SetRenderTarget(landscapeTarget);

    // clear the render target
    GraphicsDevice.Clear(Color.CornflowerBlue);

    // perform all game rendering in landscape mode (800x480)

    // allow any drawable game components to render
    base.Draw(gameTime);

    // unset the rendertarget
    GraphicsDevice.SetRenderTarget(null);

    // clear the backbuffer
    GraphicsDevice.Clear(Color.Black);

    // draw the render target to the screen, rotated into portrait 
    // mode
    spriteBatch.Begin();
    spriteBatch.Draw(
        landscapeTarget,
        new Rectangle(240, 400, 800, 480),
        null,
        Color.White,
        MathHelper.PiOver2,
        new Vector2(400, 240),
        SpriteEffects.None,
        0);
    spriteBatch.End();
}

If you run your game now, you’ll see your game is rendered in landscape mode on the emulator. However all touch input is still coming in portrait coordinates. You could convert these by hand, but the framework can already do this for you if you set the right properties on TouchPanel. However, these properties are reset anytime the graphics device is reset, which means you have to make sure you track all those resets. To this end, I’ve made a little component you can drop into your game that will handle all of this for you, which makes it much easier to strip out once the framework is handling this all for you.

 public class LandscapeTouchPanelComponent : GameComponent
{
    private bool resetTouchPanel;

    public LandscapeTouchPanelComponent(Game game) : base(game) { }

    public override void Initialize()
    {
        // anytime the graphics device is reset, it will reset the touch 
        // panel, so we need to switch it back to landscape mode after 
        // every reset. we need to do this switch on the next update because
        // the touch panel is set after the DeviceReset event, so we just 
        // set a flag.
        Game.GraphicsDevice.DeviceReset += 
            (sender, eventArgs) => resetTouchPanel = true;

        // we want to reset the panel at start up since it defaults to 
        // portrait mode
        resetTouchPanel = true;
    }

    public override void Update(GameTime gameTime)
    {
        // if we need to reset the touch panel, we use landscape left and 
        // 800x480 and unset our flag.
        if (resetTouchPanel)
        {
            TouchPanel.DisplayOrientation =DisplayOrientation.LandscapeLeft;
            TouchPanel.DisplayWidth = 800;
            TouchPanel.DisplayHeight = 480;
            resetTouchPanel = false;
        }
    }
}

Now in your game constructor you can just add this component.

 Components.Add(new LandscapeTouchPanelComponent(this));

And now you’ll notice that any of your TouchLocation positions from TouchPanel.GetState() are automatically put into landscape coordinates for you.

Remember that all of this will be done for you in the final version, but for now this should be enough to get you up and running with a landscape game in the emulator.