2

私はこの問題の回避策をあらゆる場所で探しました (解決策が転がっているのが見えないだけかもしれません)。私のゲームは現在、画面上にタイルマップをレンダリングしていますが、実際には画面の境界内にないタイルはレンダリングしません。ただし、各タイルは 16x16 ピクセルです。つまり、画面上のすべてのピクセルに解像度 1920x1080 のタイルが含まれている場合、8100 個のタイルを描画する必要があります。

サイクルごとに多くのタイルを描画すると、私の FPS は本当に死んでしまいます。解像度 800x600 で実行すると、FPS は ~20 になり、1920x1080 では約 3 ~ 5 FPS で実行されます。これは本当に私を夢中にさせます。

スレッド化と非同期タスクの使用を試みましたが、画面がちらつくだけです。おそらく私が間違ってコーディングしているだけです。

これが私が現在使用している描画コードです。

        // Get top-left tile-X
        Vector topLeft = new Vector(Screen.Camera.X / 16 - 1, 
            Screen.Camera.Y / 16 - 1);
        Vector bottomRight = new Vector(topLeft.X + (Screen.Width / 16) + 2, 
            topLeft.Y + (Screen.Height / 16) + 2);

        // Iterate sections
        foreach (WorldSection section in Sections)
        {
            // Continue if out of bounds
            if (section.X + ((Screen.Width / 16) + 2) < (int)topLeft.X ||
                section.X >= bottomRight.X)
                continue;

            // Draw all tiles within the screen range
            for (int x = topLeft.X; x < bottomRight.X; x++)
                for (int y = topLeft.Y; y < bottomRight.Y; y++)
                    if (section.Blocks[x - section.X, y] != '0')
                        DrawBlock(section.Blocks[x - section.X, y], 
                            x + section.X, y);
        }

8 ~ 12 のセクションがあります。各タイルは、2 次元配列の char オブジェクトで表されます。

描画ブロックの方法:

public void DrawBlock(char block, int x int y)
    {
        // Get the source rectangle
        Rectangle source = new Rectangle(Index(block) % Columns * FrameWidth,
            Index(block) / Columns * FrameHeight, FrameWidth, FrameHeight);

        // Get position
        Vector2 position = new Vector2(x, y);

        // Draw the block
        Game.spriteBatch.Draw(Frameset, position * new Vector2(FrameWidth, FrameHeight) - Screen.Camera, source, Color.White);
    }

Index() メソッドは、char に対応するタイルのフレーム インデックスを返すだけです。

この方法でフレームレートを犠牲にすることなく、実際にこれだけ多くを一度に描画できるようにする方法を考えています。私が提供したコードは明らかにあまり最適化されていませんか?それとも、パフォーマンスを低下させずにこれほど多くの個々のタイルを描画できるようにするために何か特別なことをしなければなりませんか?

4

1 に答える 1

0

これが問題に対処する最善の方法かどうかはわかりませんが、RenderTarget2D を使用して、世界のチャンクをテクスチャに事前レンダリングし始めました。一度にすべてのチャンクをロードするとメモリ不足になるため、実際の画面境界周辺の特定の領域内にチャンクを一度にロードする必要があります。

現在の事前レンダリングされた領域の境界に近づくと、ワールド内の新しい位置に基づいてチャンクが再処理されます。処理には約 100 ミリ秒かかるため、新しいエリアをロードするとき、プレイヤーはこの間わずかに速度が低下したと感じます。私はそれがあまり好きではありませんが、少なくとも FPS は現在 60 です。

これが私のチャンクプロセッサです:

    public bool ProcessChunk(int x, int y)
    {
        // Create render target
        using (RenderTarget2D target = new RenderTarget2D(Game.CurrentDevice, 16 * 48, 16 * 48,
            false, SurfaceFormat.Color, DepthFormat.Depth24))
        {

            // Set render target
            Game.CurrentDevice.SetRenderTarget(target);

            // Clear back buffer
            Game.CurrentDevice.Clear(Color.Black * 0f);

            // Begin drawing
            Game.spriteBatch.Begin(SpriteSortMode.Texture, BlendState.AlphaBlend);

            // Get block coordinates
            int bx = x * 48,
                by = y * 48;

            // Draw blocks
            int count = 0;
            foreach (WorldSection section in Sections)
            {
                // Continue if section is out of chunk bounds
                if (section.X >= bx + 48) continue;

                // Draw all tiles within the screen range
                for (int ax = 0; ax < 48; ax++)
                    for (int ay = 0; ay < 48; ay++)
                    {
                        // Get the block character
                        char b = section.Blocks[ax + bx - section.X, ay + by];

                        // Draw the block unless it's an empty block
                        if (b != '0')
                        {
                            Processor.Blocks[b.ToString()].DrawBlock(new Vector2(ax, ay), true);
                            count++;
                        }
                    }
            }

            // End drawing
            Game.spriteBatch.End();

            // Clear target
            target.GraphicsDevice.SetRenderTarget(null);

            // Set texture
            if (count > 0)
            {
                // Create texture
                Chunks[x, y] = new Texture2D(Game.CurrentDevice, target.Width, target.Height, true, target.Format);

                // Set data
                Color[] data = new Color[target.Width * target.Height];
                target.GetData<Color>(data);
                Chunks[x, y].SetData<Color>(data);

                // Return true
                return true;
            }
        }

        // Return false
        return false;
    }

このアプローチを改善する方法について何か提案があれば、それを聞いて悲しくはありません!

ここで助けてくれてありがとう!

于 2013-10-11T11:45:29.563 に答える