Unityのナビゲーション機能でOffMeshLinkを使って移動

Unityのナビゲーション機能については、すでにいくつか記事にしていて、ナビゲーション機能を使って
キャラクターを移動させたり、キャラクターの移動出来るエリアや移動コストの設定まで出来ました。

ナビゲーション機能やそれを使った移動方法に関しては以下の記事を参考にしてください。

Unityのナビゲーション機能を使って敵キャラクターを移動させます。ナビゲーション機能はあらかじめBakeされたフィールドを移動出来る機能です。
Unityでキャラクターはナビゲーション機能で移動させるが、移動先の指定はマウスクリックで行えるようにします。ナビゲーション機能を使っているので障害物を避けて最適な経路で目的地に進んでくれます。
Unityのナビゲーション機能でキャラクターが移動出来るエリアと移動出来ないエリアを作成します。また移動出来るエリアに移動コストを設定し移動コストが大きいエリアを回避して移動できるようにします

他のもいくつかナビゲーションに関する記事がありますので、カテゴリのナビゲーションから探してみてください。

スポンサーリンク

オフメッシュリンクとはなんぞや!?

今回はナビゲーションの中のナビゲーションオフメッシュリンクの機能を使ってみます。

エージェント(ナビゲーション機能で動くゲームオブジェクト)が移動出来る場所は
staticにしたゲームオブジェクトをBakeする事で作成しましたが、地続きでない場所へは行けませんでした。

また、Bakeのエージェントの設定によっては高い所へ移動も可能ですが、普通に考えて人型キャラクターが1mも2mも段差があるようなところをひょいと登ってしまうのは違和感があります。

なのでBakeの設定でStep Height(エージェントの移動出来る段差)は0.3(30cm)とかそんな値に設定するのが普通です。

そんな時はジャンプをして高い所や遠い所に到達させたいところです。

その為の機能がオフメッシュリンクで、オフメッシュリンクは地続きでない場所を移動したり、高い所から下りたりするような位置を繋ぐ機能です。

ナビゲーション機能を使った移動では地続きの場所をルートを探して移動しますが、高い段差から飛び降りる事や遠い所にある地面にジャンプして移動はしません。

そんな時にオフメッシュリンクを設定しておけば、ショートカットを使って移動出来るようになります。

ベイクする時に自動でオフメッシュリンクを生成する

さてこのオフメッシュリンクですが、実はBakeする時に自動で作成する事が出来ます。

オフメッシュリンク1

上のように地面にするゲームオブジェクトを選択して、Generate OffMeshLinksにチェックを入れておきます。

オフメッシュリンク2

Generated Off Mesh Linksで値を設定します。

Drop Heightはどのくらいの高さなら下りるオフメッシュリンクを作成するか
Jump Distanceはどのくらいの距離なら飛ぶオフメッシュリンクを作成するか

です。

今回の例であれば高さが5m以内、離れている距離が5m以内のところに自動でオフメッシュリンクが作成されます。
設定が終わったのでBakeしてみます。

オフメッシュリンク3

Navigationタブを表示した状態でSceneタブを見ると丸印と矢印が表示されます。

これが自動で作成されたオフメッシュリンクで片方向の矢印はそちらにしか移動出来ず(画面の例で言うと下りるだけの場所)
双方向に矢印があれば行き来が出来ます(画面の例で言うとエリアを横に飛ぶ場所)

自動生成したオフメッシュリンクの移動を確認する

それでは実際にキャラクターを動かしてオフメッシュリンクを使って移動出来るか確認してみます。

オフメッシュリンク5

上のように主人公に設定するNavMeshAgentコンポーネントでAuto Traverse Off Mesh Linkにチェックを入れてください。

Auto Traverse Off Mesh Linkにチェックを入れると移動中にオフメッシュリンクがあったら
自動でオフメッシュリンクを使い移動します。

チェックを外すとオフメッシュリンクの所で止まってしまいます。

オフメッシュリンク4

上がナビゲーション機能とマウスクリックで移動する機能を使ってオフメッシュリンクを移動した結果です。
オフメッシュリンクの部分に来ると自動で矢印が繋がった先に移動します。

ただ通常の移動と同じでジャンプするでもなくスーッと空中浮遊するようにしか移動できません。
ここはジャンプして斜め上に飛んでから着地してほしいところですね。

これに関しては後で対処してみます。

自分でオフメッシュリンクを作成する方法

さて、自動でオフメッシュリンクを作成したわけですが、自分で特定の位置を繋げて移動させたい場合もあります。

そんな時はオフメッシュリンクのコンポーネントがあるのでそれを取りつけて自分でオフメッシュリンクを作成する事が出来ます。

オフメッシュリンク6

まずは上のようにCubeでOffMeshLinkという名前にした障害物を作成します。

BakeでStep Heightを0.3にしているのでこの障害物には乗る事が出来ません(ルートが作成されていないはず)。

障害物の先をクリックして移動しようとすると、迂回して到達しようとします。

オフメッシュリンク7

OffMeshLinkゲームオブジェクトは上のようにstaticにチェックを入れてBake(全staticのゲームオブジェクトが再度Bakeされます)します。

自前のオフメッシュリンクオブジェクト

障害物(Block)があって移動出来ないのでその子要素にOffMeshLinkゲームオブジェクトをcreateEmptyで作成し、その子要素(子要素でなくてもOK)にLink1とLink2をcreateEmptyで作成し、障害物の両端に置きます。

次にOffMeshLinkゲームオブジェクトのAdd ComponentからNavigation→OffMeshLinkを追加します。

オフメッシュリンク9

StartとEndに先ほど作成したLink1とLink2を設定します。

Bi Directionalにチェックを入れると双方向の移動が可能となります。
Activatedにチェックを入れるとオフメッシュリンクを使用出来ます。

それでは設定が終了したので、自前のオフメッシュリンクが作用するかどうか確認してみます。

オフメッシュリンク10

見事にすり抜けました!!

さきほど自動でオフメッシュリンクを作成し移動させた時に空中浮遊して移動する違和感がありましたが、障害物を作成し自前のオフメッシュリンクを使って障害物を越えさせたい時は貫通してしまい全く使えません。

これは自前のオフメッシュリンクが原因ではなくオフメッシュリンクはスーッと始点から終点へと移動してしまうので、穴を飛び越えるような場合はまだ違和感で済みますが、障害物を飛び越える(見た目的に)事は出来ません。

そこでスクリプトを使って斜め上に移動してから下りる処理を加えなければいけません。

オフメッシュリンクをうまく飛び越えるスクリプトを作成する

オフメッシュリンクをうまく飛び越えるにはまずはオフメッシュリンクを自動で移動するにチェックを入れていたのを外します。

NavMeshAgentのAuto Traverse Off Mesh Linkのチェックです。

インスペクタでチェックを外してもいいんですが、今回はスクリプトで外すようにします。
自動でオフメッシュリンクを移動しないようになるとオフメッシュリンクのところで止まってしまいます。

(多少動きが変わりますがAuto Traverse Off Mesh Linkのチェックを外さなくても今回のスクリプトだと動作します)。

そうなったらスクリプトでキャラクターを移動させる処理を入れ、移動が完了したらオフメッシュリンク利用の終了を知らせなければいけません。

キャラクターの移動に関してはオフメッシュリンクの始点と終点のデータを使い移動させます。
ではキャラクターを移動させるスクリプトNavMoveに機能を追加&修正します。

Unity5.5バージョン以降でC#でスクリプトを組んでいる場合は

using UnityEngine.AI;

というusingディレクティブを入れておいた方がいいです。

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

Startメソッド

StartメソッドではAnimatorControllerのLinkJump状態に設定しているアニメーションクリップの名前で検索し、そのクリップの長さを取得しておきます。

ジャンプ中はこのアニメーションクリップの長さを使用します。

Updateメソッド

マウスクリックした位置に移動させるスクリプトは

Unityでキャラクターはナビゲーション機能で移動させるが、移動先の指定はマウスクリックで行えるようにします。ナビゲーション機能を使っているので障害物を避けて最適な経路で目的地に進んでくれます。

を参照してください。

agent.isOnOffMeshLinkプロパティはエージェントがオフメッシュリンク上にいるかどうかです。
オフメッシュリンク上にいれば到達点に向けて移動させるという処理を行います。

agent.currentOffMeshLinkDataプロパティはエージェントが現在使用しようとしているオフメッシュリンクのデータが入っています。

そこから始点と終点を取得し、

取得したオフメッシュリンクデータのlinkTypeプロパティでそのオフメッシュリンクのタイプを取得出来ます。

OffMeshLinkType.LinkTypeJumpAcrossは自動で作成した遠い地面(横にジャンプ等)に飛ぶオフメッシュリンク
OffMeshLinkType.LinkTypeDropDownは自動で作成した地面に降りるオフメッシュリンク
OffMeshLinkType.LinkTypeManualは自分で作成したオフメッシュリンク

になります。上2つのオフメッシュリンクはBakeした時に自動で作成した場合のもので、3つ目は自分で設置したものにつけられます。

今回の場合は遠い地面に飛ぶ場合と自前のオフメッシュリンクの時にジャンプするアニメーションに切り替えます。

地面に降りる時はその直前のアニメーションをそのまま使います。

isLinkJumpはオフメッシュリンクを使っている時にtrueにし、normalizedTimeはジャンプアニメーションの再生時間を入れます。

transform.LookAtで終点の方にキャラクターの方向を向けさせます。

Y軸はキャラクター自身の角度にし、傾けさせないようにします。

飛ぶ時に終点の方を向けさせなくてもいい場合は必要ありませんが、後ろ向きに飛ぶアニメーションをしてしまいます。

↑の処理ではnormalizedTimeにリンクジャンプをしている時間を足していきます。

その時間の比率をanimationTimeで計算しそれをアニメーションカーブのEvaluateに設定します。

アニメーションカーブについては後でやります。

アニメーションの再生が終わったらagent.CompleteOffMeshLinkを使ってオフメッシュリンクの使用が完了した事を知らせます。

Auto Traverse Off Mesh Linkのチェックをしていない場合、これを呼び出さないとオフメッシュリンクの利用が終わりません。

オフメッシュリンクの利用が終わったらアニメーションパラメータのLinkJumpをfalseにします。

最後にエージェントの位置をスタート位置からエンド位置に向け移動させますが、その時に計算したオフセット値を足しています。

agent.isOnOffMeshLinkがfalseになった時で、isLinkJumpがtrueの時はオフメッシュリンクの利用が終了したのにスクリプト上ではリンクジャンプしている時なので、

強制でリンクジャンプを終了させています。

この場合はアニメーションの再生が終わる前に強制で次の状態へと遷移します。

アニメーションカーブの作成

NavMoveスクリプトではインスペクタでAnimationCurveを設定出来るようにしてます。

このアニメーションカーブを使うとX軸とY軸のグラフを使ってX軸に対するY軸の値を視覚的に作成する事が出来ます。

NavMoveのインスペクタでは

NavMoveにAnimationCurve項目が表示される

↑のようにAnimationCurve項目が表示されます。

AnimationCurveの部分をクリックすると、

アニメーションカーブの作成

↑のようなグラフが表示されます。

グラフの途中で右クリックをするとキーを打つ事が出来るのでカーブの変化点を入れる事が出来ます。

X軸(スクリプトではアニメーションの経過時間)の値によってY軸の値(スクリプトではエージェントのY軸の位置)をグラフで設定します。

今回の場合はX軸は最大1でY軸は2にしています。

これでアニメーションの再生位置に応じてエージェントのY軸の位置が変換するようになります。

Evaluateメソッドの引数に渡しているのがX軸の値で、得られる結果がY軸の値になります。

アニメーターコントローラにオフメッシュリンクを飛ぶ状態と遷移の作成をする

スクリプトの追加と修正が終わったので最後にアニメーターコントローラで状態と遷移を作成します。

オフメッシュリンク13

上のようにLinkJump状態を作成します。アニメーションは好きなアニメーションを設定してください。

ただし、アニメーションクリップの名前をスクリプトで指定した名前と合わせます。

スクリプトではLinkJump4としたのでアニメーションクリップの名前もLinkJump4としておきます。

オフメッシュリンクジャンプのアニメーションクリップの名前を変更

↑のようにアニメーションクリップの元のファイルを選択し、インスペクタで名前をLinkJump4に変更し、このアニメーションを設定します。

Ilde→LinkJump、Run→LinkJumpの遷移を作りHas Exit Timeのチェックを外し、遷移条件をLinkJumpがtrueの時を加えます。

LinkJump→Runに遷移を繋げHas Exit Timeのチェックを外し、遷移条件をLinkJumpがfalseの時を加えます。

オフメッシュリンク14

上がLinkJump→Runへの遷移のインスペクタです。

最終的なオフメッシュリンクの移動を確認する

アニメータコントローラの作成も終わったので、Unityの実行ボタンを押して確認してみましょう。

オフメッシュリンク11

上の動画が障害物の所に作った自前のオフメッシュリンクを飛び越えるところです。
オフメッシュリンクの所にきたらジャンプして飛び越えているようになります。

オフメッシュリンク12

上が自動で作成されたオフメッシュリンクを移動する時の様子です。
遠い地面に飛ぶ時はジャンプアニメーション、ただ下りる時はその前のアニメーションのまま落ちていきます。

これでナビゲーション機能のオフメッシュリンクを使ってワープする事が出来るようになりました。

我ながらがんばってオフメッシュリンクの機能を使ったと思います。(^_^;)

スポンサーリンク

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

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