我对XNA很新,我遇到了一些问题。每当我最小化游戏时,当我再次打开它时屏幕变黑。可能是什么原因以及如何解决?
这是我的Image类:
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()
方法中调用。
答案 0 :(得分:4)
因此,问题在于您使用RenderTarget2D
作为纹理。
在纯DirectX中,每当图形设备丢失时,纹理和渲染目标都会丢失其内容。这是因为必须卸载视频内存中的所有内容 - 纹理所在的位置。 XNA在纹理方面将其抽象出来:它在CPU内存中保留纹理的副本,以便在设备重置后自动重新创建纹理。
然而,渲染目标是一件比较棘手的事情。您通常不会从预先存在的图像加载渲染目标;相反,您直接在GPU本身上生成渲染目标内容。那么,如果XNA无法在CPU内存中保存其内容的副本,XNA如何为您重新创建渲染目标?答案是它无法解决。当设备丢失时,渲染目标会丢失其内容,而XNA无法做到这一点。
这就是RenderTarget2D
类公开名为IsContentLost
的属性的原因。这允许您确定上述情况何时发生并作出适当响应。您不需要创建新的渲染目标 - 该对象仍然存在于内存中 - 但您需要再次告诉图形设备包含。
现在,您正在LoadContent()
中绘制渲染目标,这只会被调用一次。您需要将负责绘制渲染目标的代码部分移动到另一个方法中,并在渲染目标丢失时调用该方法。
现在,要绘制渲染目标,您需要使用SetRenderTarget(myRenderTarget)
在图形设备上进行设置。一旦完成绘制,您需要使用SetRenderTarget(null)
再次取消设置,将后备缓冲区恢复为主渲染目标。这很重要,因为渲染目标既不是渲染的源,也是同时渲染的目标。如果您尝试这样做,您将获得例外。
您的状况似乎很复杂,因为您将纹理加载到Texture
字段,然后将其绘制到渲染目标,然后将Texture
字段替换为渲染目标。如果你尝试用你所拥有的东西做我刚刚描述过的东西,那么你最终会尝试将渲染目标绘制到自身上 - 这可能是导致异常的原因#&# 39;重看。所以不要这样做。将原始纹理存储在不同的字段中,因为您以后需要它来重新生成目标。
答案 1 :(得分: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);
}
我意识到它有点晚了,但希望它会帮助那些来的人......