MonoGame - RenderTarget2D 在精灵下方和错误位置绘制
MonoGame - RenderTarget2D drawn below sprites and in the wrong location
这看起来很简单,但仍然行不通。因此,我尝试使用 RenderTarget2D 绘制可滚动日志 window(尚未滚动)。
有几个错误:
- 文本应该绘制在黑色背景上,现在看起来是透明的
- 文本应该绘制在游戏区域下方的黑框中,现在绘制在左上角
- 文本现在只出现在背景颜色上,它应该被绘制在其他 sprite 上
我的代码有什么问题?相关部分如下。
private GraphicsDevice graphicsDevice;
private RenderTarget2D logRenderTarget;
private bool redrawLogFlag;
public void Init(ContentManager content, GraphicsDevice graphicsDevice)
{
this.graphicsDevice = graphicsDevice;
logRenderTarget = new RenderTarget2D(
graphicsDevice,
10,
10
);
Log.LogWritten += SetRedrawLogFlag;
}
private void DrawUiComponents(SpriteBatch spriteBatch)
{
spriteBatch.Draw(Scavenger.AssetManager.TextureMap["game_area"], Vector2.Zero, Color.White);
spriteBatch.Draw(Scavenger.AssetManager.TextureMap["log_area"], new Vector2(0, Constants.GAME_AREA_HEIGHT), Color.White);
spriteBatch.Draw(Scavenger.AssetManager.TextureMap["stats_area"], new Vector2(Constants.GAME_AREA_WIDTH, 0), Color.White);
spriteBatch.Draw(Scavenger.AssetManager.TextureMap["help_info"], new Vector2(Constants.GAME_AREA_WIDTH, Constants.SCREEN_HEIGHT - 52), Color.White);
DrawStats(spriteBatch);
TryRedrawLog(spriteBatch);
WriteLog(spriteBatch);
}
private void SetRedrawLogFlag(object sender, EventArgs e)
{
redrawLogFlag = true;
}
private void TryRedrawLog(SpriteBatch spriteBatch)
{
if(redrawLogFlag)
{
redrawLogFlag = false;
logRenderTarget = new RenderTarget2D(
this.graphicsDevice,
Constants.GAME_AREA_WIDTH,
Log.Height
);
this.graphicsDevice.SetRenderTarget(logRenderTarget);
this.graphicsDevice.Clear(Color.Black);
for (int i = 0; i < Log.Count; i++)
{
spriteBatch.DrawString(Scavenger.AssetManager.Font12,
Log.Entries[i],
new Vector2(Constants.LOG_MARGIN, Constants.LOG_MARGIN + i * Scavenger.AssetManager.Font12.LineSpacing),
Color.GreenYellow
);
}
this.graphicsDevice.SetRenderTarget(null);
}
}
private void WriteLog(SpriteBatch spriteBatch)
{
spriteBatch.Draw(logRenderTarget,
new Rectangle(0, Constants.GAME_AREA_HEIGHT, Constants.GAME_AREA_WIDTH, Constants.LOG_HEIGHT),
new Rectangle(0, 0, Constants.GAME_AREA_WIDTH, Constants.LOG_HEIGHT),
Color.White
);
}
我决定改用视口。然而,似乎 MonoGame 在调用 spriteBatch.End()
之前使用了最后一个 set-up 视口。它似乎也与 ScissorRectangle 相同,所以我本可以让它也起作用。我在评论中添加了 ScissorRectangle-specific 代码。这是我的新 class:
public class LogWriter
{
private GraphicsDevice graphicsDevice;
private Viewport defaultViewport, logViewport;
//private Rectangle scissor, scissorBackup;
public void Init(GraphicsDevice graphicsDevice)
{
this.graphicsDevice = graphicsDevice;
defaultViewport = this.graphicsDevice.Viewport;
logViewport = new Viewport(0, Constants.GAME_AREA_HEIGHT, Constants.GAME_AREA_WIDTH, Constants.LOG_HEIGHT);
//scissor = new Rectangle(0, Constants.GAME_AREA_HEIGHT, Constants.GAME_AREA_WIDTH, Constants.LOG_HEIGHT);
//scissorBackup = this.graphicsDevice.ScissorRectangle;
}
public void WriteLog(SpriteBatch spriteBatch)
{
this.graphicsDevice.Viewport = logViewport;
//this.graphicsDevice.ScissorRectangle = scissor;
spriteBatch.Begin();
//spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, new RasterizerState() { ScissorTestEnable = true });
for (int i = 0; i < Log.Count; i++)
{
spriteBatch.DrawString(Scavenger.AssetManager.Font12,
Log.Entries[i],
new Vector2(
Constants.LOG_MARGIN,
Constants.LOG_MARGIN - 100 + i * Scavenger.AssetManager.Font12.LineSpacing),
Color.GreenYellow
);
}
spriteBatch.End();
this.graphicsDevice.Viewport = defaultViewport;
//this.graphicsDevice.ScissorRectangle = scissorBackup;
}
}
Init()
在LoadContent()
函数中被调用。 WriteLog()
在 Draw()
函数中被调用,在 End()
在绘制所有其他东西之后在 spriteBatch 上被调用之后。
这看起来很简单,但仍然行不通。因此,我尝试使用 RenderTarget2D 绘制可滚动日志 window(尚未滚动)。
有几个错误:
- 文本应该绘制在黑色背景上,现在看起来是透明的
- 文本应该绘制在游戏区域下方的黑框中,现在绘制在左上角
- 文本现在只出现在背景颜色上,它应该被绘制在其他 sprite 上
我的代码有什么问题?相关部分如下。
private GraphicsDevice graphicsDevice;
private RenderTarget2D logRenderTarget;
private bool redrawLogFlag;
public void Init(ContentManager content, GraphicsDevice graphicsDevice)
{
this.graphicsDevice = graphicsDevice;
logRenderTarget = new RenderTarget2D(
graphicsDevice,
10,
10
);
Log.LogWritten += SetRedrawLogFlag;
}
private void DrawUiComponents(SpriteBatch spriteBatch)
{
spriteBatch.Draw(Scavenger.AssetManager.TextureMap["game_area"], Vector2.Zero, Color.White);
spriteBatch.Draw(Scavenger.AssetManager.TextureMap["log_area"], new Vector2(0, Constants.GAME_AREA_HEIGHT), Color.White);
spriteBatch.Draw(Scavenger.AssetManager.TextureMap["stats_area"], new Vector2(Constants.GAME_AREA_WIDTH, 0), Color.White);
spriteBatch.Draw(Scavenger.AssetManager.TextureMap["help_info"], new Vector2(Constants.GAME_AREA_WIDTH, Constants.SCREEN_HEIGHT - 52), Color.White);
DrawStats(spriteBatch);
TryRedrawLog(spriteBatch);
WriteLog(spriteBatch);
}
private void SetRedrawLogFlag(object sender, EventArgs e)
{
redrawLogFlag = true;
}
private void TryRedrawLog(SpriteBatch spriteBatch)
{
if(redrawLogFlag)
{
redrawLogFlag = false;
logRenderTarget = new RenderTarget2D(
this.graphicsDevice,
Constants.GAME_AREA_WIDTH,
Log.Height
);
this.graphicsDevice.SetRenderTarget(logRenderTarget);
this.graphicsDevice.Clear(Color.Black);
for (int i = 0; i < Log.Count; i++)
{
spriteBatch.DrawString(Scavenger.AssetManager.Font12,
Log.Entries[i],
new Vector2(Constants.LOG_MARGIN, Constants.LOG_MARGIN + i * Scavenger.AssetManager.Font12.LineSpacing),
Color.GreenYellow
);
}
this.graphicsDevice.SetRenderTarget(null);
}
}
private void WriteLog(SpriteBatch spriteBatch)
{
spriteBatch.Draw(logRenderTarget,
new Rectangle(0, Constants.GAME_AREA_HEIGHT, Constants.GAME_AREA_WIDTH, Constants.LOG_HEIGHT),
new Rectangle(0, 0, Constants.GAME_AREA_WIDTH, Constants.LOG_HEIGHT),
Color.White
);
}
我决定改用视口。然而,似乎 MonoGame 在调用 spriteBatch.End()
之前使用了最后一个 set-up 视口。它似乎也与 ScissorRectangle 相同,所以我本可以让它也起作用。我在评论中添加了 ScissorRectangle-specific 代码。这是我的新 class:
public class LogWriter
{
private GraphicsDevice graphicsDevice;
private Viewport defaultViewport, logViewport;
//private Rectangle scissor, scissorBackup;
public void Init(GraphicsDevice graphicsDevice)
{
this.graphicsDevice = graphicsDevice;
defaultViewport = this.graphicsDevice.Viewport;
logViewport = new Viewport(0, Constants.GAME_AREA_HEIGHT, Constants.GAME_AREA_WIDTH, Constants.LOG_HEIGHT);
//scissor = new Rectangle(0, Constants.GAME_AREA_HEIGHT, Constants.GAME_AREA_WIDTH, Constants.LOG_HEIGHT);
//scissorBackup = this.graphicsDevice.ScissorRectangle;
}
public void WriteLog(SpriteBatch spriteBatch)
{
this.graphicsDevice.Viewport = logViewport;
//this.graphicsDevice.ScissorRectangle = scissor;
spriteBatch.Begin();
//spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, new RasterizerState() { ScissorTestEnable = true });
for (int i = 0; i < Log.Count; i++)
{
spriteBatch.DrawString(Scavenger.AssetManager.Font12,
Log.Entries[i],
new Vector2(
Constants.LOG_MARGIN,
Constants.LOG_MARGIN - 100 + i * Scavenger.AssetManager.Font12.LineSpacing),
Color.GreenYellow
);
}
spriteBatch.End();
this.graphicsDevice.Viewport = defaultViewport;
//this.graphicsDevice.ScissorRectangle = scissorBackup;
}
}
Init()
在LoadContent()
函数中被调用。 WriteLog()
在 Draw()
函数中被调用,在 End()
在绘制所有其他东西之后在 spriteBatch 上被调用之后。