【发布时间】:2013-06-07 09:07:30
【问题描述】:
我一直在使用 MonoGame 将我在 XNA 中制作的滚动射击游戏移植到 Linux 上。几乎一切都进行得很顺利,但我在一个特定的地方遇到了一个问题,调用 SpriteBatch.Draw() 会削弱帧速率。大多数游戏运行良好,没有任何打嗝。它一次吸引大量敌人和大量子弹而没有任何减速。然而,导致丢帧的部分是分层滚动背景。代码的相关部分在这里。
Level.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 上的一个问题。尽管我暂时已经解决了我的问题,但我还是会暂时搁置一下,以防万一有人知道是什么导致了巨大的性能差异。
【问题讨论】:
-
我真的不记得不同事物的性能成本,但强制 GPU 绘制那么多高分辨率纹理可能不是一个好主意,你应该能够以不同的方式进行设计.如果记忆对我有用,那么这些纹理在发送到 GPU 时最终将是 1024*1024 纹理(由于 2-required 的幂并在运行时重新制作成该大小)。
-
这种情况下的问题是背景的每张图片滚动速度不同,或者透明度不同。其中一些我绝对可以切碎并创建在屏幕较小区域绘制的图层,但其中一些(主要是透明图层)并不那么容易。无论如何,我不知道 GPU 调整了两个纹理的非功率;也许我会调整它们的大小,看看它是否改变了什么。不管我打算做哪些优化,我真的很困惑为什么这个问题不会在 Windows 上发生。
标签: xna draw frame-rate monogame spritebatch