C# XNA 4.0 纹理在最小化时消失
本文关键字:最小化 消失 纹理 XNA | 更新日期: 2023-09-27 18:26:25
我对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()
方法中调用。
所以这里的问题源于你使用RenderTarget2D
作为纹理的事实。
在纯 DirectX 中,每当图形设备丢失时,纹理和呈现目标都会丢失其内容。 这是因为视频内存中的所有内容(纹理所在的位置(都必须卸载。 XNA 在纹理方面将其抽象出来:它会在 CPU 内存中保留纹理的副本,以便在重置设备后自动重新创建它。
但是,渲染目标是一件比较棘手的事情。 您通常不会从预先存在的图像加载呈现器目标;相反,您直接在 GPU 本身上生成呈现目标内容。 那么,如果 XNA 无法在 CPU 内存中保存其内容的副本,它将如何为您重新创建渲染目标呢? 答案是不能。 当设备丢失时,您的渲染目标将丢失其内容,XNA 对此无能为力。
这就是 RenderTarget2D
类公开名为 IsContentLost
的属性的原因。 这使您可以确定上述情况何时发生并做出适当的响应。 您不需要创建新的呈现目标(对象仍存在于内存中(,但您需要再次告诉图形设备它包含的内容。
现在,您正在绘制渲染目标 LoadContent()
,这只被调用一次。 您需要将负责绘制呈现目标的代码部分移动到另一个方法中,并在呈现器目标丢失时调用该方法。
现在,要绘制呈现器目标,您需要使用 SetRenderTarget(myRenderTarget)
在图形设备上设置它。 绘制完后,需要使用 SetRenderTarget(null)
再次取消设置它,这会将后台缓冲区恢复为主渲染目标。 这一点很重要,因为呈现器目标不能同时是呈现源(即纹理(和呈现目标。 如果您尝试这样做,则会得到一个例外。
由于您将纹理加载到Texture
字段中,然后将其绘制到呈现器目标,然后将Texture
字段替换为呈现器目标,因此您的情况似乎很复杂。 如果你尝试用你所拥有的东西做我刚才描述的事情,你最终会试图将渲染目标绘制到自身上 - 这可能是导致你看到的异常的原因。 所以不要那样做。 将原始纹理存储在其他字段中,因为稍后需要它来重新生成目标。
我遇到了同样的问题,并找到了一种(更优雅?(方法来解决这个问题。这不涉及重绘初始纹理(因为切换渲染目标的成本很高(。
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);
}
我意识到有点晚了,但希望它能帮助那些出现的人......