Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Uniformly Resizing a Window in XNA

Tags:

c#

window

xna

Well, I am trying to give my game's window the ability to resize uniformly. I have checked everywhere but I can't seem to find anything about it.

Any ideas?

I can't post the code due to the character limit. It would be much appreciated if someone could please help me out and see what I am doing wrong :)

Also helpful would be how to resize the backbuffer when this happens, as I don't think the game would be playable with only half the sprites visible :)

   void Window_ClientSizeChanged( object sender, EventArgs e )
   {
       int new_width = graphics.GraphicsDevice.Viewport.Width;
       int new_height = graphics.GraphicsDevice.Viewport.Height;

       if (new_width != Variables.SCREEN_WIDTH)
       {
           Variables.SCREEN_HEIGHT = (int)(new_width * ascept_ratio);
           Variables.SCREEN_WIDTH = new_width;
       }
       if (new_height != Variables.SCREEN_HEIGHT)
       {
           Variables.SCREEN_WIDTH = (int)(new_height / ascept_ratio);
           Variables.SCREEN_HEIGHT = new_height;
       }

       UpdateParameters();
   }

...

   public void UpdateParameters()
   {
       graphics.PreferredBackBufferWidth = Variables.SCREEN_WIDTH;
       graphics.PreferredBackBufferHeight = Variables.SCREEN_HEIGHT;
       graphics.ApplyChanges();
   }

Thanks,

Kind Regards, Darestium

like image 615
Darestium Avatar asked Dec 06 '11 07:12

Darestium


1 Answers

To keep the aspect ratio you mean?

You'd do this the same as any WinForms project:

When the form loads up store the aspect radio: (float)Width/(float)Height. In XNA, this could be in the LoadContent of your game (since the window would be created by then).

Then, handle the form's sizechanged event. You'll need to keep track of whether the user is changing height, width or both. If it's height, then set the Width = Height / AspectRatio, if the width changes set Height = Width * AspectRatio.

If both change, then decide on either width or height, (i mean pick either one in design, not each resize) and do as above.


You'll probably have to do things XNA-specific once you've done this, such as resize the backbuffer etc. but this isn't specific to this question so i'll leave it out (ask another question if need be).


EDIT. Below is a minimal, working sample:

It maintains aspect ratio, as well as resizes the graphics by drawing to a render target the original size of the window, then drawing that scaled to fit the new window. If you don't want this remove the overridden BeginDraw and EndDraw methods.

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace WindowsGame1
{
    public class Game1 : Game
    {
        GraphicsDeviceManager Graphics;
        float AspectRatio;
        Point OldWindowSize;
        Texture2D BlankTexture;
        RenderTarget2D OffScreenRenderTarget;
        SpriteBatch SpriteBatch;

        public Game1()
        {
            Graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            Graphics.IsFullScreen = false;
            Window.AllowUserResizing = true;
            Window.ClientSizeChanged += new EventHandler<EventArgs>(Window_ClientSizeChanged);
        }

        void Window_ClientSizeChanged(object sender, EventArgs e)
        {
            // Remove this event handler, so we don't call it when we change the window size in here
            Window.ClientSizeChanged -= new EventHandler<EventArgs>(Window_ClientSizeChanged);

            if (Window.ClientBounds.Width != OldWindowSize.X)
            { // We're changing the width
                // Set the new backbuffer size
                Graphics.PreferredBackBufferWidth = Window.ClientBounds.Width;
                Graphics.PreferredBackBufferHeight = (int)(Window.ClientBounds.Width / AspectRatio);
            }
            else if (Window.ClientBounds.Height != OldWindowSize.Y)
            { // we're changing the height
                // Set the new backbuffer size
                Graphics.PreferredBackBufferWidth = (int)(Window.ClientBounds.Height * AspectRatio);
                Graphics.PreferredBackBufferHeight = Window.ClientBounds.Height;
            }

            Graphics.ApplyChanges();

            // Update the old window size with what it is currently
            OldWindowSize = new Point(Window.ClientBounds.Width, Window.ClientBounds.Height);

            // add this event handler back
            Window.ClientSizeChanged += new EventHandler<EventArgs>(Window_ClientSizeChanged);
        }

        protected override void LoadContent()
        {
            // Set up initial values
            AspectRatio = GraphicsDevice.Viewport.AspectRatio;
            OldWindowSize = new Point(Window.ClientBounds.Width, Window.ClientBounds.Height);

            BlankTexture = new Texture2D(GraphicsDevice, 1, 1);
            BlankTexture.SetData(new Color[] { Color.FromNonPremultiplied(255, 255, 255, 255) });
            SpriteBatch = new SpriteBatch(GraphicsDevice);

            OffScreenRenderTarget = new RenderTarget2D(GraphicsDevice, Window.ClientBounds.Width, Window.ClientBounds.Height);
        }

        protected override void UnloadContent()
        {
            if (OffScreenRenderTarget != null)
                OffScreenRenderTarget.Dispose();

            if (BlankTexture != null)
                BlankTexture.Dispose();

            if (SpriteBatch != null)
                SpriteBatch.Dispose();

            base.UnloadContent();
        }

        protected override bool BeginDraw()
        {
            GraphicsDevice.SetRenderTarget(OffScreenRenderTarget);
            return base.BeginDraw();
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            SpriteBatch.Begin();
            SpriteBatch.Draw(BlankTexture, new Rectangle(100, 100, 100, 100), Color.White);
            SpriteBatch.End();
            base.Draw(gameTime);
        }

        protected override void EndDraw()
        {
            GraphicsDevice.SetRenderTarget(null);
            SpriteBatch.Begin();
            SpriteBatch.Draw(OffScreenRenderTarget, GraphicsDevice.Viewport.Bounds, Color.White);
            SpriteBatch.End();
            base.EndDraw();
        }
    }
}
like image 190
George Duckett Avatar answered Sep 22 '22 20:09

George Duckett