0

我正在编写某种受几何战争启发的游戏,除了添加了 2d 刚体物理 Ai 寻路一些航点分析视线检查负载平衡等。似乎即使屏幕上有大约 80-100 个敌人,它也可以相当快地工作一旦你达到总共 250 个(150 个敌人)左右的物体,所有这些东西使性能完全崩溃。我已经搜索了代码中的任何 O(n^2) 部分,但似乎没有任何剩余。我也在使用空间网格。

即使我从所谓的昂贵的 Ai 相关处理中禁用了几乎所有东西,这似乎并不重要,它仍然会在 150 个敌人时崩溃。

现在我从头开始实现所有代码,目前甚至是矩阵乘法代码,而且我几乎完全依赖 GC 以及在某些事情上使用 C# 闭包,所以我希望这远未得到优化,但仍然对我来说,只有 1/15 的处理工作,但将对象加倍,游戏突然开始减速爬行,这对我来说没有意义吗?这是正常的吗,XNA 平台通常应该如何扩展正在处理的对象数量?

我记得我最初做的一些 slerp 旋转立方体的事情可以一次处理超过 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;

    }


}

公共类 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 回答