XNA 调整窗口大小而不增加分辨率

发布于 2024-12-07 12:35:26 字数 181 浏览 1 评论 0原文

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

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

预先感谢,

xoorath

I want to create a low resolution game on a larger window. (96x54 res on 960x540 size window for example).

How would I go about this? Is there a way to resize a window independently of the preferred back buffer width and height? Or should I just keep a low resolution render target I draw on, and just draw it as a full screen quad on my window when I'm done adjusting for nearest texture sampling?

Thanks in advance,

xoorath

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦断已成空 2024-12-14 12:35:26

我倾向于选择“渲染到纹理”解决方案,这样我就可以允许全屏显示而不会失真。

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

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);
    }

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

I tend to opt for the "render to texture" solution so that I can allow for things like full screen without distortions.

The class I use to achieve this usually looks something like:

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);
    }


}

And then in my game, the initialisation tends look something like:

  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();
    }

With the all important call to Update:

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

        base.Update(gameTime);
    }

And then the act of drawing itself:

 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);
    }

With this in place, I can basically stop caring about resolution at all and just focus on the game.

踏雪无痕 2024-12-14 12:35:26

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

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

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);

Using the RenderToTexture method you're talking about might be a good idea (plus it will be easier for you if you want to do post-process shaders).
Alternatively, you can set the Window's size, but your code will only work on a desktop.

You must add those 2 references in your project:

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

And then in your Game class (i.e. in the Initialize method)

GraphicsDeviceManager.PreferredBackBufferWidth = 96;
GraphicsDeviceManager.PreferredBackBufferHeight = 54;
IntPtr ptr = this.Window.Handle;
Form form = (Form) Control.FromHandle(ptr);
form.Size = new Size(960, 540);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文