How do I scale the graphics of a game?

493 views Asked by At

I'm making a game in C# and XNA 4.0. It's pretty much finished, but now I want to add settings so that players can change the window size if they want to. The current setup goes like this:

void Initialize()
{
    //The window size is initally 800x480
    graphics.PreferredBackBufferWidth = 800;
    graphics.PreferredBackBufferHeight = 480;
    graphics.ApplyChanges();
}

void Update()
{
    //If the player completes an action, the window size is changed
    if (windowSizeChanged)
    {
        graphics.PreferredBackBufferWidth = 1024;
        graphics.PreferredBackBufferHeight = 720;
        graphics.ApplyChanges();
    }
}

Using this code, this is what the game looks like at specific resolutions:

800x480 enter image description here

1024x720 enter image description here

As you can hopefully see, when the window size is changed it does not affect the actual graphics of the game. The sprites and hitboxes of all of the objects stay the same size, so they instead fill up a small box in the corner of the screen rather than the entire window. Can anyone tell me how I can scale the sprites so that they fill up the window? I assume I would need to use a matrix of some sort, but can anyone point me in the right direction?

Edit:

Here's the draw code.

void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.CornflowerBlue);

    base.Draw(gameTime);

    spriteBatch.Begin();

    //Background texture drawn at default window size
    spriteBatch.Draw(background, new Rectangle(0, 0, 800, 480), Color.White);

    //Each object in the level (player, block, etc.) is drawn with a specific texture and a rectangle variable specifying the size and coordinates
    //E.g. Each block is a size of 64x64 pixels and in this level they are placed at X-coordinates 0, 64, 128 and so on
    //Each Y-coordinate for the blocks in this level is '480 - 64' (Window height minus block height)
    foreach (/*Object in level*/)
    {
        spriteBatch.Draw(object.Texture, object.TextureSize, Color.White);
    }

    spriteBatch.End();
}
1

There are 1 answers

0
Jaanus Varus On BEST ANSWER

By default, SpriteBatch assumes that your world space is the same as client space, which is the size of the window. You can read about SpriteBatch and different spaces in a post by Andrew Russell.

When you are resizing the backbuffer, the window size will also change changing the world space together with it (which you don't want). In order not to allow that, you should stick a transformation matrix in between the transformation pipeline to make that correction.

SpriteBatch.Begin allows exactly that in one of its overloads.

There are numerous ways to approach the scaling, but I assume that you want to scale uniformly, meaning that sprites don't get stretched out when the aspect ratio changes compared to the initial aspect ratio. The following code will adjust the scaling based on initial screen height.

...

const float initialScreenHeight = 480f; 
Matrix transform = Matrix.CreateScale(GraphicsDevice.Viewport.Height / viewportHeightInWorldSpace);

spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, transform);

...

Note that when changing the resolution such that the aspect ratio changes compared to the initial aspect ratio, you will run into issues such as drawing out of screen (to the right) or not drawing at the right edge of the screen (getting a similar blue background as currently).

Also, you don't want to calculate that scaling matrix every frame in the Draw method, but only when the resolution is changed.