cma*_*k89 5 xna frame-rate draw monogame spritebatch
我一直在使用MonoGame将我在XNA中制作的滚动射击游戏移植到Linux上.几乎所有事情都进展顺利,但我在一个特定的地方遇到问题,调用SpriteBatch.Draw()会削弱帧速率.大多数游戏运行良好,没有任何打嗝.它同时吸引了大量的敌人和大量的子弹而没有任何减速.但是,导致丢帧的部分是分层滚动背景.代码的相关部分在这里.
Level.cs:
public void Draw(SpriteBatch spriteBatch)
{
foreach (ScrollingBackgroundLayer sbl in scrollingBackground)
{
sbl.Draw(spriteBatch);
}
}
Run Code Online (Sandbox Code Playgroud)
上面的"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);
}
}
Run Code Online (Sandbox Code Playgroud)
一旦我注释掉对ScrollingBackgroundLayer.Draw()的调用,所有的帧速率问题都会消失,所以这似乎是一个非常大的提示,即问题来自SpriteBatch尝试绘制滚动图层.显然,我想弄清楚为什么会这样.我查看了SpriteBatches的其他一些问题,我发现可能指向答案的最常见的事情是每当纹理发生变化时都会创建一个新的SpriteBatch,但即使将SpriteSortMode设置为Texture也没有任何改进.
帧速率降低发生在具有7个不同ScollingBackgroundLayers的游戏阶段,每个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上的一个问题.尽管我暂时解决了我的问题,但我还是要稍微公开一下,以防任何人对可能导致严重性能差异的问题有所了解.
在这种情况下,我建议您改用着色器来实现此目的。通过这样做,你会发现你的表现突飞猛进。看看以下内容:
http://www.david-gouveia.com/scrolling-textures-with-zoom-and-rotation/
这样做可以减少大量 CPU 使用率,并让 GPU 完成大部分工作。
您可能还想以 2 的幂存储纹理,而不是 700x900。(例如 512x512)。您的图形管道具有与具有 2 的幂的纹理相关的性能提升。