Uniformly Resizing a Window in XNA

前端 未结 2 1067
夕颜
夕颜 2021-01-06 09:05

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?

相关标签:
2条回答
  • 2021-01-06 09:28

    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();
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-06 09:45

    My guess is that this code won't work because it will keep calling itself, because the ClientSizeChanged event will fire the ClientSizeChanged event.

    Maybe you need to check and see if the window is already in the correct aspect ratio, and not change it further.

    0 讨论(0)
提交回复
热议问题