1

私は 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()1 回呼び出されDraw()、コンテンツが失われるたびにメソッドで呼び出されます。

4

2 に答える 2

4

したがって、ここでの問題はRenderTarget2D、テクスチャとして を使用しているという事実から発生します。

純粋な DirectX では、グラフィックス デバイスが失われると、テクスチャとレンダー ターゲットの両方のコンテンツが失われます。これは、テクスチャが存在するビデオ メモリ内のすべてをアンロードする必要があるためです。XNA はテクスチャに関してこれを抽象化します。テクスチャのコピーを CPU メモリに保持し、デバイスのリセット後に自動的に再作成できるようにします。

ただし、レンダー ターゲットはよりトリッキーなものです。通常、既存のイメージからレンダー ターゲットをロードすることはありません。むしろ、レンダー ターゲットのコンテンツを GPU 自体で直接生成しています。では、レンダー ターゲットのコンテンツのコピーを CPU メモリに保持できない場合、XNA はどのようにレンダー ターゲットを再作成するのでしょうか? できないというのが答えです。デバイスが失われると、レンダー ターゲットのコンテンツが失われ、XNA がそれに対してできることは何もありません。

RenderTarget2Dこれが、クラスが というプロパティを公開する理由IsContentLostです。これにより、上記のシナリオがいつ発生したかを判断し、適切に対応できます。新しいレンダー ターゲットを作成する必要はありません(オブジェクトはメモリ内にまだ存在します) が、グラフィック デバイスにその内容を再度伝える必要があります。

LoadContent()現在、一度だけ呼び出される でレンダー ターゲットを描画しています。レンダー ターゲットの描画を担当するコードの部分を別のメソッドに移動し、レンダー ターゲットが失われるたびにそのメソッドを呼び出す必要があります。

ここで、レンダー ターゲットを描画するには、 を使用してグラフィックス デバイスに設定する必要がありますSetRenderTarget(myRenderTarget)。描画が完了したら、 を使用して再度設定を解除する必要があります。SetRenderTarget(null)これにより、バックバッファがプライマリ レンダー ターゲットとして復元されます。レンダー ターゲットは同時にレンダリングのソース(テクスチャ) とレンダリングのターゲットの両方になることはできないため、これは重要です。それをしようとすると、例外が発生します。

テクスチャをTextureフィールドにロードし、それをレンダー ターゲットに描画してから、Textureフィールドをレンダー ターゲットに置き換えるという事実によって、状況は複雑に見えます。あなたが持っているもので私が今説明したことをしようとすると、レンダー ターゲットをそれ自体に描画しようとすることになります。おそらくそれが、あなたが見ている例外の原因です. だから、それをしないでください。後でターゲットを再生成するために元のテクスチャが必要になるため、元のテクスチャを別のフィールドに保存します。

于 2013-08-05T15:29:35.387 に答える