800行のコードで行動木(Behavior Tree)のライブラリを作る(3)

4741 ワード

転入先http://www.aisharing.com/archives/530
行動木の最後にお話しするのは、前提(Precondition)についてです.第1部では、少しお話ししましたが、今回は、前提の純虚基類の定義をよく見てみましょう.
 1: class BevNodePrecondition
 2: {
 3: public:
 4:     virtual bool ExternalCondition(const BevNodeInputParam& input) const = 0;
 5: };

各前提クラスには,この判断を実現する虚関数が必要である.私は『クラスで論理演算を表すC行為木の前提の一つの実現方式』で、私たちはクラスで論理演算を表すことができて、このような利点はモジュール化することができて、同じ判断条件は多重化することができて、だからライブラリの中で、私もこのような論理の表現方式を実現して、基本的な論理演算クラスを定義しました
 1: class BevNodePreconditionTRUE{};
 2: class BevNodePreconditionFALSE{};
 3: class BevNodePreconditionNOT{};
 4: class BevNodePreconditionAND{};
 5: class BevNodePreconditionOR{};
 6: class BevNodePreconditionXOR{};

これらのクラスの名前から明らかなように、これらのクラスの意味は、論理オペレータと同様に、いくつかのクラスの構造関数には2つのパラメータが必要であり、これによって2元の論理演算(AND,OR,XOR)を表し、一部は1つのパラメータだけが必要であり、これによって1元の論理演算(NOT)を表す.前提クラスは動作ツリーのノードにアタッチするために使用され(各ノードにアタッチ可能)、デフォルトでは、ノードに前提クラスがない、すなわち「外在前提」が存在せず、「内在前提」のみであり、これはBevNodePreconditionTRUE(Trueに永遠に戻る)がアタッチされた「外在前提」のノードと等価である.
さあ、行動ツリーライブラリの内容は基本的にこれらです.次に例プログラムを見てみましょう.ライブラリで動作ツリーを作成する方法を紹介します.例のコードはBevTreeTestというプロジェクトで、コンパイル後に直接実行できます.この例では、簡単から複雑まで、3つの動作ツリーをそれぞれ示しています.マウスをクリックすると、この3つの例を切り替えることができます.このプログラムは,「シーンマップ上では,タイミング的にターゲットポイントが生成され,スマートボディは動作ツリーの定義に基づいて異なる動作モードでターゲットポイントに移動する」という機能を実現している.
このプログラムでは、スマートボディの4つの動作を定義しました.
 1: class NOD_Idle{};      //  ,         
 2: class NOD_Breathe{};   //  ,          
 3: class NOD_MoveTo{};    //  ,       
 4: class NOD_FaceTo{};    //  ,      

さらに2つの「外在的前提」を定義しました.
 1: class CON_HasReachedTarget{};    //       
 2: class CON_HasFacedToTarget{};    //       

最初の例では、最初の例の動作ツリー図は次のようになります.
BevTreeTest1
これは簡単な動作ツリーで、ルートノードは優先度のある選択ノードなので、MoveToはIdleより優先度が高く、MoveToは「外在的前提」を持ち、「目標点に達していない」場合はMoveToでの動作を選択し、逆にIdleでの動作を選択します.
コードでは、この動作ツリーを定義できます.
 1: BevNode& ret =
 2:     BevNodeFactory::oCreatePrioritySelectorNode(NULL, "root");
 3:         BevNodeFactory::oCreateTeminalNode<NOD_MoveTo>(&ret, "move to")
 4:             .SetNodePrecondition(new BevNodePreconditionNOT(new CON_HasReachedTarget()));
 5:         BevNodeFactory::oCreateTeminalNode<NOD_Idle>(&ret, "idle")
 6:             .SetNodePrecondition(new BevNodePreconditionTRUE());
 7: m_BevTreeRoot = &ret;

関連ノードの作成を支援するために、ライブラリにいくつかのファクトリメソッドを定義しました.ここでは,クラスで論理を表す使い方を実証した.私は動作ツリーを定義するときに、対応する親子構造をいくつかのフォーマットのインデントで表します.これは視覚的に明らかにするためだけです.もちろん、後で動作ツリーの定義インタフェースを改善したり、データファイルで動作ツリーを定義したりすることができます.
定義が完了すると、動作ツリーで動作を決定できます.コードはかなり簡単です.
 1: BevNodeInputParam input(&m_BevTreeInputData);
 2: BevNodeOutputParam output(&m_BevTreeOutputdata);
 3: if(m_BevTreeRoot->Evaluate(input))
 4: {
 5:     m_BevTreeRoot->Tick(input, output);
 6: }

例では、スマートボディの情報を直接修正するのではなく、BevNodeOutputParam構造に出力する変数をできるだけ書きます.このようなメリットは、動作ツリーの入力と出力のインタフェースをかなり明確にし、ブラックボックスを作ることができ、ここでの議論を参考にすることができます.
2つ目の例ではパラレルノードの使い方を示し,3つ目の例ではシーケンスノードの使い方を示したが,あまり話さず,コードを自分で見ることができる.
すべてのコードは以下の方法で入手できます.
ダウンロード先:
GoogleCodeダウンロードポイント(exeフォルダに実行可能ファイルが含まれています)
svnは、次のアドレスで取得することもできます.
http://tsiu.googlecode.com/svn/branches/blogver/
コンパイル方法:
VS 2005以上で開く、Debug NoDxまたはRelease NoDxを選択し、コンパイル後、BevTreeTestを実行する.
関連コード:
TAI_BevTree.h
TAI_BevTree.cpp
TsiUについて
TsiUは私がずっとメンテナンスしている小型のフレームワークです.私が普段作っているAIのsampleやツールは、このフレームワークに基づいています.TsiUには基本的なUIコントロールライブラリ、ネットワークモジュールライブラリ、GDIグラフィックスモジュール、D 3 Dグラフィックスモジュールなどがあります.小型のサンプルプログラムを迅速に作成することができます.便利(具体的にはSampleAppsの例プログラムを参照できます)、アーキテクチャ全体がObjectで組織されており、理解しやすく拡張しやすいです.全体のフレームワークはとても軽量化して、基本的にいくつかの下層の基本的な機能をして、このように私はふだんものをする時、下層を書き直す必要がなくて、精力を上層部の実現に置きました.後でコードを共有するのはすべてこのフレームワークに基づいて、みんなもsvnを通じていつでもupdateを私の最新の変更に変えることができます.下の図はTsiUのいくつかの工事の紹介で、コードは多くなくて、みんなが見たいのも自分で見ることができます:)