0

私はある種の Geometry Wars にインスパイアされたゲームを書いていますが、追加された 2D 剛体物理学、Ai パスファインディング、いくつかのウェイポイント分析、視線チェック、ロード バランシングなどがあります。全部で 250 個 (敵 150 個) のオブジェクトに到達すると、パフォーマンスが完全に低下します。コード内の O(n^2) 部分を検索しましたが、残っていないようです。空間グリッドも使用しています。

おそらく高価なAi関連の処理からほとんどすべてを無効にしても、それは問題ではないようですが、それでも150人の敵で故障するようです.

現在、すべてのコードをゼロから実装しました。現在は行列乗算コードも含めて、ほぼ完全に GC に依存しているだけでなく、C# クロージャーを使用しているため、これは最適化にはほど遠いと予想されますが、それでも処理作業の 1/15 で、オブジェクトが 2 倍になると、ゲームが突然速度を落としてクロールし始めるのは、私には意味がありません。これは正常ですか? XNA プラットフォームは、処理されるオブジェクトの量に関する限り、通常どのようにスケーリングすることになっていますか?

私が最初にやったスラープ回転キューブのことは一度に1000以上を処理できたので、何か間違ったことをしていると思いますか?

編集:グリッド構造のクラスは次のとおりです

パブリック抽象クラス GridBase{

    public const int WORLDHEIGHT = (int)AIGridInfo.height;
    public const int WORLDWIDTH = (int)AIGridInfo.width;
    protected float cellwidth;
    protected float cellheight;


    int no_of_col_types;

    // a dictionary of lists that gets cleared every frame
    // 3 (=no_of_col_types) groups of objects (enemy side, players side, neutral)
    // 4000 initial Dictionary hash positions for each group
    // I have also tried using an array of lists of 100*100 cells
    //with pretty much identical results
    protected Dictionary<CoordsInt, List<Collidable>>[] grid;


    public GridBase(float cellwidth, float cellheight, int no_of_col_types)
    {
        this.no_of_col_types = no_of_col_types;
        this.cellheight=cellheight;
        this.cellwidth=cellwidth;

        grid = new Dictionary<CoordsInt, List<Collidable>>[no_of_col_types];
        for (int u = 0; u < no_of_col_types; u++)
           grid[u] = new Dictionary<CoordsInt, List<Collidable>>(4000);

    }

    public abstract void InsertCollidable(Collidable c);
    public abstract void InsertCollidable(Grid_AI_Placeable aic);

    //gets called in the update loop
    public void Clear()
    {
        for (int u = 0; u < no_of_col_types; u++)
            grid[u].Clear();
    }

    //gets the grid cell of the left down corner
    protected void BaseCell(Vector3 v, out int gx, out int gy)
    {
        gx = (int)((v.X + (WORLDWIDTH / 2)) / cellwidth);
        gy = (int)((v.Y + (WORLDHEIGHT / 2)) / cellheight);

    }

    //gets all cells covered by the AABB
    protected void Extent(Vector3 pos, float aabb_width, float aabb_height, out int totalx, out int totaly)
    {
        var xpos = pos.X + (WORLDWIDTH / 2);
        var ypos = pos.Y + (WORLDHEIGHT / 2);
        totalx = -(int)((xpos / cellwidth)) + (int)((xpos + aabb_width) / cellwidth) + 1;
        totaly = -(int)((ypos / cellheight)) + (int)((ypos + aabb_height) / cellheight) + 1;

    }


}

public class GridBaseImpl1 : GridBase{

    public GridBaseImpl1(float widthx, float widthy)
        : base(widthx, widthy, 3)
    {

    }


    //adds a collidable to the grid /
    //caches for intersection test
    //checks if it should be tested to prevent penetration /
    //tests penetration
    //updates close, intersecting, touching lists
    //Collidable is an interface for all objects that can be tested geometrically
    //the dictionary is indexed by some simple struct that wraps the row and column number in the grid
    public override void InsertCollidable(Collidable c)
    {

        //some tag so that objects don't get checked more than once
        Grid_Query_Counter.current++;

        //the AABB is allocated in the heap
        var aabb = c.CollisionAABB;
        if (aabb == null) return;
        int gx, gy, totalxcells, totalycells;
        BaseCell(aabb.Position, out gx, out gy);

        Extent(aabb.Position, aabb.widthx, aabb.widthy, out totalxcells, out totalycells);

        //gets which groups to test this object with in an IEnumerable (from a statically created array)
        var groupstestedagainst = CollidableCalls.GetListPrevent(c.CollisionType).Select(u =>   CollidableCalls.group[u]);
        var groups_tested_against = groupstestedagainst.Distinct();
        var own_group = CollidableCalls.group[c.CollisionType];


        foreach (var list in groups_tested_against)
            for (int i = -1; i < totalxcells + 1; i++)
                for (int j = -1; j < totalycells + 1; j++)
                {

                    var index = new CoordsInt((short)(gx + i), (short)(gy + j));

                    if (grid[list].ContainsKey(index))

                        foreach (var other in grid[list][index])
                        {

                            if (Grid_Query_Counter.Check(other.Tag))
                            {

                                //marks the pair as close, I've tried only keeping the 20 closest but it's still slow
                                other.Close.Add(c);
                                c.Close.Add(other);

                                //caches the pair it so that checking if the pair intersects doesn't go through the grid        //structure loop again
                                c.CachedIntersections.Add(other);

                                var collision_function_table_id = c.CollisionType * CollidableCalls.size +      other.CollisionType;


                                //gets the function to use on the pair for testing penetration
                                //the function is in a delegate array statically created to simulate multiple dispatch
                                //the function decides what coarse test to use until descending to some complete        //geometric query
                                var prevent_delegate = CollidableCalls.preventfunctions[collision_function_table_id];

                                if (prevent_delegate == null) { Grid_Query_Counter.Put(other.Tag); continue; }

                                var a = CollidableCalls.preventfunctions[collision_function_table_id](c, other);

                                //if the query returns true mark as touching
                                if (a) { c.Contacted.Add(other); other.Contacted.Add(c); }






                                //marks it as tested in this query
                                Grid_Query_Counter.Put(other.Tag);
                            }




                        }


                }

        //adds it to the grid if the key doesn't exist it creates the list first
        for (int i = -1; i < totalxcells + 1; i++)
            for (int j = -1; j < totalycells + 1; j++)
            {
                var index = new CoordsInt((short)(gx + i), (short)(gy + j));

                if (!grid[own_group].ContainsKey(index)) grid[own_group][index] = new List<Collidable>();

                grid[own_group][index].Add(c);
            }
    }


    [...]
}
4

2 に答える 2

2

初め。コードをプロファイリングします。手動で挿入したタイム スタンプを使用して、関心のあるブロックを囲むだけでも構いません。私は、Visual Studio Pro に組み込まれているプロファイラーを使用することを好みます。

ただし、あなたの説明に基づいて、あなたの問題はドローコールが多すぎることが原因であると思います。フレームあたりの描画呼び出しが 200 ~ 400 を超えると、パフォーマンスが劇的に低下する可能性があります。レンダリングをバッチ処理して、パフォーマンスが向上するかどうかを確認してください。

于 2012-06-12T18:18:42.843 に答える
0

ANTS Profilerなどのプロファイラーを使用して、何が問題であるかを確認できます。

コードがなければ、私にできることはあまりありません。

于 2012-06-11T19:47:23.090 に答える