Unityのナビゲーションのオフメッシュリンクの移動速度と落下速度を制御

今回はナビゲーション機能のナビメッシュリンクやオフメッシュリンクを使って移動する時の移動速度を制御してみたいと思います。

制御なんて言ってますが難しいことは出来ないので出来る事だけをやります。

ナビゲーション機能のオフメッシュリンクについては

Unityのナビゲーション機能でキャラクターを動かす時にオフメッシュリンクを使うと地続きでない場所に移動する事が出来るようになります。

の記事で詳しくやりましたが、↑の記事ではアニメーションカーブ等を使ったりオフメッシュリンク移動時に専用のアニメーション再生をしたりしてオフメッシュリンクの移動をさせていました。

ナビゲーションエージェントの設定でAuto Traverse Off Mesh Linkにチェックを入れていればオフメッシュリンクの位置に来るとStartからEnd位置まで自動で移動します。

しかし、その移動速度はエージェントが勝手に判断しオフメッシュリンクのStartからEndまで移動させる為、通常の移動よりも速いスピードで移動してしまいます。

また高い所から地面に下りるオフメッシュリンクを使う場合も平面を移動する時と同じように同一スピードで落下していきます。

通常であればキャラクターに重力がかかり段々と落下スピードが加速するはずです。

ナビメッシュを

通常のオフメッシュリンクの移動用のナビメッシュ

↑のような感じで行った場合に通常の移動と今回の機能を取り付けた移動を確認してみます。

地面の間は自分でナビメッシュリンクでリンクし、高い所から落下する部分はNavigationウインドウの自動オフメッシュリンクで生成されたものです。

単純なナビメッシュリンクやオフメッシュリンクを使った移動は、

↑のような感じで平面を繋いだ所(ナビメッシュリンクを使用)で辺にスピードアップした移動になり、高い所から落下する時(オフメッシュリンクの自動生成)のスピードが平面を移動する時と同じように一定速度で落下しています。

これに今回の機能を取り付けると、

↑のような感じで平面移動ではスピードが上がり過ぎず、落下時は重力値を計算して落下するようになります。

スポンサーリンク

サンプルの作成

サンプルを作成していきます。

移動出来る地面を作成

移動できる地面は先ほど紹介した動画と同じ物を作成します。

ヒエラルキー上にPlaneを2つ作成し、地面を少し離します。

Planeのインスペクタの名前の横のStaticにチェックを入れます。

作成した地面のゲームオブジェクトのStaticにチェックを入れる

次に片方のPlaneの子要素にCubeを作成し、Scaleを調整して坂を作成し、インスペクタの名前の横のStaticにチェックを入れます。

オフメッシュリンク用の地面の階層

Cubeで作った坂は

オフメッシュリンクのサンプル用に高い所を作成

↑のようになります。

2つのPlane、CubuのレイヤーにはFieldレイヤーを作成し、設定しておきます。

UnityメニューのWindowからNavigationを選択しNavigationウインドウを開きます。

まずはNavigationウインドウでAgentタブを選択し、設定をします。

Agentの設定

Agent TypesでHumanoidを選択し、↑のような感じに設定しました。

次にBakeタブを選択し、ベイクの設定をします。

NavigationのBakeの設定

Generated Off Mesh LinksのDrop Heightの数値を上げ、高い所から落下するオフメッシュリンクが生成されるようにしておきます。

デフォルトの状態であればNavigationウインドウのObjectタブのGenerate OffMeshLinksのチェックが入っているので自動でオフメッシュリンクが生成されるようになっています。

最後にBakeボタンを押してナビメッシュのベイクをします。

通常のオフメッシュリンクの移動用のナビメッシュ

↑のようにナビメッシュベイクがされます。

操作キャラクターの作成

移動する地面の作成とナビメッシュのベイクが終わったので、次はナビメッシュ上を動くキャラクターを作成します。

キャラクターにはIdle状態とWalk状態を作成し、アニメーションパラメータのSpeedの値で相互に状態が遷移するようにしたAnimatorControllerを作成し取り付けます。

またAdd ComponentからNavigation→NavMeshAgentを取り付けます。

Agent TypeをHumanoidにし、Auto Traverse Off Mesh Linkのチェックを外しておきます。

Speed等を変更しエージェントの最大移動速度の変更等を行います。

オフメッシュリンク移動サンプルのキャラクターの設定

このキャラクターにはRigidbodyとCapsuleColliderを取り付けていますが、今回の機能では使っていません。

キャラクターにはMoveOffmeshLinkCharaスクリプトを作成し、取り付けます。

平坦なナビメッシュリンクやオフメッシュリンクの移動機能

まずは平たんなナビメッシュリンクやオフメッシュリンクを通常のナビメッシュエリアの移動と同じようなスピードで移動出来るようにしていきます。

概要

平坦なナビメッシュリンクやオフメッシュリンクの移動は自前の物でも落下が絡まないのでそのまま一定速度で移動させるようにするだけです。

NavMeshAgentのAuto Traverse Off Mesh Linkのチェックを外したので、オフメッシュリンクの位置にキャラクターが来るとその場で移動しなくなります。

その為、オフメッシュリンクを使用する場合は自分でオフメッシュリンクのend位置まで移動させてあげる必要があります。

その為にオフメッシュリンクを今使用しているかどうか調べ、使用しているのであればオフメッシュリンクのデータを取得し、それを元にキャラクターの位置を変更します。

ナビゲーション機能を使った移動の詳細は

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

の記事を参照してください。

Fieldレイヤーを設定した地面をマウスクリックしたらそこにキャラクターが移動します。

オフメッシュリンクを使っている時の移動スピードはoffmeshLinkSpeed、回転スピードはoffmeshLinkRotateSpeedとして作成しており、StartメソッドでNavMeshAgentの最高速度であるagent.speedと最大回転速度であるagent.angularSpeedを設定しています。

こうする事で通常の移動や回転の最大値以上の速さでオフメッシュリンクを移動する事がなくなります。

エージェントがナビメッシュリンクやオフメッシュリンクを使っているかどうかはNavMeshAgentの参照をagentに入れている場合

で調べられます。

使用している時は最初にオフメッシュリンクのデータを取得します。

現在のオフメッシュリンクのデータは

で得られるので、そこからオフメッシュリンクのend位置を取得し、そこからend位置の方向を計算します。

キャラクターの回転や位置はRotateTowardsやMoveTowardsを使って徐々に変更しています。

その際のスピードを先ほどのoffmeshLinkRotateSpeedやoffmeshLinkSpeedを使います。

キャラクターの位置がendPosとかなり近くなったら

を使ってオフメッシュリンクの利用の終了を伝えます。

平坦なナビメッシュリンク、オフメッシュリンクの移動はこれで一定速度で移動するようになりました。

高い所から落下するオフメッシュリンクの移動

次はナビメッシュをベイクした時に自動で生成した高い所から降りるオフメッシュリンクの移動処理を作成します。

自動で作成された落下するオフメッシュリンクのオフメッシュリンクタイプは

OffMeshLinkType.LinkTypeDropDown

なので、その時だけ重力値を計算したY座標の値を計算する事にします。

先ほどのスクリプトにフィールドを追加します。

offMeshLinkDataはオフメッシュリンクのデータを入れます。

rayPositionは地面と接触したか判断するレイを飛ばす位置。

gravityYは重力値を入れます。

次にオフメッシュリンクを使っている時の処理を変更します。

オフメッシュリンク使用時の初期設定でoffMeshLinkDataを取得します。

キャラクターの位置を計算している部分で、オフメッシュリンクタイプが落下タイプかどうか判断し、落下タイプであればX軸とZ軸だけMoveTowardsで一定速度で移動するように計算します。

Y軸は重力を計算したいのでgravityYに重力加速度を足していきます。

Physics.Linecastを使ってrayPositionからレイを1m下に飛ばし、Fieldレイヤーがあればその接触位置のY座標をキャラクターのY座標にします(XZは先ほど計算した値)。

地面に接触していなければ現在のY座標の位置に重力値を足した位置にY座標を設定します。

オフメッシュリンクタイプが落下タイプじゃなければ平坦な時と同じ処理を行います。

オフメッシュリンクの使用が終わったらgravityYの値を0に初期化しています。

これで機能が完成しました。

出来上がりは記事の最初に示した動画となっておりますので、再度確認してみてください。

今回の機能の制限

今回の機能を搭載しても落下のスピードの制御に関しては地面のゲームオブジェクトをStaticにし通常のNavMeshをベイクする時に自動でオフメッシュリンクを生成した時だけしか使えません。

その理由は自分で作成したオフメッシュリンクのタイプが全てOffMeshLinkType.Manualになってしまうからです。

今回の機能の落下の判断はオフメッシュリンクのタイプがOffMeshLinkType.LinkTypeDropDownである時だけ処理分けして移動させるので、自身で作ったオフメッシュリンクを使うときは別の判断で落下の移動かどうかを判断する必要がありそうです。

自分で作成したナビメッシュリンクとオフメッシュリンクに対応する

自分で作成したナビメッシュリンクやオフメッシュリンクでも同じように移動速度や落下速度を操作してみます。

オフメッシュリンクを使っている条件の部分以下を次のように修正します。

Fieldレイヤーを設定したゲームオブジェクトにレイが接触している時は通常の移動。

それ以外の時は地面に接地していないとして重力値を計算して移動させるようにします。

これで対応終了です。(^^)/

ちょっと変えただけでしたね・・・・(^_^;)

↑のようになりました。

地面の途中から落下してますが、これはナビメッシュのベイクが地面の端までないのと地面を確認するレイが腰の辺りから飛ばしている為です。

足元辺りから飛ばすと大丈夫そうですが、その場合は地面を検知出来ずに地面をすり抜ける可能性もあるかも?

終わりに

ナビメッシュリンクやオフメッシュリンクの移動速度に違和感がなくなればさらにナビゲーション機能を積極的に使えますね。

ただ、たまに地面をすり抜けて落下してしまう事がありました。

レイの距離が関係してるのかも?(謎)

あ・・・・ジャンプアップの場合を考慮していなかった・・・・ジャンプアップのオフメッシュリンクはスタート位置とエンド位置の高さの違いで調べて記事の最初にリンクしてある処理でやるといいのかも。

スポンサーリンク

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

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