When I first started making my game, I hard coded the screen resolution to 800 x 600 for simplicity and built my menus and levels with the assumption that the screen was exactly 800 pixels wide and 600 pixels high. This was a mistake because all of my UI positions, tile positions, and entity placements were based on absolute positions and did not look proper when the resolution changed. If the user wanted to use a screen size that was not 4:3 and super tiny, the game looked completely wrong and was unplayable because the level layout was all over the place.
To solve this, I used David Amador’s Resolution class to introduce a means of rendering my scenes independent of the actual resolution of the window. I maintained an “internal” or “virtual” resolution of 1280 x 720 (Xbox standard) to be used for position of all my entities and UI elements. This virtual resolution never changes. Users can then adjust the “actual” resolution of the game which determines the real window size. We use a scaling matrix to transform the virtual resolution to fill the actual resolution with additional letterboxes or pillarboxes depending on the virtual and actual resolutions. I suggest you read the linked article from David Amador to understand the class and how to use it.
Changes for XNA 4
David’s article is what really counts when it comes making this work. However, it was written pre-XNA 4 and requires a minor change. Calls to SpriteBatch.Begin() require more parameters in the overload that allows for a transform matrix. The current method of using David’s code to scale your virtual resolution up to the actual resolution is:
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, null, Resolution.getTransformationMatrix());
Obviously, your needs will dictate the exact parameters, but this is the overload you need to use at the very basic level.
Transforming Mouse Coordinates
Another problem you’ll run into is when trying to use mouse coordinates to interact with the elements of your game. The transformation matrix is applied only to the sprite rendering and does not affect the state of the mouse cursor. For example, using a straight up MouseState.GetState() will return coordinates in terms of the actual resolution and not the virtual resolution. Since your game is working in terms of the virtual resolution, this behavior is wrong!
Luckily, one of the commentors in David’s article explained a way to transform mouse coordinates into the virtual screen space. Here is a simple static abstraction that I created to get mouse position in terms of virtual resolution.
First, add two static members to the Resolution class.
static private int virtualViewportX;
static private int virtualViewportY;
Second, assign values in the ResetViewport() method.