【问题标题】:XNA resize window without increasing resolutionXNA 在不增加分辨率的情况下调整窗口大小
【发布时间】:2011-09-29 01:27:35
【问题描述】:

我想在较大的窗口上创建低分辨率游戏。 (例如 960x540 尺寸窗口上的 96x54 分辨率)。

我该怎么做呢?有没有办法独立于首选的后台缓冲区宽度和高度来调整窗口大小?或者我应该只保留我绘制的低分辨率渲染目标,并在我完成最近纹理采样的调整后将其绘制为窗口上的全屏四边形?

提前致谢,

xoorath

【问题讨论】:

    标签: c# windows xna


    【解决方案1】:

    我倾向于选择“渲染到纹理”的解决方案,这样我就可以实现全屏而不失真。

    我用来实现这一点的类通常看起来像:

    class VirtualScreen
    {
        public readonly int VirtualWidth;
        public readonly int VirtualHeight;
        public readonly float VirtualAspectRatio;
    
        private GraphicsDevice graphicsDevice;
        private RenderTarget2D screen;
    
        public VirtualScreen(int virtualWidth, int virtualHeight, GraphicsDevice graphicsDevice)
        {
            VirtualWidth = virtualWidth;
            VirtualHeight = virtualHeight;
            VirtualAspectRatio = (float)(virtualWidth) / (float)(virtualHeight);
    
            this.graphicsDevice = graphicsDevice;
            screen = new RenderTarget2D(graphicsDevice, virtualWidth, virtualHeight, false, graphicsDevice.PresentationParameters.BackBufferFormat, graphicsDevice.PresentationParameters.DepthStencilFormat, graphicsDevice.PresentationParameters.MultiSampleCount, RenderTargetUsage.DiscardContents);
        }
    
        private bool areaIsDirty = true;
    
        public void PhysicalResolutionChanged()
        {
            areaIsDirty = true;
        }
    
        private Rectangle area;
    
        public void Update()
        {
            if (!areaIsDirty)
            {
                return;
            }
    
            areaIsDirty = false;
            var physicalWidth = graphicsDevice.Viewport.Width;
            var physicalHeight = graphicsDevice.Viewport.Height;
            var physicalAspectRatio = graphicsDevice.Viewport.AspectRatio;
    
            if ((int)(physicalAspectRatio * 10) == (int)(VirtualAspectRatio * 10))
            {
                area = new Rectangle(0, 0, physicalWidth, physicalHeight);
                return;
            }
    
    
            if (VirtualAspectRatio > physicalAspectRatio)
            {
                var scaling = (float)physicalWidth / (float)VirtualWidth;
                var width = (float)(VirtualWidth) * scaling;
                var height = (float)(VirtualHeight) * scaling;
                var borderSize = (int)((physicalHeight - height) / 2);
                area = new Rectangle(0, borderSize, (int)width, (int)height);
            }
            else
            {
                var scaling = (float)physicalHeight / (float)VirtualHeight;
                var width = (float)(VirtualWidth) * scaling;
                var height = (float)(VirtualHeight) * scaling;
                var borderSize = (int)((physicalWidth - width) / 2);
                area = new Rectangle(borderSize, 0, (int)width, (int)height);
            }
        }
    
        public void BeginCapture()
        {
            graphicsDevice.SetRenderTarget(screen);
        }
    
        public void EndCapture()
        {
            graphicsDevice.SetRenderTarget(null);
        }
    
        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(screen, area, Color.White);
        }
    
    
    }
    

    然后在我的游戏中,初始化看起来像这样:

      VirtualScreen virtualScreen;
    
        protected override void Initialize()
        {
            virtualScreen = new VirtualScreen(96, 54, GraphicsDevice);
            Window.ClientSizeChanged += new EventHandler<EventArgs>(Window_ClientSizeChanged);
            Window.AllowUserResizing = true;
            base.Initialize();
        }
    
        void Window_ClientSizeChanged(object sender, EventArgs e)
        {
            virtualScreen.PhysicalResolutionChanged();
        }
    

    所有重要的更新调用:

    protected override void Update(GameTime gameTime)
        {
            virtualScreen.Update();
    
            base.Update(gameTime);
        }
    

    然后是绘画本身的行为:

     protected override void Draw(GameTime gameTime)
        {
            virtualScreen.BeginCapture();
    
    
            GraphicsDevice.Clear(Color.CornflowerBlue);
            // game rendering happens here...
    
    
            virtualScreen.EndCapture();
    
            GraphicsDevice.Clear(Color.Black);
            spriteBatch.Begin();
            virtualScreen.Draw(spriteBatch);
            spriteBatch.End();
    
            base.Draw(gameTime);
        }
    

    有了这个,我基本上可以不再关心分辨率,只专注于游戏。

    【讨论】:

    • 非常感谢lzcd。这是一个非常好的参考,现在希望这两种解决方案都能帮助其他一些偶然发现它的人。感谢您为此花费的时间。
    【解决方案2】:

    使用您正在谈论的 RenderToTexture 方法可能是一个好主意(另外,如果您想做后期处理着色器,这对您来说会更容易)。 或者,您可以设置窗口的大小,但您的代码只能在桌面上运行。

    您必须在项目中添加这 2 个引用:

    using System.Drawing;
    using System.Windows.Forms;
    

    然后在您的 Game 类中(即在 Initialize 方法中)

    GraphicsDeviceManager.PreferredBackBufferWidth = 96;
    GraphicsDeviceManager.PreferredBackBufferHeight = 54;
    IntPtr ptr = this.Window.Handle;
    Form form = (Form) Control.FromHandle(ptr);
    form.Size = new Size(960, 540);
    

    【讨论】:

    • 谢谢老兄,这就是我要找的。我不确定我是否可以修复它,以便采样最接近且清晰(对于我的游戏来说是理想的)。但如果不是,那么我将使用渲染目标方法。
    猜你喜欢
    • 2020-10-14
    • 1970-01-01
    • 1970-01-01
    • 2018-05-11
    • 1970-01-01
    • 2022-11-13
    • 2014-12-30
    • 1970-01-01
    • 2014-04-24
    相关资源
    最近更新 更多