7
\$\begingroup\$

I am developing a game with XNA, and I am having trouble with resolutions. For now, I have only implemented the main menu, but I want to make a game that is independent of the resolution. As I am a beginner, I haven't taken into account the resolution, so far. When I changed the resolution, it gave me a real headache. The background image that I use has a 1920x1080 resolution, so it has an aspect ratio of 16:9. The initial resolution was 800x600, so the background image looks stretched. The same happens with resolutions with aspect ratio 4:3 (e.g. 640x480, 1024x768, etc.).

Before posting this question, I searched for information on the Internet. I found "XNA 2D Independent Resolution Rendering", and other similar solutions. The solution offered seems perfect for me, at first, because I wasn't thinking of using two resolutions; one internal, for drawing, and one that corresponds to the size of the window. However, I have been observing some problems.


When I enable fullscreen mode, and its resolution is lower than the desktop resolution, the game doesn't stretch the resolution to fill the entire screen. This makes the game draw at the center of the screen, but with a black border on both sides of the screen.

enter image description here


The aspect ratio of my background image is 16:9, however, the resolutions that I am trying have an aspect ratio of 4:3. With the page solution, I have the same problem; the background image seems to be stretched. I researched the code, to find a solution, and changed the RecreateScaleMatrix() function to this:

private static void RecreateScaleMatrix() 
{
    _dirtyMatrix = false;
    float aspect = 16.0f / 9.0f;
    _scaleMatrix =
        Matrix.CreateScale((float)_device.GraphicsDevice.Viewport.Width / _virtualWidth,
        (float)_device.GraphicsDevice.Viewport.Height / _virtualHeight, 1f) *
        Matrix.CreateScale(1, EngineManager.GameGraphicsDevice.Viewport.AspectRatio / 
        aspect, 1) * Matrix.CreateTranslation(0, (_device.GraphicsDevice.Viewport.Height - 
        (_device.GraphicsDevice.Viewport.Height / aspect)) / 4.0f, 0);
}

This seems to have solved the problem, but only on certain resolutions ,and further reducing the rectangle which show the final result.


I have been thinking about these problems all day, and I realized that without knowing the exact resolution of the image to draw, in advance (independent of aspect ratio), is almost impossible to draw an image clearly.

How do I solve my resolution problems?

\$\endgroup\$
4
\$\begingroup\$

The most simple answer is what you've already found: draw everything internally to a RenderTarget with a fixed resolution and after that use the RenderTarget as a texture and draw it as large as possible. You should be able to fill the entire screen if the aspect ratio is the same. Simply use the Spritebatch.Draw overload that uses a destination rectangle. If you use an internal resolution with an aspect ratio of 16:9 then you should create a rectangle like this:

//If the internal resolution and target resolution are both 16:9
Rectangle dest = new Rectangle
    (
        0,
        0,
        graphics.ViewPort.Width,
        graphics.ViewPort.Height
    );

//If the internal resolution is 16:9 and target resolution is 4:3
int height = (int)(graphics.ViewPort.Width * (16.0/9.0));
Rectangle dest = new Rectangle
    (
        0,
        graphics.ViewPort.Height - (int)(height / 2.0),
        graphics.ViewPort.Width,
        height
    );

Another approach would be to make sure that all text and GUI elements are withing a safe in the render target that has a 4:3 aspect ratio and then simply discard the most left and right part on a 4:3 screen. (This might give players with a 16:9 aspect ratio an advantage since they will have a larger FOV).

Tip: if you are developing your game for the XBOX360 you can jus develop for one resoltion since the XBOX will do the up and down scaling automatically for you. You should use an internal resolution of 720P since this is the highest resolution that the XBOX upscaler/downscaler can scale down to old-TV resolution.

Edit:

See the comments: the general formula for the destination rectangle that works for all aspect ratios where width >= height would be:

double aspectratio = ((double)graphics.ViewPort.Width / (double)graphics.Viewport.Height);
    int height = (int)(graphics.ViewPort.Width * aspectratio;
    Rectangle dest = new Rectangle
        (
            0,
            graphics.ViewPort.Height - (int)(height / 2.0),
            graphics.ViewPort.Width,
            height
        );
\$\endgroup\$
  • 1
    \$\begingroup\$ Don't forget about 16:10 which is also a fairly common monitor size as well. \$\endgroup\$ – Matthew Scharley Aug 13 '12 at 1:25
  • \$\begingroup\$ Ah you're absolutely right! I've added the general formula that should work for all aspect ratios where the screen width >= screen height. \$\endgroup\$ – Roy T. Aug 13 '12 at 6:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.