是STD ::设置我应该用什么来组织对象到层次结构?

时间:2012-04-08 01:19:08

标签: c++ boost data-structures hierarchy

我想将所有GameObjects组织成一个层次结构。我认为一棵树最适合这个。我曾考虑使用STD :: Set来处理这个问题。这有任何意义吗?基本上,GameObject可以容纳可变数量的其他GameObject。如果我以这种方式处理它,那么处理访问树中对象的最佳方法是什么?通过ID访问它们是否足够快?我想我也可以通过指针访问它们,但如果你遇到很多对象的情况,那些传递它们听起来有点危险和乏味。

如果有任何影响,我也会显示这些数据。

EX:

-Hierarchy
    -GameObject
        -GameObject
        -Gameobject
    -GameObject
        -GameObject
            -GameObject
   -GameObject

我感谢任何输入的人。感谢。

4 个答案:

答案 0 :(得分:3)

我假设你想做这样的事情:

class GameObject {
    some_container<GameObject> nested_objects_;
    ....
}

如果你真的不需要O(log(n))搜索并删除你的对象集合,我建议改用std::vector,这样你就可以避免内存开销,并且(非常可能)有些CPU开销也是。因此,如果您只需要为每个对象存储几个嵌套对象,那么一定要选择std::vector

但是如果您需要快速查找/删除对象或保持唯一性,那么std::set可能是一个不错的选择。为了使用std::set,您需要提供一个比较函数,它的作用类似于<运算符(严格来说,您的比较函数必须是strict weak ordering。)您可以只定义{{1}对于你operator <类。 GameObject的效率取决于此函数,因此请小心。

注意,您可以通过提供std::set本身来遍历整个集合或find个人GameObjects(严格来说,您可以提供其等价物 - 查看比较函数) 。因此,如果您需要通过其id获取对象,请更好地使用GameObject,它更适合此类作业。 std::set referencestd::map reference

我还建议调查boost :: unordered_set&amp; boost :: unordered_map(如果可以使用C ++ 11,则为std :: unordered_set&amp; std :: unordered_map)。

答案 1 :(得分:1)

您是否有理由认为每个“游戏对象”都不能将游戏对象数组作为实例变量?也许你的主要应该创建一个GameObjects数组,并且每个游戏对象都可以在数组实例变量中保存正在进行的游戏对象。这就是我至少会想到它的方式。

答案 2 :(得分:1)

  

我考虑过使用STD :: Set来处理这个问题。这有什么意义吗?

没有。 std :: set用于存储唯一对象的集合,其中对象使用用户提供的operator<lessthan比较器进行排序。没有理由将std :: set用于对象列表。

  

通过ID访问它们的速度是否足够快?

这就是问题所在。 ID中没有std::set个。有物体。因此,如果您使用std :: set,您将无法通过ID访问对象而无需遍历整个集合(除非对象按ID排序,但这是另一个故事)。要将某些内容映射到其他内容,请使用std::mapstd::set用于收藏。

  

如果我以这种方式处理它,那么处理访问树中对象的最佳方法是什么?

最好的方法可能是使用列表或deques - 取决于你的游戏处理对象的方式。

没有&#34;最好的&#34;表示树木的方式。

  1. 您可以将层次结构的根对象存储在列表中,并将子项存储在父对象中。
  2. 您可以存储列表中的所有对象(子项和父项),子项对象存储对父项的引用,然后确保&#34; update()&#34;功能考虑到了这一点。
  3. 您可以存储两个列表 - 一个用于根对象,另一个用于所有对象。 (例如,您在第1个列表上调用update,并使用第二个列表进行冲突检测查询等)
  4. 所有这些方法都有意义,对某些情况有用。

      

    但是传递那些听起来有点危险

    是的,当一个发射导弹的人被炸成碎片并导弹指向所有者进行友军火力检查时,这是一个确定的崩溃方法。但是,由于您的问题被标记为&#34; boost&#34;,您可以使用boost::weak_ptr来解决此问题。此外,对象可以存储为std :: list,std :: deque甚至std :: vector中的shared_ptr列表 - 具体取决于您的游戏将如何使用它们。

答案 3 :(得分:0)

对于它的价值,我发现通过“path”访问它们,有点像磁盘上的目录树,效果很好。这是从我正在编写的一些C#代码中获取的(注意我在下面的课程中遗漏了一些内容),但这个想法将直接转换为C ++:

sealed class Entity : IEntity
{
    private readonly IDictionary<string,IEntity> m_children = new Dictionary<string,IEntity>();

    private readonly IDictionary<string,dynamic> m_properties;

    public string Name { get { return m_properties["Name"]; } }

    public IEntity Parent { get; set; }

    /// <summary>
    /// Adds a child to this entity.
    /// </summary>
    /// <param name="child">The child to add.</param>
    public void AddChild(IEntity child)
    {
        m_children.Add(child.Name, child);
        child.Parent = this;
    }

    /// <summary>
    /// Gets the absolute path of this entity in its tree.
    /// </summary>
    /// <returns>The entity's absolute path.</returns>
    public string GetAbsolutePath()
    {
        IEntity cur = this;
        var path = new LinkedList<string>();
        while(cur.Parent != null)
        {
            path.AddFirst(cur.Name);
            cur = cur.Parent;
        }
        path.AddFirst(".");
        return string.Join("/", path);
    }

    /// <summary>
    /// Gets another entity in this entity's tree by its absolute path (i.e. its path relative to the root entity).
    /// </summary>
    /// <param name="path">The absolute path to the other entity.</param>
    /// <returns>The other entity, if found, or null otherwise.</returns>
    public IEntity GetEntityByAbsolutePath(string path)
    {
        return GetRootEntity().GetEntityByRelativePath(path);
    }

    /// <summary>
    /// Gets another entity in this entity's tree by its absolute path (i.e. its path relative to the root entity).
    /// </summary>
    /// <param name="path">The absolute path to the other entity, as a list of path components.</param>
    /// <returns>The other entity, if found, or null otherwise.</returns>
    public IEntity GetEntityByAbsolutePath(LinkedList<string> path)
    {
        return GetRootEntity().GetEntityByRelativePath(path);
    }

    /// <summary>
    /// Gets another entity in this entity's tree by its path relative to this entity.
    /// </summary>
    /// <param name="path">The relative path to the other entity.</param>
    /// <returns>The other entity, if found, or null otherwise.</returns>
    public IEntity GetEntityByRelativePath(string path)
    {
        return GetEntityByRelativePath(new LinkedList<string>(path.Split('/')));
    }

    /// <summary>
    /// Gets another entity in this entity's tree by its path relative to this entity.
    /// </summary>
    /// <param name="path">The relative path to the other entity, as a list of path components.</param>
    /// <returns>The other entity, if found, or null otherwise.</returns>
    public IEntity GetEntityByRelativePath(LinkedList<string> path)
    {
        IEntity cur = this;

        while(cur != null && path.Count != 0)
        {
            switch(path.First())
            {
                case ".":
                    break;
                case "..":
                    cur = cur.Parent;
                    break;
                default:
                    cur = cur.GetChild(path.First());
                    break;
            }

            path.RemoveFirst();
        }

        return cur;
    }

    /// <summary>
    /// Gets the root entity of this entity's tree.
    /// </summary>
    /// <returns>The root entity of this entity's tree.</returns>
    private IEntity GetRootEntity()
    {
        IEntity cur = this;
        while(cur.Parent != null)
        {
            cur = cur.Parent;
        }
        return cur;
    }
}

给定实体树中的任何实体,然后您可以通过其绝对路径或相对路径访问其他实体,例如

cityA.GetEntityByRelativePath("../city:B/building:1");