我一直在使用 MonoGame 将我在 XNA 中制作的滚动射击游戏移植到 Linux 上。几乎一切都进行得很顺利,但我在一个特定的地方遇到了一个问题,调用 SpriteBatch.Draw() 会削弱帧速率。大多数游戏运行良好,没有任何打嗝。它一次吸引大量敌人和大量子弹而没有任何减速。然而,导致丢帧的部分是分层滚动背景。代码的相关部分在这里。
级别.cs:
public void Draw(SpriteBatch spriteBatch)
{
foreach (ScrollingBackgroundLayer sbl in scrollingBackground)
{
sbl.Draw(spriteBatch);
}
}
上面的“scrollingBackground”是一个ScrollingBackgroundLayers的列表,其相关部分是:
ScrollingBackgroundLayers.cs:
Vector2[] scrollingBackgroundImages;
public float DrawLayer;
public ScrollingBackgroundLayer(GameScene newScene, Texture2D texture, float scrollSpeed, Color color)
{
layerColor = color;
layerSpeed = scrollSpeed;
layerTexture = texture;
thisScene = newScene;
Initialize();
}
public void Initialize()
{
scrollingBackgroundImages = new Vector2[2];
for (int i = 0; i < 2; i++)
{
scrollingBackgroundImages[i] = new Vector2(0, thisScene.ScreenArea.Height - (layerTexture.Height * i));
}
}
public void Update(GameTime gameTime)
{
for (int i = 0; i < scrollingBackgroundImages.Length; i++)
{
scrollingBackgroundImages[i].Y += (float)gameTime.ElapsedGameTime.TotalSeconds * layerSpeed;
if (layerSpeed > 0 && scrollingBackgroundImages[i].Y >= thisScene.ScreenArea.Height)
{
scrollingBackgroundImages[i] = new Vector2(scrollingBackgroundImages[i].X, (scrollingBackgroundImages[i].Y - layerTexture.Height * 2));
}
else if (layerSpeed < 0 && scrollingBackgroundImages[i].Y + layerTexture.Height <= 0)
{
scrollingBackgroundImages[i] = new Vector2(scrollingBackgroundImages[i].X, (scrollingBackgroundImages[i].Y + layerTexture.Height * 2));
}
}
}
public void Draw(SpriteBatch spriteBatch)
{
foreach (Vector2 sb in scrollingBackgroundImages)
{
spriteBatch.Draw(layerTexture, sb, null, layerColor, 0f, Vector2.Zero, 1f, SpriteEffects.None, DrawLayer);
}
}
一旦我注释掉对 ScrollingBackgroundLayer.Draw() 的调用,所有帧速率问题都会消失,因此这似乎是一个很大的暗示,即问题来自 SpriteBatch 尝试绘制滚动层。显然,我想弄清楚为什么会这样。我研究了 SpriteBatches 的其他一些问题,我发现可能指向答案的最常见的事情是,每当纹理更改时都会创建一个新的 SpriteBatch,但即使将 SpriteSortMode 设置为 Texture 也没有任何改进。
帧速率下降发生在具有 7 个不同 ScollingBackgroundLayers 的游戏阶段,每个阶段绘制一个大约 700 像素宽和 900 高的单独纹理(每个层应该这样做不超过 2 次以考虑滚动效果) . 我觉得我必须遗漏一些明显的东西,因为游戏有时会使用完全相同的过载渲染多达 2-300 颗子弹,所以另外 14 次调用应该是杯水车薪。这仅仅是尝试绘制太大的纹理以使 SpriteBatch 无法有效处理的问题吗?这在 Windows 版本上不是问题,所以我想知道是否没有特定于平台的解决方法,或者 MonoGame 的 Draw 实现是否效率低下。欢迎任何反馈。
感兴趣的人的完整来源:
Linux - https://github.com/cmark89/AsteroidRebuttal-Linux
Windows - https://github.com/cmark89/AsteroidRebuttal
编辑:我尝试对其进行更多修改。我更改了对 Draw() 的调用以确保目标矩形等于屏幕的可绘制区域,但没有明显的变化。我将纹理换成一个非常小的纹理,这样就消除了延迟,所以我想它确实与纹理的大小有关。
编辑 2:好吧,我最终只是硬着头皮切开了我正在使用的透明层(就像某种不懒惰的人)。它解决了这个问题,大概是因为它不再需要渲染大量无用的像素,但它仍然让我想知道为什么这只是 Linux 上的一个问题。尽管我暂时已经解决了我的问题,但我还是会暂时搁置一下,以防万一有人知道是什么导致了巨大的性能差异。