XNA performance

本文关键字:performance XNA | 更新日期: 2023-09-27 18:36:54

我正在编写某种受几何战争启发的游戏,除了添加 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;
    }

}

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);
            }
    }

    [...]
}

XNA performance

第一。分析代码。即使您只是使用手动插入的时间戳来包围您感兴趣的块。我更喜欢使用Visual Studio Pro内置的分析器。

但是,根据您的描述,我认为您的问题是由于太多的绘制调用造成的。一旦每帧超过 200-400 次绘制调用,您的性能就会急剧下降。尝试对渲染进行批处理,看看这是否会提高性能。

您可以使用探查器(如 ANTS 探查器)来查看可能出现的问题。

没有任何代码,我无能为力。