5

XNA で作成したスクロール シューティング ゲームを、MonoGame を使用して 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 だけの問題なのか疑問に思っています。当分の間問題を解決しましたが、劇的なパフォーマンスの違いを引き起こしている可能性があることについて誰かが洞察を持っている場合に備えて、これを少し開いたままにします.

4

1 に答える 1

2

この状況では、これを実現するために、代わりにシェーダーを使用することをお勧めします。これを行うことで、パフォーマンスが急上昇することがわかります。以下を見てください。

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

このようにすると、多くの CPU 使用率が軽減され、GPU が大部分の作業を行うようになります。

700x900 ではなく、2 の累乗でテクスチャを保存することもできます。(512x512のようなことをしてください)。グラフィックス パイプラインは、2 の累乗を持つテクスチャに関連するパフォーマンスを向上させます。

于 2013-06-07T10:44:37.583 に答える