303.Rigidbodyコンポーネント

 Rigidbodyコンポーネント速度を管理するコンポーネントです。速度Velocityと呼ばれ、向きベクトルを持ったスピードです。
 単位は秒速です。
 Rigidbodyコンポーネントを実装するには、ゲームオブジェクトのOnCreate()関数などで
    //Rigidbodyをつける
    auto PtrRedid = AddComponent<Rigidbody>();
    PtrRedid->SetVelocity(Vec(0, 0, 1.0f));
 のように記述します。これでオブジェクトは秒速1.0fでZの方向に移動するようになります。
 動的に変化させる場合は、ゲームオブジェクトのOnUpdate()関数などで
    //Rigidbodyを呼び出す
    auto PtrRedid = GetComponent<Rigidbody>();
    PtrRedid->SetVelocity(Vec(0, 0, 1.0f));
 のように設定します。SetVelocity()関数に渡す値を動的に変更すれば、違う動きを演出できます。

ステアリング(操舵)

 さて、主にAIで操作するオブジェクトに関しては、前項のようにAction系で動かす方法もありますが、ステアリング(操舵)と呼ばれる方法があります。
 ステアリングニュートンの第2法則に基づきフォースを利用したAI動作です。
 まず、ニュートンの第2法則とはどんなものかを考えましょう。公式は以下です。
 M(質量) × A(加速) = F(フォース)
 というのがニュートンの第2法則です。これは
 A(加速) = F(フォース) / M(質量)
 とも書けます。これはどういうことかというと、加速(A)は、フォース(F)をM(質量)で割った値であるということです。フォースとは力のことです。
 静止している物体が動くことや動いている物体が止まるというのは必ず加速が発生します。動いている物体がそのまま同じ速度で動くのは慣性が働いているので、加速は加わりません。つまり、速度を変化させるのには加速が必要なのです。
 ステアリングというのはF(フォース)を発生させ、その力の向きに加速をつける方法です。

 では、具体的にはどのように計算するかですが、目標地点に向かうステアリングを考えてみましょう。
 以下の図はチュートリアル003でも紹介した図ですが

 

図0303a

 

 今、移動している物体がある目標に向かうために方向転換をするとします。
 すると、必要なベクトルは青い線で表されたベクトルです。物体が静止しているのであれば、単純にF(力)は目標の方向にかければいいのですが、現在も移動中で、速度を持ってます。そのため、現在の速度を考慮した方向に力をかけなければいけません。
 図を見ればわかるように、
現在のベクトル + 赤い線のベクトル = 青い線のベクトル
 という関係があります。ですので赤い線のベクトルを導くには
赤い線のベクトル = 青い線のベクトル - 現在のベクトル
 と引き算をしてあげればいいのです。ですので、以下は概念ですが
    //準備
    //目標地点までのベクトルを得る(正規化されていてよい)
    Vector Target = GetTarget();
    //最高秒速をかける
    Target *= GetMaxSpeed();
    //前回のターンからの時間(秒)
    float ElapsedTime = App::GetApp()->GetElapsedTime();
    //Rigidbodyを取り出す
    auto PtrRedit = GetComponent<Rigidbody>();
    //現在の速度を取り出す
    auto Velo = PtrRedit->GetVelocity();
    //目的地に向かうために力のかける方向を計算する
    //Forceはフォース(力)である
    auto Force = Target - Velo;
    //加速度を求める
    //GetMass()は質量を得る関数
    auto Accel = Force / GetMass();
    //ターン時間を掛けたものを速度に加算する
    Velo += (Accel * ElapsedTime);
    //速度を設定する
    PtrRedit->SetVelocity(Velo);
 上記の例で赤くなっているGetTarget()は目標までの正規化されたベクトルを得る関数GetMaxSpeed()は最高秒速を得る関数です。またGetMass()は物体の質量を得る関数です。こららはどこかに用意しておきます。
 このようなコードをOnUpdate()関数など、毎ターン実行されるように記述しておきます。
 そうすると目標地点が移動しても、常に目標を追いかけるAI動作を実装できます。また、このAI動作は目まぐるしく加速が変わるために、生きてるような動作を実装できます。追いかける速度を調整した場合は、GetMaxSpeed()が返す値を変えればいいのです。

ステアリング(操舵)行動

 ステアリングを実装するには、Rigidbodyコンポーネントを追加して、OnUpdate()関数などで上記のようなコードを記述すればいいのですが、いくつかのパターン化されたステアリング行動クラスとして用意されているので、それを使う方法もあります。
 チュートリアル006サンプルには、SeekObjectというプレイヤーを追いかけるオブジェクトがあり、これにSeekSteeringコンポーネントArriveSteering行動、そしてSeparationSteering行動という3つの行動でAI動作を実装しています。
 SeekObjectにおける実装はまずSeekObject::OnCreate()関数において
//初期化
void SeekObject::OnCreate() {
    //中略

    //操舵系のコンポーネントをつける場合はRigidbodyをつける
    auto PtrRegid = AddComponent<Rigidbody>();
    //Seek操舵
    auto PtrSeek = AddComponent<SeekSteering>();
    //Arrive操舵
    auto PtrArrive = AddComponent<ArriveSteering>();
    //Arriveは無効にしておく
    PtrArrive->SetUpdateActive(false);

    //オブジェクトのグループを得る
    auto Group = GetStage()->GetSharedObjectGroup(L"ObjectGroup");
    //グループに自分自身を追加
    Group->IntoGroup(GetThis<SeekObject>());
    //分離行動をつける
    AddComponent<SeparationSteering>(Group);

    //中略
}
 このように、3つのステアリングコンポーネントを実装しています。
 SeekSteering目標を追いかける操舵を発生させるコンポーネントで、ArriveSteering目標に到着する操舵です。この2つの違いは目標に近づいたときにブレーキをかけるかどうかです。発生する速度はSeekSteeringのほうが速いです。SeekSteeringは目標に到達しても、そのまま行き過ぎてしまいます。ですから、追いかける対象に近づいたら、ArriveSteeringに操舵を切り替える処理をしています。
 このオブジェクトはインスタンスは4つ作成されます。それらはすべて初期値はプレイヤーから離れている位置にいるので、最初はSeekSteeringのみ有効にしているのです。
 オブジェクトとプレイヤーの位置が近くなったときにSeekSteeringは無効になりArriveSteeringが有効になります。
 またSeparationSteering分離行動と呼ばれるステアリングで、このステアリングはお互いが離れる操舵を発生させます。SeekObjectは、4つにインスタンスが作成されますが、これらがすべてプレイヤーを追いかけると、次第に同じ軌道をとるようになります。なるべくお互いがぶつからないようにするためにこの操舵を加えています。
 ここでなるべくというのはステアリングを考えるのにヒントとなる表現です。ステアリングフォースを発生させ、現在の速度を変化させる(加速をかける)アルゴリズムです。ですから、現在の速度によってはステアリングがあまり効かない場合もあります。まあ、現実の自動車と同じですね。車は急に止まれないのは出ている速度が速い場合、ブレーキをかけても思うように止まれません。ステアリングはそうした現実の現象をアルゴリズム化したものです。

 ステアリングコンポーネントはすべて同じフォース変数を使います。つまりフォースは合成することが可能ということです。追いかけるというフォースとお互いが離れるというフォースを合成するには、単純にフォース同士を足し算します。
 このように、複数のステアリングコンポーネントを同居させて、最終的にはRigidbodyのVelocityを変更します。
 Basecrossにあらかじめ実装されているステアリング系コンポーネントは以下のものがあります。
コンポーネント名 用途 備考
SeekSteering 探索する(追いかける)  
ArriveSteering 到着する  
PursuitSteering 追跡 精度の高いSEEK
WanderSteering 徘徊  
WallAvoidanceSteering 壁回避  
ObstacleAvoidanceSteering 障害物回避  
FollowPathSteering 経路追従  
AlignmentSteering 整列 グループ操舵
CohesionSteering 結合 グループ操舵
SeparationSteering 分離 グループ操舵
SeparationSteering 分離 グループ操舵
 グループ操舵となっているのは分離行動のように、グループを指定する操舵です。また、操舵によってはパラメータを複数設定するものもあります。ソースコードのコメントも参照ください。
 またステアリングのアルゴリズムは実例で学ぶゲームAIプログラミング(オライリージャパン)を参考に、コンポーネント化しています。

ステアリング(操舵)コンポーネントを自作する

 さて、上記のようにいくつかのステアリングコンポーネントが用意されていますが、本当にゲームにぴったりくるステアリングを実現するには、コンポーネントを自作するのが良いでしょう。
 ステアリングの自作方法として、FullSample303を参考にしてください。Character.h/cppにあるMySeekSteeringコンポーネントは、Seekステアリングを自作する方法が記述されています。アルゴリズムはSeekSteeringと同じですが、計算方法を変えるといろんな表現ができると思います。