XNA 3.1到4.0需要不断重绘或显示紫色屏幕

时间:2010-11-20 22:54:23

标签: xna xna-4.0

对于我游戏中的菜单,我将它们绘制到屏幕一次,然后只有在被认为是脏的时才重绘。每当用户执行应该导致重绘的操作时,都会通过布尔值设置为true来处理,然后绘制循环将在绘制菜单之前检查该值。这个逻辑在3.1中完美运行,但在4.0中,菜单会闪烁(绘制1帧),然后显示紫色屏幕,直到再次绘制。

我在4.0中创建了一个非常简单的测试游戏来演示如下所示的问题。您会注意到屏幕看起来只是紫色。如果将行设置_isDirty删除为false,您将看到矢车菊蓝色背景。

public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    bool _isDirty = true;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
    }
    protected override void Draw(GameTime gameTime)
    {
        if (_isDirty)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            _isDirty = false;
        }
        base.Draw(gameTime);
    }
}

我如何从XNA 3.1获取行为?我见过几个人提到PreserveContents,但这似乎没有任何影响,除非我错误地应用它。

3 个答案:

答案 0 :(得分:13)

以下是对XNA游戏中调用内容的概述:

Update
BeginDraw
Draw
EndDraw

EndDraw的默认实施最终会调用GraphicsDevice.Present。打开双缓冲后,可以交换前后缓冲区。

所以发生的事情是:

  • 第一次:您将场景绘制到后台缓冲区,然后让XNA将其交换到前面。

  • 第二次:你没有画任何东西,让表面充满了DirectX初始化这些表面的紫色,并将那个交换到前面!

    < / LI>
  • 后续时间:你什么都没画,所以你会看到这两个表面之间的显示闪烁。

有几种方法可以抑制XNA中的绘图。我在this answer to a similar question中查看了它们。在答案中,我建议你覆盖BeginDraw,如下所示:

protected override bool BeginDraw()
{
    if(_isDirty)
        return base.BeginDraw();
    else
        return false;
}

BeginDraw返回false时,DrawEndDraw(以及Present)将不会被调用该帧。什么都不会画,前/后缓冲区不会交换。

答案 1 :(得分:2)

我最近也偶然发现了这一点;我认为翻转缓冲区不是问题。在3.1和4.0中应该是相同的。我用ILSpy查看了GraphicsDevice,发现了这个:

更改的是,在4.0中,如果设置了私有标志,则首先在GraphicsDevice.Present()中清除当前渲染目标。默认情况下,此标志最初将设置(渲染目标是干净的)。绘制到渲染目标会清除此标志(渲染目标现在变脏)。在执行它的任务后,GraphicsDevice.Present()再次设置标志(渲染目标被“刷出”到你的窗口,现在再次被认为是干净的。)

要从GraphicsDevice.Present()获取结果,您需要严格按顺序调用Draw()和EndDraw()。

如果在没有事先调用Draw()的情况下调用EndDraw(),则不会获得渲染目标(被清除)的内容,而只会获取紫色屏幕。

不幸的是,旗帜是私人的,并没有干净的方式来获取它。您可以使用反射来清除这样的标志,强制渲染目标变脏而不向其中绘制任何内容:

graphicsDevice.GetType()。GetField(“lazyClearFlags”,BindingFlags.NonPublic | BindingFlags.Instance)。SetValue(graphicsDevice,0);

(graphicsDevice是您当前的GraphicsDevice实例)

在调用EndDraw()之前放置上面的行,行为将恢复为3.1中的行为

答案 2 :(得分:0)

在我的特定情况下,我有一个状态机,可以在负责绘图的状态之间切换。因此,当我在两个游戏状态之间转换时,没有任何东西可以绘制,并且屏幕闪烁紫色直到下一个游戏状态处于活动状态。

我要解决的问题很简单,在Update中,如果我没有状态,请在游戏对象中调用 SuppressDraw()方法。这可以防止在下一次更新发生之前进行绘制。

我想除了你设置一个isDirty标志外,没有什么可以阻止你总是在Update中调用它。但是你必须准备好处理屏幕可能被破坏的其他事件/案例。