Unityの敵キャラクターが目的地に到達出来なければ違う場所を目的地にする

以前、敵キャラクターが最初に登場した位置からランダムな位置を歩き回る機能を作成しましたが、

Unityのゲームで作った敵キャラクターが見回りをするように、ランダムに設定した位置に移動させる機能を作成します。

CharacterControllerで敵キャラクターを動かす場合は、目的地とキャラクターとの間に壁があると壁にずっと衝突して移動出来なくなってしまいます。

そこで今回は敵キャラクターの前に壁等の特定のゲームオブジェクトがあってずっと衝突する可能性がある場合は敵キャラクターの目的地を変更するようにします。

そんなに複雑なAIというものでもなく単純に壁が前にあったら別の目的地を設定してちょっと頭良さげに見えるようにするという簡易的な方法になります。

かえって頭の悪い移動の仕方をする可能性も十分ありますけどね・・・・(^_^;)

今回の機能を作成すると、

上のような感じのものが出来上がります。

スポンサーリンク

Terrainで地面を作成する

まずは敵キャラクターが移動する地面をTerrainで作り、所々盛り上げて敵キャラクターより背の高い山を作ってください。

このキャラクターより高い山が前にあったら別の目的地に変更するようにします。

Terrainの使い方は

UnityのツールであるTerrainを使ってゲームに使用するフィールドを作成していきます。

を参照してください。

わたくしは

敵キャラクターが壁に突入するサンプルで使用するTerrain

上のような感じの地面を作りました。

地面が出来たらインスペクタのLayerでFieldを作成し、設定しておきます。

Terrainを使って障害物を作成せずとも普通のゲームオブジェクトを設置して、そのゲームオブジェクトのLayerをFieldにしても同じように出来ます。

敵キャラクターの作成

敵キャラクターにはCharacterControllerの取り付けとコライダの調整、AnimatorControllerの作成とAnimatorへの設定を行っておきます。

ここら辺は、

Unityのアニメーションの切り替えシステムであるAnimatorControllerの設定とスクリプトからアニメーションを制御していきます。

を参照してください。

AnimatorControllerのアニメーションパラメータには、Float型のWalkSpeedを作成し、Idle→Walkの条件はWalkSpeedがGreaterで0.1、Walk→Idleの条件はWalkSpeedがLessで0.1を設定しておきます。

敵キャラクターの子要素にCreate Emptyで空のゲームオブジェクトを作成し、名前をRayTransformとします。

トロールの子要素にレイを飛ばす位置を作成

RayTransformの位置と向きは

トロールの子要素のレイを飛ばす位置の向きを調整

上のようにします。

ここでRayTransformのLocalの向きが違うとうまくいきません。

敵キャラクターのスクリプト

今回作成する敵キャラクターのスクリプトでは最初に登場した位置から一定の範囲内でランダムな位置を取得し、そこを目的地に設定する事にします。

その為、最初に登場した位置から一定の距離の範囲内しか移動しません。

敵キャラクターにはTrollScriptという名前のスクリプトを作成し取り付けます。

スクリプト名は自由に変えてください。

スクリプトが長いので少しづつ解説します。

宣言部分

まずは宣言部分です。

TrollStateでは敵(トロール)の状態を宣言しています。

defaultPosはトロールが最初にいる位置を記憶しておきます。

trollStateはトロールの状態を保持します。

destinationはトロールの移動する目的地を保持します。

movementRangeはトロールが最初の位置から移動出来る距離を指定します。

walkSpeedは歩く速さ、rotateSpeedは目的地の方向に向く速さを指定します。

elapsedTimeOfIdleStateはIdle状態になってから経過した時間を入れます。

timeToStayInIdleはIdle状態になってから何秒経ったらnormal状態にするかを指定します。

rayTransformはトロールの前方に壁があるかどうかを調べる時にレイを飛ばす位置を設定します。

rayDistanceは壁を調べる時に飛ばす例の距離を指定します。

elapsedCollisionWall最初に壁を検知してからの経過時間を入れます。最初は必ず壁を検知させる為、Mathf.Infinityで最大値を入れておきます。

avoidanceTimeCollisionWallは最初に壁を検知してから次に検知出来るようにするまでの時間です。

Startメソッドではコンポーネントの取得とdefaultPosの設定、SetRandomDestinationPointメソッドを呼び出して目的地をランダムに設定します。

SetRandomDestinationPointメソッドはこの後作成します。

SetRandomDestinationPointメソッド

SetRandomDestinationPointメソッドはランダムに目的地を設定するメソッドです。

Random.insideUnitSphereでSphere(Vector3)のランダムな点(0~1の間)を取得出来ます。

それにmovementRangeをかけることでその範囲内のランダム値が得られます。

目的地は敵が最初にいた位置から一定の範囲内を移動出来るようにするので、最初に登場した位置 + ランダムな位置にします。

目的地が地面の位置になるように『求めた目的地の上10mの地点』から下向きのレイを求め(ray)、Fieldレイヤーが設定された地面と接触した位置(hit.point)を目的地に設定する事にします。

SetStateメソッド

SetStateメソッドでは引数で受け取った状態にします。

idle状態になった時は重力だけ働かせ、アニメーションパラメータのWalkSpeedを0にしてIdle状態に遷移させます。

さらに次の目的地をランダムに決定します。

Updateメソッド

Updateメソッドがメインの処理になります。

敵の状態trollStateがTrollState.idleの時は一定時間その場で待機した後TrollState.normalに変更します。

TrollState.normal状態の時は敵キャラクターを目的地の方向に徐々に向けさせ、移動させます。

目的地に十分近づいたらidle状態にします。

その後レイを視覚化していますが、これは設定したrayTransformの位置から前方にrayDistanceの距離だけのレイ、右斜め前のレイ、左斜め前のレイを視覚化しています。

また、レイを飛ばす位置から目的地までのレイも視覚化しています。

次のif文ではelapsedCollisionWallがavoidanceTimeCollisionWallの時間を超えている時で3方向に飛ばしたレイと接触していた時は前方に壁があって進めない為、idle状態にします。

飛ばすレイは前方と右斜め前、左斜め前のレイを飛ばしある程度の角度をカバー出来るようにしています。

elapsedCollisionWallは時間をどんどん足していくので、avoidanceTimeCollisionWallの値を超えたらavoidanceTimeCollisionWallの値を設定するようにしています。

これで完成です!

終わりに

今回の機能はCharacterControllerを使って敵キャラクターを動かす場合の壁への衝突問題を簡易的に解決する為の機能です。

簡易的なものなので、狭い場所に入ってしまうと永遠にその場所から出てこられない可能性もあります。

また一度壁を認識した場合は次の移動ですぐに壁を認識しないように回避する時間を設けている為、その間は壁に衝突し続けることになります。

敵キャラクターが移動する場所をあらかじめ設定しておいたり、移動する範囲を狭めておけばこの機能を取り付ける必要はないかもしれません。

もっと頭の良い移動をさせたい!

という場合はやはりナビゲーション機能を使うと便利ですね。(^^)/

Unityのナビゲーション機能を使って敵キャラクターを移動させます。ナビゲーション機能はあらかじめBakeされたフィールドを移動出来る機能です。
スポンサーリンク

記事をシェアして頂ける方はこちら

フォローして頂くとやる気が出ます