【问题标题】:C# XNA 4.0 textures disappearing when minimizedC# XNA 4.0 纹理在最小化时消失
【发布时间】:2013-08-06 04:39:52
【问题描述】:

我是 XNA 的新手,我遇到了一些问题。每当我最小化游戏时,当我再次打开它时屏幕会变黑。可能是什么原因造成的,如何解决?

这是我的图像类:

 public class Image
 {
    public float Alpha;
    public string Text, FontName, Path;
    public Vector2 Position, Scale;
    public Rectangle SourceRect;
    public bool IsActive;
    public bool Logo;
    public Texture2D Texture;
    Vector2 origin;
    ContentManager content;
    RenderTarget2D renderTarget;
    SpriteFont font;
    Dictionary<string, ImageEffect> effectList;
    public string Effects;

    public FadeEffect FadeEffect;

    void SetEffect<T>(ref T effect)
    {
        if (effect == null)
            effect = (T)Activator.CreateInstance(typeof(T));
        else
        {
            (effect as ImageEffect).IsActive = true;
            var obj = this;
            (effect as ImageEffect).LoadContent(ref obj);
        }

        effectList.Add(effect.GetType().ToString().Replace("RPG.", ""), (effect as ImageEffect));
    }

    public void ActivateEffect(string effect)
    {
        if (effectList.ContainsKey(effect))
        {
            effectList[effect].IsActive = true;
            var obj = this;
            effectList[effect].LoadContent(ref obj);
        }
    }

    public void DeactivateEffect(string effect)
    {
        if (effectList.ContainsKey(effect))
        {
            effectList[effect].IsActive = false;
            effectList[effect].UnloadContent();
        }
    }

    public void StoreEffects()
    {
        Effects = String.Empty;
        foreach (var effect in effectList)
        {
            if (effect.Value.IsActive)
                Effects += effect.Key + ":";
        }

        if(Effects != String.Empty)
            Effects.Remove(Effects.Length - 1);
    }

    public void RestoreEffects()
    {
        foreach (var effect in effectList)
            DeactivateEffect(effect.Key);
        string[] split = Effects.Split(':');
        foreach (string s in split)
            ActivateEffect(s);
    }

    public Image()
    {
        Path = Text = Effects = String.Empty;
        FontName = "Fonts/FixedSys Ex";
        Position = Vector2.Zero;
        Scale = Vector2.One;
        Alpha = 1.0f;
        SourceRect = Rectangle.Empty;
        effectList = new Dictionary<string, ImageEffect>();
    }

    public void LoadContent()
    {
        content = new ContentManager(ScreenManager.Instance.Content.ServiceProvider, "Content");


        if (Path != String.Empty)
            Texture = content.Load<Texture2D>(Path);

        font = content.Load<SpriteFont>(FontName);

        Vector2 dimensions = Vector2.Zero;

        if (Texture != null)
            dimensions.X += Texture.Width;
        dimensions.X += font.MeasureString(Text).X;

        if (Texture != null)
            dimensions.Y = Math.Max(Texture.Height, font.MeasureString(Text).Y);
        else
            dimensions.Y = font.MeasureString(Text).Y;

        if (SourceRect == Rectangle.Empty)
            SourceRect = new Rectangle(0, 0, (int)dimensions.X, (int)dimensions.Y);

        renderTarget = new RenderTarget2D(ScreenManager.Instance.GraphicsDevice, (int)dimensions.X, (int)dimensions.Y);
        ScreenManager.Instance.GraphicsDevice.SetRenderTarget(renderTarget);
        ScreenManager.Instance.GraphicsDevice.Clear(Color.Transparent);
        ScreenManager.Instance.SpriteBatch.Begin();
        if (Texture != null)
            ScreenManager.Instance.SpriteBatch.Draw(Texture, Vector2.Zero, Color.White);
        ScreenManager.Instance.SpriteBatch.DrawString(font, Text, Vector2.Zero, Color.White);
        ScreenManager.Instance.SpriteBatch.End();

        Texture = renderTarget;

        ScreenManager.Instance.GraphicsDevice.SetRenderTarget(null);

        SetEffect<FadeEffect>(ref FadeEffect);

        if (Effects != string.Empty)
        {
            string[] split = Effects.Split(':');
            foreach (string item in split)
                ActivateEffect(item);
        }


    }

    public void UnloadContent()
    {
        content.Unload();
        foreach (var effect in effectList)
        {
            DeactivateEffect(effect.Key);
        }
    }

    public void Update(GameTime gameTime)
    {
        foreach (var effect in effectList)
        {
            if(effect.Value.IsActive)
                effect.Value.Update(gameTime);
        }
    }

    public void Draw(SpriteBatch spriteBatch)
    {
        origin = new Vector2(SourceRect.Width / 2, SourceRect.Height / 2);
        spriteBatch.Draw(Texture, Position + origin, SourceRect, Color.White * Alpha, 0.0f, origin, Scale, SpriteEffects.None, 0.0f);
    }
}

编辑:

我终于设法让它正常工作了!

固定代码:

public class Image
{
    public float Alpha;
    public string Text, FontName, Path;
    public Vector2 Position, Scale;
    public Rectangle SourceRect;
    public bool IsActive;
    public bool Logo;
    public Texture2D Texture;
    Vector2 origin;
    Vector2 dimensions;
    ContentManager content;
    RenderTarget2D renderTarget;
    SpriteFont font;
    Dictionary<string, ImageEffect> effectList;
    public string Effects;

    public FadeEffect FadeEffect;

    void SetEffect<T>(ref T effect)
    {
        if (effect == null)
            effect = (T)Activator.CreateInstance(typeof(T));
        else
        {
            (effect as ImageEffect).IsActive = true;
            var obj = this;
            (effect as ImageEffect).LoadContent(ref obj);
        }

        effectList.Add(effect.GetType().ToString().Replace("RPG.", ""), (effect as ImageEffect));
    }

    public void ActivateEffect(string effect)
    {
        if (effectList.ContainsKey(effect))
        {
            effectList[effect].IsActive = true;
            var obj = this;
            effectList[effect].LoadContent(ref obj);
        }
    }

    public void DeactivateEffect(string effect)
    {
        if (effectList.ContainsKey(effect))
        {
            effectList[effect].IsActive = false;
            effectList[effect].UnloadContent();
        }
    }

    public void StoreEffects()
    {
        Effects = String.Empty;
        foreach (var effect in effectList)
        {
            if (effect.Value.IsActive)
                Effects += effect.Key + ":";
        }

        if(Effects != String.Empty)
            Effects.Remove(Effects.Length - 1);
    }

    public void RestoreEffects()
    {
        foreach (var effect in effectList)
            DeactivateEffect(effect.Key);
        string[] split = Effects.Split(':');
        foreach (string s in split)
            ActivateEffect(s);
    }

    public Image()
    {
        Path = Text = Effects = String.Empty;
        FontName = "Fonts/FixedSys Ex";
        Position = Vector2.Zero;
        Scale = Vector2.One;
        Alpha = 1.0f;
        SourceRect = Rectangle.Empty;
        effectList = new Dictionary<string, ImageEffect>();
    }

    public void LoadContent()
    {
        content = new ContentManager(ScreenManager.Instance.Content.ServiceProvider, "Content");


        if (Path != String.Empty)
            Texture = content.Load<Texture2D>(Path);

        font = content.Load<SpriteFont>(FontName);

        dimensions = Vector2.Zero;

        if (Texture != null)
            dimensions.X += Texture.Width;
        dimensions.X += font.MeasureString(Text).X;

        if (Texture != null)
            dimensions.Y = Math.Max(Texture.Height, font.MeasureString(Text).Y);
        else
            dimensions.Y = font.MeasureString(Text).Y;

        if (SourceRect == Rectangle.Empty)
            SourceRect = new Rectangle(0, 0, (int)dimensions.X, (int)dimensions.Y);

        SetEffect<FadeEffect>(ref FadeEffect);

        LoadDevice();

        if (Effects != string.Empty)
        {
            string[] split = Effects.Split(':');
            foreach (string item in split)
                ActivateEffect(item);
        }

    }

    public void LoadDevice()
    {
        if (Path != String.Empty)
            Texture = content.Load<Texture2D>(Path);

        font = content.Load<SpriteFont>(FontName);

        renderTarget = new RenderTarget2D(ScreenManager.Instance.GraphicsDevice, (int)dimensions.X, (int)dimensions.Y);
        ScreenManager.Instance.GraphicsDevice.SetRenderTarget(renderTarget);
        ScreenManager.Instance.GraphicsDevice.Clear(Color.Transparent);
        ScreenManager.Instance.SpriteBatch.Begin();
        if (Texture != null)
            ScreenManager.Instance.SpriteBatch.Draw(Texture, Vector2.Zero, Color.White);
        ScreenManager.Instance.SpriteBatch.DrawString(font, Text, Vector2.Zero, Color.White);
        ScreenManager.Instance.SpriteBatch.End();

        Texture = renderTarget;

        ScreenManager.Instance.GraphicsDevice.SetRenderTarget(null);
    }

    public void UnloadContent()
    {
        content.Unload();
        foreach (var effect in effectList)
        {
            DeactivateEffect(effect.Key);
        }
    }

    public void Update(GameTime gameTime)
    {
        foreach (var effect in effectList)
        {
            if(effect.Value.IsActive)
                effect.Value.Update(gameTime);
        }
    }

    public void Draw(SpriteBatch spriteBatch)
    {
        origin = new Vector2(SourceRect.Width / 2, SourceRect.Height / 2);
        spriteBatch.Draw(Texture, Position + origin, SourceRect, Color.White * Alpha, 0.0f, origin, Scale, SpriteEffects.None, 0.0f);

        if (renderTarget.IsContentLost)
        {
            ScreenManager.Instance.SpriteBatch.End();
            LoadDevice();
            ScreenManager.Instance.SpriteBatch.Begin();
        }
    }
}

renderTarget 的内容现在在单独的方法中绘制,并在LoadContent() 中调用一次,并且在内容丢失时在Draw() 方法中调用。

【问题讨论】:

  • 图像类中的 Draw() 是什么?屏幕管理员呢?这个图像类是唯一不绘制的,还是在最小化游戏后什么都不绘制?
  • @davidsbro 在 ScreenManager 内: public void Draw(SpriteBatch spriteBatch) { currentScreen.Draw(spriteBatch); if (IsTransitioning) Image.Draw(SpriteBatch);它还加载和卸载图像内容。在 Game1 内部:受保护的覆盖 void Draw(GameTime gameTime) { spriteBatch.Begin(); ScreenManager.Instance.Draw(spriteBatch); spriteBatch.End(); base.Draw(游戏时间); } 当我最小化它并再次打开它时,无论游戏在做什么,我看到的都是黑屏。

标签: c# xna textures xna-4.0 rendertarget


【解决方案1】:

所以这里的问题源于您使用RenderTarget2D 作为纹理。

在纯 DirectX 中,只要图形设备丢失,纹理和渲染目标都会丢失其内容。这是因为视频内存中的所有内容——你的纹理所在的地方——都必须被卸载。 XNA 将纹理从您那里抽象出来:它在 CPU 内存中保留纹理的副本,以便在设备重置后可以自动重新创建它。

但是,渲染目标是一件比较棘手的事情。您通常不会从预先存在的图像加载渲染目标;相反,您直接在 GPU 本身上生成渲染目标内容。那么,如果 XNA 不能在 CPU 内存中保存其内容的副本,它如何为您重新创建渲染目标呢?答案是不能。当设备丢失时,您的渲染目标会丢失其内容,XNA 对此无能为力。

这就是RenderTarget2D 类公开一个名为IsContentLost 的属性的原因。这使您可以确定上述情况何时发生并做出适当的响应。您不需要创建一个新的渲染目标——该对象仍然存在于内存中——但你需要再次告诉图形设备它包含什么。 p>

现在,您正在LoadContent() 中绘制渲染目标,它只被调用一次。您需要将该代码中负责绘制渲染目标的部分移动到另一个方法中,并在渲染目标丢失时调用该方法。

现在,要绘制渲染目标,您需要使用SetRenderTarget(myRenderTarget) 在图形设备上设置它。完成绘制后,您需要使用 SetRenderTarget(null) 再次取消设置,这会将后缓冲区恢复为主要渲染目标。这一点很重要,因为渲染目标不能同时是渲染的源(即纹理)和渲染的目标。如果你尝试这样做,你会得到一个例外。

您的情况似乎很复杂,因为您将纹理加载到 Texture 字段中,然后将其绘制到渲染目标,然后用渲染目标替换 Texture 字段。如果你试图用你所拥有的东西来做我刚才描述的事情,你最终会试图将渲染目标绘制到自身上——这可能是导致你看到的异常的原因。所以不要那样做。将原始纹理存储在不同的字段中,因为稍后您将需要它来重新生成目标。

【讨论】:

  • 更新中: if (renderTarget.IsContentLost) { // "renderTarget = new RenderTarget2D(ScreenManager.Instance.GraphicsDevice, (int)dimensions.X, (int)dimensions.Y);"到“ScreenManager.Instance.SpriteBatch.End();”来自原始代码} 这给了我错误:“渲染目标在用作纹理时不能在设备上设置。”在“ScreenManager.Instance.SpriteBatch.End();”上行。
  • 你不需要创建一个新的渲染目标,你只需要重新绘制它的内容。在尝试使用SpriteBatch 绘制它之前,您需要调用SetRenderTarget(null)。
  • 你能给我举个例子来说明你的意思吗?我尝试按照您所说的几种方式对其进行更改,但都没有奏效。要么我遇到同样的问题,要么同样的错误。
  • 那太好了。提前致谢。我真的坚持这一点。
  • 我已经扩展了我的答案。我很抱歉昨天没有按照我的承诺这样做;我当时感觉不太好。
【解决方案2】:

我遇到了同样的问题,并找到了一种(更优雅的?)方法来解决这个问题。这不涉及重绘初始纹理(因为切换渲染目标的成本很高)。

public void Initialize(GraphicsDevice graphics)
{
    Color[] colors = new Color[Width * Height];
    RenderTarget2D target = new RenderTarget2D(graphics, Width, Height);
    gridTexture = new Texture2D(graphics, Width, Height);

    graphics.SetRenderTarget(target);
    graphics.Clear(Color.Black);

    SpriteBatch.Begin();
    // drawing code...
    SpriteBatch.End();

    graphics.SetRenderTarget(null);

    target.GetData<Color>(colors);
    gridTexture.SetData<Color>(colors);
}

我意识到这有点晚了,但希望它会帮助那些过来的人......

【讨论】:

    猜你喜欢
    • 2018-10-09
    • 1970-01-01
    • 1970-01-01
    • 2012-01-24
    • 1970-01-01
    • 2013-05-18
    • 1970-01-01
    • 1970-01-01
    • 2014-08-31
    相关资源
    最近更新 更多