How to: Scale Sprites Based On Screen Size

This article demonstrates how to scale sprites using a Matrix that is created based on the Viewport width. This article applies only to Windows programming.

To scale sprites based on screen size

  1. Determine the default screen size of your game. This can be set using the PreferredBackBufferHeight and PreferredBackBufferWidth properties of GraphicsDeviceManager during your game's Initialize.
  2. In your LoadGraphicsContent method, use Matrix.CreateScale to create a scaling matrix outside of the LoadAllContent block. This matrix will get recreated any time the resolution of the GraphicsDevice changes. Because we are scaling sprites, use only the X and Y parameters to create the scaling matrix. Scaling the depth of sprites can result in their depth shifting above 1.0; if that happens, they will not draw.

    protected override void LoadGraphicsContent( bool loadAllContent )
    {
        if (loadAllContent)
        {
            ...
        }
        // Default resolution is 800x600; scale sprites up or down based on
        // current viewport
        float screenscale = graphics.GraphicsDevice.Viewport.Width / 800f;
        // Create the scale transform for Draw. 
        // Do not scale the sprite depth (Z=1).
        SpriteScale = Matrix.CreateScale( screenscale, screenscale, 1 );
    }
  3. In your Update method, determine whether the game needs to change screen resolution. This example uses game pad buttons to switch between two resolutions.

    protected override void Update( GameTime gameTime )
    {
        ...
        // Change the resolution dynamically based on input
        if (GamePad.GetState( PlayerIndex.One ).Buttons.A == ButtonState.Pressed)
        {
            graphics.PreferredBackBufferHeight = 768;
            graphics.PreferredBackBufferWidth = 1024;
            graphics.ApplyChanges();
        }
        if (GamePad.GetState( PlayerIndex.One ).Buttons.B == ButtonState.Pressed)
        {
            graphics.PreferredBackBufferHeight = 600;
            graphics.PreferredBackBufferWidth = 800;
            graphics.ApplyChanges();
        }
        base.Update( gameTime );
    }
  4. In your Draw method, call SpriteBatch.Begin, passing the scaling matrix created in LoadGraphicsContent.
  5. Draw your scene normally, then call SpriteBatch.End. All of the sprites you draw will be scaled according to the matrix.

    protected override void Draw( GameTime gameTime )
    {
        ...
        // Initialize the batch with the scaling matrix
        batch.Begin( SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, 
            SaveStateMode.None, SpriteScale );
        // Draw a sprite at each corner
        for (int i = 0; i < spritepos.Length; i++)
        {
            batch.Draw( square, spritepos[i], null, Color.White, rotation, origin, scale, SpriteEffects.None,
                depth );
        }            
        batch.End();
        base.Draw( gameTime );
    }
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
protected override void Initialize()
{
    // TODO: Add your initialization logic here
    graphics.PreferredBackBufferHeight = 600;
    graphics.PreferredBackBufferWidth = 800;

    base.Initialize();
}
Texture2D square;
SpriteBatch batch;
Vector2[] spritepos;
Matrix SpriteScale;
protected override void LoadGraphicsContent( bool loadAllContent )
{
    if (loadAllContent)
    {
        // Load a sprite to draw at each corner
        batch = new SpriteBatch( graphics.GraphicsDevice );
        square = content.Load<Texture2D>( "sprite" );

        // Create the corners where the sprites will be drawn
        spritepos = new Vector2[4];
        spritepos[0] = new Vector2( 42, 42 );
        spritepos[1] = new Vector2( graphics.GraphicsDevice.Viewport.Width - 42, 42 );
        spritepos[2] = new Vector2( 42, graphics.GraphicsDevice.Viewport.Height - 42 );
        spritepos[3] = new Vector2( spritepos[1].X, spritepos[2].Y );
    }
    // Default resolution is 800x600; scale sprites up or down based on
    // current viewport
    float screenscale = graphics.GraphicsDevice.Viewport.Width / 800f;
    // Create the scale transform for Draw. 
    // Do not scale the sprite depth (Z=1).
    SpriteScale = Matrix.CreateScale( screenscale, screenscale, 1 );
}
protected override void Update( GameTime gameTime )
{
    // Allows the game to exit
    if (GamePad.GetState( PlayerIndex.One ).Buttons.Back == ButtonState.Pressed)
        this.Exit();

    // Change the resolution dynamically based on input
    if (GamePad.GetState( PlayerIndex.One ).Buttons.A == ButtonState.Pressed)
    {
        graphics.PreferredBackBufferHeight = 768;
        graphics.PreferredBackBufferWidth = 1024;
        graphics.ApplyChanges();
    }
    if (GamePad.GetState( PlayerIndex.One ).Buttons.B == ButtonState.Pressed)
    {
        graphics.PreferredBackBufferHeight = 600;
        graphics.PreferredBackBufferWidth = 800;
        graphics.ApplyChanges();
    }
    base.Update( gameTime );
}
protected override void Draw( GameTime gameTime )
{
    graphics.GraphicsDevice.Clear( Color.CornflowerBlue );

    // Set draw parameters
    Vector2 origin = new Vector2( 32 );
    float rotation = 0;
    float depth = 0;
    float scale = 1;

    // Initialize the batch with the scaling matrix
    batch.Begin( SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, 
        SaveStateMode.None, SpriteScale );
    // Draw a sprite at each corner
    for (int i = 0; i < spritepos.Length; i++)
    {
        batch.Draw( square, spritepos[i], null, Color.White, rotation, origin, scale, SpriteEffects.None,
            depth );
    }            
    batch.End();
    base.Draw( gameTime );
}
Show: