2

タイルの 2D グリッドがあるとします (これは 2D タイル ベースのゲーム用です)。ほとんどのタイルは 1 つのスポットを占有しますが、一部の大きな「オブジェクト」は複数のスポットを埋めることができます。配列でインデクサーを使用して、これらのオブジェクトをベース タイルに自動的に "参照" します。したがって、3,4 に 2x2 オブジェクトがあり、4,4 にアクセスすると、自動的にリダイレクトされ、3,4 でタイルが取得されます。ただし、正確なタイルを取得する必要がある場合は、引数を指定してこの機能を回避できます。(これについてのGameDevに関する私の古い質問についてのより良い説明)

別の見方をすると、ゲームの世界のドア オブジェクトです。ユーザーはドアの任意の場所をクリックして開くことができますが、個々のパーツには、さまざまな背景や照明の値など、他のプロパティを含めることができます。

注: 私は趣味のプログラマーなので、これは正しくない可能性があります (なぜ私はあなたのアドバイスを求めているのですか)。各「特大」タイルは、そのベース タイルへの参照をX,Y位置の形式で格納します (これは代わりに参照である必要があります)。メモリ内の実際のオブジェクトに?)

public class TileWrapper
{
    public int Width = 0;
    public int Height = 0;
    private Tile[] tiles; //Backing Store
    public TileWrapper()
    {
        tiles = new Tile[Width * Height]; 
    }
    public TileWrapper(int width, int height)
    {
        Width = width;
        Height = height;
        tiles = new Tile[Width * Height];
    }
    /// <summary>
    /// Accessor for tiles
    /// </summary>
    /// <param name="x">X Position</param>
    /// <param name="y">Y Position</param>
    /// <param name="overide">Bool to "override" the get, if true, it wont get the reference tile and will bypass the checks</param>
    public Tile this[int x, int y, bool override = false]
    {
        get 
        {
             //If we do not want to bypass the checks, AND the current tile is > than 1x1
             if (!override && tiles[y * Width + x].IsLarge)
                return tiles[tiles[y * Width + x].refY * Width + tiles[y * Width + x].refX]; //Use the reference positions to get the main position of the tile
             //If we want to bypass the checks or the tile wasn't large, get the absolute position
             else 
                 return tiles[y * Width + x];
        }
        set 
        {
             //Same thing for SET
             if (!override && tiles[y * Width + x].IsLarge) //Set base tile if the large tile has a reference
                 tiles[tiles[y * Width + x].refY * Width + tiles[y * Width + x].refX] = value;
             else  //Set absolute tile
                  tiles[y * Width + x] = value;
        }
    }

2D から 1D への変換で読みにくい場合は申し訳ありませんが、いくつかのテストを行った後、内部で 1D 配列を使用する方が少し速いようです。

IsLargeタイルが大きい (1x1 より大きい) かどうかを単純にチェックするプロパティです。

大きなタイルが配置されたときに隣接するタイルの参照を埋め、それに応じてそれらを削除するロジックは既に用意されています。

ゲームのプロファイリング中に、タイルの get アクセサーが大量の CPU を消費し、ライティング、レンダリング、衝突などのためにフレームごとに何百回もタイルを取得していることがわかりました。

このコードのパフォーマンスと効率を改善するにはどうすればよいですか?

ベンチマーク(Intel Quad Core i7 2670QM での 30,000 回の反復の平均)

Tile t = tiles[100, 100];- 2D 内部アレイで 160 ns および 175 ns

Tile t = tiles[100, 100, true];- 137 ns および 264 ns WITH 2D 内部アレイ (奇数)

100,100は大きなタイルではありませんが、これらのタイルはあまり一般的ではないことに注意してください。画面に家があった場合、いくつかの大きなタイル (ドア、テーブル) が表示されますが、土/石/木がたくさんあります。

4

1 に答える 1