2013-08-05 4 views
1

저는 XNA를 처음 접했고 몇 가지 문제가있었습니다. 게임을 최소화 할 때마다 다시 열면 화면이 검게 변합니다. 이 문제의 원인은 무엇이며 어떻게 해결 될 수 있습니까?C# XNA 4.0 텍스처가 최소화 될 때 사라짐

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

내용은 이제 별도의 방법으로 그려, 한 번 LoadContent()에 호출되고, 그리고 Draw() 방법에 내용이 손실 될 때마다.

+0

? 스크린 관리자가 있습니까? 그리고이 이미지 클래스가 그림을 그리지 않는 유일한 것입니까, 아니면 게임을 최소화 한 후에도 그릴 수 없습니다. – davidsbro

+0

@davidsbro 내부에 ScreenManager : 공공 무효 그리기 (의 SpriteBatch의 SpriteBatch) { currentScreen.Draw (의 SpriteBatch); if (IsTransitioning) Image.Draw (SpriteBatch); } 또한 이미지 콘텐츠를로드하고 언로드합니다. 인사이드 게임 1 : 무효 보호 무효 Draw (GameTime gameTime) { spriteBatch.Begin(); ScreenManager.Instance.Draw (spriteBatch); spriteBatch.End(); base.Draw (gameTime); } 내가 최소화하고 다시 열면 게임이 무슨 일을 하든지 검은 화면이됩니다. – Doomer9lives

답변

4

그래서 여기서 문제는 텍스처로 RenderTarget2D을 사용하고 있다는 사실에서 발생합니다.

순수 DirectX에서 그래픽 장치가 손실 될 때마다 텍스처와 렌더링 대상이 내용을 잃습니다. 이것은 비디오 메모리의 모든 부분 (텍스처가있는 곳)을 언로드해야하기 때문입니다. XNA는 텍스처와 관련하여 이것을 추상화합니다. 텍스처가 CPU 메모리에 유지되므로 장치가 재설정 된 후에도 자동으로 다시 생성 할 수 있습니다.

그러나 렌더링 타겟은 더 까다로운 문제입니다. 기존 이미지에서 렌더 타겟을로드하는 것이 아닙니다. 오히려 GPU 자체에서 렌더링 대상 내용을 직접 생성하고 있습니다. 그렇다면 XNA는 CPU 메모리에 내용물의 복사본을 저장할 수 없다면 렌더 타겟을 어떻게 다시 생성합니까? 대답은 할 수 없다는 것입니다. 장치가 손실되면 렌더 타겟이 내용을 잃어 버리고 XNA가 할 수있는 일이 없습니다.

이렇게하면 RenderTarget2D 클래스가 IsContentLost이라는 속성을 노출합니다. 이렇게하면 위 시나리오가 언제 발생했는지 판단하고 적절하게 대응할 수 있습니다. 렌더링 대상을 만들 필요가 없습니다. 개체가 여전히 메모리에 있지만 그래픽 장치에 이 포함되어 있는지 다시 알려야합니다.

바로 지금 렌더 타겟을 LoadContent()에 그리는 것입니다. 렌더링 대상은 한 번만 호출됩니다. 렌더 타겟 그리기를 담당하는 코드 부분을 다른 메소드로 옮기고 렌더 타겟을 잃을 때마다이 메소드를 호출해야합니다.

이제 렌더 대상을 그리려면 SetRenderTarget(myRenderTarget)을 사용하여 그래픽 장치에 설정해야합니다. 일단 그리기를 마쳤 으면 SetRenderTarget(null)을 사용하여 다시 설정을 해제해야합니다. 그러면 기본 버퍼 대상으로 백 버퍼가 복원됩니다. 렌더링 타겟이 소스 렌더링 (즉, 텍스처)과 타겟 (동시에 렌더링 타겟) 일 수 없기 때문에 이것은 중요합니다. 그렇게하려고하면 예외가 발생합니다.

Texture 필드에 텍스처를로드 한 다음 렌더링 대상으로 그려서 Texture 필드를 렌더링 대상으로 바꾸면 상황이 복잡해 보입니다. 방금 설명한 내용을 방금 여러분이 해보려고한다면, 렌더링 타겟을 그 자체에 그려 내려고 할 것입니다. 아마도 여러분이 보는 예외를 일으키는 것일 것입니다.그러지 마라. 나중에 대상을 재생성해야하기 때문에 원본 텍스쳐를 다른 필드에 저장하십시오.

+0

업데이트 : if (renderTarget.IsContentLost) { // "renderTarget = new RenderTarget2D (ScreenManager.Instance.GraphicsDevice, (int) dimensions.X, (int) dimensions.Y);" "ScreenManager.Instance.SpriteBatch.End();"로 변경하십시오. from original code } 이렇게하면 "텍스처로 사용할 때 렌더링 대상을 장치에 설정해서는 안됩니다."라는 오류 메시지가 나타납니다. "ScreenManager.Instance.SpriteBatch.End();" 선. – Doomer9lives

+0

새로운 렌더 타겟을 만들 필요가 없습니다. 단지 내용을 다시 그려야합니다. 그리고'SpriteBatch'를 사용하여 그것을 그리기 전에'SetRenderTarget (null)'을 호출해야합니다. –

+0

당신이 의미하는 것을 보여 줄 수 있습니까? 나는 당신이 몇 가지 방법으로 말한 것에 따라 그것을 바꾸려고했지만, 그들 중 누구도 일하지 않았습니다. 동일한 문제 또는 동일한 오류가 발생합니다. – Doomer9lives

1

동일한 문제가 발생하여이를 해결하는 (더 우아한?) 방법을 발견했습니다. 초기 텍스처를 다시 그리는 것을 포함하지 않습니다 (렌더링 타겟을 전환하는 것이 값 비싸기 때문에).

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

나는 그것을 조금 늦게 실현 그러나 희망이 도움이됩니다 나타나서 사람 ...

이미지 클래스에서 그리기()를 호출 무엇