5

我一直在使用 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 上的一个问题。尽管我暂时已经解决了我的问题,但我还是会暂时搁置一下,以防万一有人知道是什么导致了巨大的性能差异。

4

1 回答 1

2

在这种情况下,我建议您改用着色器来完成此操作。这样做你会看到你的表现飞涨。看看以下内容:

http://www.david-gouveia.com/scrolling-textures-with-zoom-and-rotation/

这样做,将减轻大量 CPU 使用率,并使您的 GPU 完成大部分工作。

您可能还希望将纹理存储为 2 的幂,而不是 700x900。(做类似512x512的事情)。您的图形管道具有与具有 2 次幂的纹理相关的性能提升。

于 2013-06-07T10:44:37.583 回答