15

古い古典的なバイオハザードのタイトルに似たゲームのアイテム システムに取り組んでいます。現在、さまざまなアイテムを組み合わせて新しい何かを得るアイテム合成を実装しています。複雑さは、変換のレベルが複数あり、各レベルに複数のメイトがあるアイテムが存在するという事実から生じます。緑、赤、青のハーブがあるとしましょう。赤と青を組み合わせることはできませんが、G+B を組み合わせてGreenBlueHerbのようなものを取得したり、G+R を組み合わせてGreenRedHerbを取得したりできます。これらの結果のいずれかを青いハーブに組み合わせると、次のようになります。グレイハーブ. この例からわかるように、緑のハーブには 2 つのレベルの変換があり、最初のレベルに到達するには、2 つの可能な仲間 (赤|青) があり、その時点からレベル 2 に行くと、ただ 1 つの仲間しかありません。 (青い)。

そこで私は興味深いツリーを思いつきました。2 つだけでなく、 nLevelsを下るすべての可能性をカバーしています。レベルが増えるほど、ツリーはより複雑になります。この 3 つのレベルの例を見てください。真ん中に見える三角形は、アイテム、およびその周りの他の色付きの形状は、次のレベルに到達するための可能な仲間を表します:

ここに画像の説明を入力

さまざまな組み合わせがあります。最初にアイテムを青いものと組み合わせ、次に赤、次に緑、または緑、次に赤、次に青などを組み合わせて、最終レベルに到達します。考えられるすべての組み合わせを表すこのツリーを思いつきました。

ここに画像の説明を入力

(右の数字は #levels、左の数字は各レベルの #nodes です) しかし、ご覧のとおり、冗長です。エンド ノードを見ると、それらはすべて同じ最終結果 (G+R+B) につながるため、すべて 1 である必要があります。この状況では、実際には合計で 7 つの状態が考えられます。右のツリーは次のとおりです。

ここに画像の説明を入力

これは非常に理にかなっています。ノード数の大きな違いに注目してください。

私の質問は、これに適したデータ構造は何ですか? -これには組み込みのものはないと確信しているので、実際に行った独自のカスタムのものを作成し、なんとか機能させる必要がありますが、問題があります。(言及する価値のあることの1つは、XMLファイルからノード情報を取得していることです。情報とは、ノード/レベルに到達するために必要なアイテムと、そのノードでのアイテムの名前になることを意味します。例:緑のハーブの場合RedGreenHerb状態に到達するには、RedHerbが「必要」です。その組み合わせが発生すると、「 GreenHerb 」という名前が「RedGreenHerb に変わります、消えるだけです。もう必要ありません)、これが私のデータ構造です:

public struct TransData
{
    public TransData(string transItemName, string itemRequired)
    {
        this.transItemName = transItemName;
        this.itemRequired = itemRequired;
    }
    public string transItemName;
    public string itemRequired;
}

public class TransNode
{
    public List<TransNode> nodes = new List<TransNode>();
    public TransData data;
    public TransNode(TransNode node): this(node.data.transItemName, node.data.itemRequired) { }
    public TransNode(string itemName, string itemRequired)
    {
       data = new TransData(itemName, itemRequired);
    }
}

public class TransLevel
{
    public List<TransNode> nodes = new List<TransNode>();
    public TransNode NextNode { get { return nodes[cnt++ % nodes.Count]; } }
    int cnt;
}

public class TransTree
{    
    public TransTree(string itemName)
    {
        this.itemName = itemName;
    }
    public string itemName;
    public TransNode[] nodes;
    public List <TransLevel> levels = new List<TransLevel>();
    // other stuff...
}

説明させてください: これTransTreeは実際にはベース ノードであり、開始時にアイテムの名前 (たとえば GreenHerb ) があり、ツリーにはいくつかのレベル (写真に表示されている黒の線) があり、各レベルにはいくつかのノードがあります。 、各ノードには、新しい項目データと、同様にポイントする多数のノード (子ノード) が含まれます。TransTreeここで、ノードのリストをクラスに入れる必要があるのは何ですか?と尋ねているかもしれません。- XML ファイルからデータを取得する方法を示した後で、それについてお答えします。

public TransTree GetTransItemData(string itemName)
{
    var doc = new XmlDocument();
    var tree = new TransTree(itemName);
    doc.LoadXml(databasePath.text);

    var itemNode = doc.DocumentElement.ChildNodes[GetIndex(itemName)];
    int nLevels = itemNode.ChildNodes.Count;
    for (int i = 0; i < nLevels; i++) {
       var levelNode = itemNode.ChildNodes[i];
       tree.levels.Add(new TransLevel());
       int nPaths = levelNode.ChildNodes.Count;
       for (int j = 0; j < nPaths; j++) {
            var pathNode = levelNode.ChildNodes[j];
        string newName = pathNode.SelectSingleNode("NewName").InnerText;
        string itemRequired = pathNode.SelectSingleNode("ItemRequired").InnerText;
        tree.levels[i].nodes.Add(new TransNode(newName, itemRequired));
       }
    }
    tree.ConnectNodes(); // pretend these two
    tree.RemoveLevels(); // lines don't exist for now
    return tree;

}

すべてを明確にするための XML サンプルを次に示します: ItemName->Level->Path (これは単なるノードです)->Path データ

<IOUTransformableItemsDatabaseManager>
  <GreenHerb>
    <Level_0>
      <Path_0>
        <NewName>RedGreenHerb</NewName>
        <ItemRequired>RedHerb</ItemRequired>
      </Path_0>
      <Path_1>
        <NewName>BlueGreenHerb</NewName>
        <ItemRequired>BlueHerb</ItemRequired>
      </Path_1>
    </Level_0>
    <Level_1>
      <Path_0>
        <NewName>GreyHerb</NewName>
        <ItemRequired>BlueHerb</ItemRequired>
      </Path_0>
    </Level_1>
  </GreenHerb>
</IOUTransformableItemsDatabaseManager>

そのようにすることの問題点は、ノードが互いに接続されていないことです。それは何を意味するのでしょうか? アイテムが特定のレベルへの特定のパスをたどる場合、それがたどらなかった他のパスを保存し続ける必要がないことは確かです。(パスを取得すると、そのパスをたどる義務があり、決して振り返ることはありません)私が持ちたいのは、ノードを取り出すと、その下の残りのすべてのノードですこれは理にかなっていますが、現在私がこれまでにやっている方法は次のようなものです:

ここに画像の説明を入力

ノードが接続されていないことがわかるように、それらを保持しているのはレベルです! つまり、現在、すべての子ノードを削除する方法でノードを削除する方法はありません。(ノードが接続されていないという事実なしでそれを行うのは非常に困難であり、パフォーマンスが大幅に低下します)。

tree.ConnectNodes(); 
tree.RemoveLevels();

最初にノードを接続してから、レベルを削除しますか? そうしないと、各ノードには 2 つの参照があり、1 つは親ノードから、もう 1 つは現在のレベルからです。これは実際には、私ConnectNodeが示した長いツリーの場合であり、7 つの状態を持つ最適化されたツリーの場合ではありません。

    // this is an overloaded version I use inside a for loop in ConnectNodes()
    private void ConnectNodes(int level1, int level2)
    {
        int level1_nNodes = levels[level1].nodes.Count;
        int level2_nNodes = levels[level2].nodes.Count;

        // the result of the division gives us the number of nodes in level2,
        // that should connect to each node in level1. 12/4 = 3, means that each
        // node from level1 will connect to 3 nodes from level2;
        int nNdsToAtch = level2_nNodes / level1_nNodes;
        for (int i = 0, j = 0; i < level2_nNodes; j++)
        {
            var level1_nextNode = levels[level1].nodes[j];
            for (int cnt = 0; cnt < nNdsToAtch; cnt++, i++)
            {
                var level2_nextNode = levels[level2].nodes[i];
                level1_nextNode.nodes.Add(new TransNode(level2_nextNode));
            }
        }
   }

これは最終的に私が他のツリーに持ちたいものですが、方法がわかりません。ノードを接続して、私が示した2番目のツリーを形成したいのですが、これはexの4レベルよりも比較的単純で、ペイントでノードを接続することさえできませんでした! (4レベルやってみたところ)

よく見ると、2 進数に似ていることがわかります。これが私のツリーを 2 進数で表したものです。

001
010
100
011
101
110
111

各「1」は実際のアイテムを表し、「0」は空を意味します。私のツリーから、「001」=青、「010」=緑、「100」=赤、「011」は緑+青、...「111」=灰色 (最終レベル)

だから今、私は最初にすべてを説明しました:私のアプローチは正しいですか?そうでない場合、何ですか?もしそうなら、これを達成するために使用/作成できるデータ構造は何ですか? そして、私が思いついたデータ構造がその場所にある場合、ノードを一緒に接続して、ノードを取り出すたびにその子ノードを取り出す方法で、XMLファイルからデータ構造にデータを保存するにはどうすればよいですかそれと?

あなたの助けと忍耐を前もって感謝します:)

編集: 興味深いことに、このシステム全体は、ゲーム全体で 1 回だけ発生する (1 回拾われる) アイテム用です。これが、パスを取得するたびにメモリから削除し、アイテムを取得するたびに、そのエントリをデータベースから削除する理由です。

編集:私は自分のアイテムを文字列だけで表すだけでなく、他の多くのプロパティを持っていることに注意してください。しかし、この状況では名前だけを気にします。そのため、文字列を扱っています。

4

2 に答える 2

2

このソリューションで気に入らない点:

  • シンプルなソリューションが最善のソリューションです
  • xml はグラフに基づいているため、保守が困難です。
  • OOPを実際に利用しないでください
  • バグの原因
  • 小さな問題に を使用する可能性がありReflectionます (小さいと言うのは、そのようなゲームを行うと、はるかに困難な問題に直面するからです ;))。これは、不必要な複雑さを意味します。

このソリューションで私が好きなもの:

  • あなたは問題を完全に理解しました。各アイテムには、他のオブジェクトとの変換のリストがあります。問題は、それをどのように表現するか(保存しないか)です。

私がしなければならなかったこと(私見ですが、あなたのソリューションも良いです):ノードのみの観点でOOPを使用してください。したがって、ツリーをデータ構造にアタッチする場合は、ツリーがステート マシンになります(パスについて話していたように ;))。

public class InventoryObject
{
    protected Dictionnary<Type, InventoryObject> _combinations = new Dictionnary<Type, InventoryObject>();

    public InventoryObject() {}       

    public InventoryObject Combine(InventoryObject o)
    {
       foreach (var c in _combinations)
          if (typeof(o) == c.Key)
            return c.Value

       throw new Exception("These objects aren't combinable");
    }
}

public class BlueHerb : InventoryObject
{
    public Herb()
    {
       _combinations.Add(RedHerb, new BlueRedHerb());
       _combinations.Add(GreenHerb, new BlueGreenHerb());
    }
}

public class BlueRedHerb: InventoryObject
{
    public BlueRedHerb()
    {
       _combinations.Add(GreenHerb, new GreyHerb());
    }
}

次に、呼び出しBlueHerb.Combine(myRedHerb);て結果を取得します。BlueHerb.Combine(myStone);また、簡単にデバッグすることもできます。

例をできるだけ単純に保つようにしています。コードを明るくするために、多くの変更を行うことができます (クラスHerb、クラスCombinedHerb、LINQ クエリの使用など...)。

于 2013-08-06T10:51:04.593 に答える