4

すべてのGameObjectを階層構造に編成したいと思います。これには木が一番いいと思います。これを処理するためにSTD::Setを使用することを考えました。それは意味がありますか?基本的に、GameObjectは可変数の他のGameObjectを保持できます。この方法で処理する場合、ツリー内のオブジェクトへのアクセスを処理するための最良の方法は何ですか?IDを介してそれらにアクセスするのは十分に速いでしょうか?ポインタを介してそれらにアクセスすることもできると思いますが、オブジェクトがたくさんある状況になると、それらを渡すのはやや危険で退屈に聞こえます。

影響がある場合は、このデータも表示します。

元:

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

入力してくれた人に感謝します。ありがとう。

4

4 に答える 4

3

私はあなたがこのようなことをしたいと思っています:

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

O(log(n))オブジェクトのコレクションで検索と削除が本当に必要ない場合はstd::vector、代わりに使用することをお勧めします。これにより、メモリのオーバーヘッドと (おそらく) CPU のオーバーヘッドも回避できます。したがって、オブジェクトごとにいくつかのネストされたオブジェクトを保存するだけでよい場合は、間違いなく選択してくださいstd::vector

ただし、オブジェクトをすばやく検索/削除したり、一意性を維持したりする必要がstd::setある場合は、良い選択かもしれません。使用するstd::setには、演算子のように機能する比較関数を提供する必要があります<(厳密に言えば、比較関数は厳密な弱い順序付けである必要があります) 。クラスを定義するだけでかまいoperator <ません。GameObjectの効率はstd::setこの関数に依存するので、ここで注意してください。

セット全体、またはそれ自体を提供することによってfind個別にトラバースすることに注意してください(厳密に言えば、同等のものを提供することができます - 比較関数を調べてください)。そのため、ID でオブジェクトを取得する必要がある場合は、 を使用すると、このタイプのジョブにより適しています。 参照してください参照GameObjectsGameObjectstd::mapstd::setstd::map

また、boost::unordered_set & boost::unordered_map (または C++11 を使用できる場合は std::unordered_set & std::unordered_map) を調べることをお勧めします。

于 2012-04-08T02:07:56.867 に答える
1

各「ゲームオブジェクト」がインスタンス変数としてゲームオブジェクトの配列を持つことができない理由はありますか?おそらく、メインはGameObjectsの配列を作成する必要があり、それらのゲームオブジェクトのそれぞれは、配列インスタンス変数に進行中のゲームオブジェクトを保持できます。それは私が少なくともそれについて考える方法です。

于 2012-04-08T01:27:31.783 に答える
1

これを処理するために STD::Set を使用することを考えました。それは意味がありますか?

いいえ。 std::set は、一意のオブジェクトのコレクションを格納するために作成されます。オブジェクトは、ユーザーが提供するoperator<またはlessthanコンパレーターを使用して並べ替えられます。オブジェクト リストに std::set を使用する理由はありません。

ID 経由でそれらにアクセスするのは十分に速いでしょうか?

これがキャッチです。には がありませIDstd::set。オブジェクトがあります。そのため、std::set を使用すると、セット全体を反復せずにオブジェクトにアクセスすることはできませんID(オブジェクトが ID 順に並べられている場合を除きますが、それは別の話です)。何かを別のものにマップするには、 を使用しますstd::mapstd::setコレクション用です。

この方法で処理する場合、ツリー内のオブジェクトへのアクセスを処理する最良の方法は何ですか?

ゲームがオブジェクトを処理する方法に応じて、おそらくリストまたはデキューを使用するのが最善の方法です。

木を表現するための「最良の」方法はありません。

  1. 階層のルート オブジェクトをリストに格納し、子を親オブジェクト内に格納できます。
  2. リスト内のすべてのオブジェクト (子と親の両方) を格納できます。子オブジェクトは親への参照を格納し、「update()」関数がそれを考慮に入れるようにします。
  3. 2 つのリストを保存できます。1 つはルート オブジェクト用で、もう 1 つはすべてのオブジェクト用です。(たとえば、最初のリストで更新を呼び出し、衝突検出クエリなどに 2 番目のリストを使用します)

これらのアプローチはすべて理にかなっていて、特定のシナリオで役立つ場合があります。

しかし、それらの周りを通り過ぎるのは少し危険に聞こえます

ええ、ミサイルを発射した誰かが粉々に吹き飛ばされ、ミサイルがフレンドリーファイアチェックのために所有者へのポインターを持っている場合、それはゲームをクラッシュさせる確実な方法です. ただし、質問には「boost」というタグが付けられているboost::weak_ptrため、この問題に対処するために使用できます。また、オブジェクトはshared_ptr、ゲームでの使用方法に応じて、std::list、std::deque、さらには std::vector 内の のリストとして格納することもできます。

于 2012-04-08T02:06:06.050 に答える
0

価値があるのは、ディスク上のディレクトリツリーに少し似た「パス」でアクセスするのが非常にうまくいくことです。これは、私が書いているいくつかの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");
于 2012-04-08T01:44:25.560 に答える