The OrientationSupport example project
demonstrates the problem that we need to address—and its solution. If
you start the project running with the device or emulator in portrait
mode, you will see that it displays three textured squares just as in
the alpha blending example, except that this time they rotate back and
forth so that they stay essentially upright. This will allow us to
ensure that the graphics are being kept the right way up and are not
appearing sideways.
The initial display from the project is just as we
would expect, with the squares arranged vertically above one another.
The project is configured to support all three of the Windows Phone 7
orientations, however, so now rotate the device or the emulator so that
it is in a landscape orientation.
XNA correctly rotates the screen so that the
graphics remain upright (the grapes are still the right way up, and the
objects are still arranged vertically within the new orientation).
However, the objects are no longer square: they are instead very
squashed, as can be seen in Figure 1.
This is where we calculated the aspect ratio for the screen by dividing
the back buffer width by its height. For a portrait screen, this
calculation is 480 / 800, which equals 0.6. For a landscape screen,
however, the calculation is 800 / 480, which results in 1.666. Because
XNA is still rendering with the original portrait aspect ratio, it
continues after rotation to render with the belief that the screen
width is 6/10 of its height, which it no longer is.
To address the problem, we simply need to
recalculate the aspect ratio when the orientation changes. We can add a
handler for the Window.OrientationChanged event in the game class's constructor, as shown in Listing 1.
Example 1. Handling the window's OrientationChanged event
// Add a handler to update projection matrix if the orientation changes Window.OrientationChanged += new EventHandler<EventArgs>(Window_OrientationChanged);
|
The implementation of the OrientationChanged event is shown in Listing 2. This does result in a small amount of code duplication as the Initialize
function also sets the projection matrix, so you might want to separate
this out into a separate function that can be called from each of these
two locations. For simplicity, we will duplicate the code in this
example.
Example 2. Updating the projection matrix when the screen orientation changes
void Window_OrientationChanged(object sender, EventArgs e) { // Calculate the new screen aspect ratio float aspectRatio = (float)GraphicsDevice.Viewport.Width / GraphicsDevice.Viewport.Height; // Create a projection matrix Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), aspectRatio, 0.1f, 1000.0f); // Set the matrix into the effect _effect.Projection = projection; }
|
This block of code is initially commented out in the OrientationSupport
example project, which is why the graphics appeared distorted after the
orientation was changed. Uncomment the code and then run the project
again. This time you will see that the behavior after rotation from
portrait to landscape is quite different: the objects are no longer
distorted, and the scene "zooms out" so that the amount of vertical
space that is displayed on the screen is the same in landscape
orientation as it was in portrait. This can be seen in Figure 2.
Although the objects appear smaller than
they were, the code to render them and the transformations that are
applied are completely unchanged; it is just the projection matrix that
has caused the change in appearance.