ナビゲーション・メッシュを追加する
ナビゲーション・メッシュは、ポイント・アンド・クリックのタッチ入力を使って、キャラクター( エージェント)がARシーンをナビゲートすることを可能にする。
前提条件
Lightship ARとLightship Meshingを有効にしたUnityプロジェクト が必要です。 詳細については、 ARDK 3.0 のインストール と How to Mesh: Adding Physics(メッシュの操作方法: 物理演算の追加) を参照してください。
また、Unity GameObject
と AR Mesh Manager および Lightship Meshing Extension コンポネントが必要です。 詳しくは、 メッシュの作成のセクション1の手順に従ってください。
このチュートリアルを始める前に、この画像のようにシーンでメッシュが生成されていることを確認してください。 確認できたら、プレハブの シェーダー を変更してメッシュを不可視にし、このガイドに従ってナビゲーションの追加を開始します。
Navigation Mesh Managerの追加
LightshipNavMeshManager
を追加する:
- 空の
GameObject
を作成する。- Hierarchyで、シーンのルートを選択します。
- メインメニューから、 GameObject を選択し、次に Create Empty を選択します。
- NavMeshManager という名前を付けます。
- NavMeshManager オブジェクトに
LightshipNavMeshManager
コンポーネントを追加します。- Inspector ウィンドウで、 Add Componentをクリックします。
- 検索窓に「LightshipNavMeshManager」と入力し、選択します。
- コンポーネントに Main Camera を追加します。 ここを起点に、マネージャーでメッシュ上で有効なパスをスキャンします。
- LightshipNavMesh を表示する場合は、 NavMeshManager に
LightshipNavMeshRenderer
コンポーネントも追加します。 これにより、カメラが動くと LightshipNavMesh が画面上にレンダリングされます。- Inspector ウィンドウで、 Add Component を再度クリックします。
- 今回は、代わりに "LightshipNavMeshRenderer "を検索して選択します。
LightshipNavMeshManager
をコンポーネントに追加します。- ナビゲーション・メッシュのレンダリングに使用するマテリアルを作成し、それをコンポーネントに追加します。
NavMesh サンプルプロジェクトの LightshipNavMeshManager
プレハブを追加することもできます。 詳細については、 サンプルプロジェクト をご覧ください。
これで、エディターで「Play」ボタンを押すと、タイルのグリッドが生成されるようになりました。 次に、ナビゲーションメッシュ上を移動できるエージェントを追加します。
LightshipNavMeshManager
の Scan Range
の値を上げることで、カメラ周辺に広範囲のタイルのグリッドを作成できます。
LightshipNavMeshへのエージェントの追加
LightshipNavMesh をテストするには、その上を動き回る Agent をシーンに追加する必要があります。 Gameboardサンプルプロジェクトには、テストに使えるAgentプレハブが含まれていますが、代わりに自分で作成することもできます。
Agent プレハブを作成します:
- Agent として動作するオブジェクトをシーンに追加するには、次の手順を行います。
- Hierarchyで、シーンのルートを選択します。
- 右クリックして Create Empty を選択し、 新しい空のオブジェクトに
TestAgent
と名前を付けます。
LightshipNavMeshAgent
コンポーネントを新しい Agentに追加する。- Hierarchyで、
TestAgent
を選択します。 - Inspector ウィンドウで、 Add Componentをクリックします。 「LightshipNavMeshAgent」を検索し、選択してコンポーネントを追加します。
- Hierarchyで、
LightshipNavMeshAgentPathRenderer
コンポーネントを追加して、 Agent がシーン内で通ることができるパスを表示します。- Inspector ウィンドウで、 Add Componentをクリックし、"LightshipNavMeshAgentPathRenderer" を検索して選択し、コンポーネントを追加します。
LightshipNavMeshAgent
と Material プロパティを設定します。
- Agent を表すキューブを追加する手順は以下のとおりです。
- Hierarchy で
TestAgent
を右クリックし、 3D Object にカーソルを合わせます。 この例では、 Cube を選択して、基本キューブをテスト Agentとして追加します。 - インスペクタの変形ウィンドウで、立方体のスケールを(0.2, 0.2, 0.2)に設定して縮小します。
- キューブの底が (0, 0, 0) になるように、キューブの位置を (0, 0.1, 0) に変更します。
- Box Collider の横にあるボックスのチェックを外して無効にします。 これにより、キューブエージェントが生成されたメッシュと衝突するのを防ぐことができます。
- Hierarchy で
- Agent を Assets ウィンドウにドラッグしてプレハブにし、シーンから削除します。
エージェントを制御するスクリプトを作成する
Agentにコントロールスクリプトを追加するには:
- ユーザー入力を管理してエージェントを制御するためのスクリプト Asset を作成します。
- Assets ウィンドウの空いているスペースを右クリックし、 Create にカーソルを合わせ、 C#スクリプト を選択します。
- 新しいスクリプトに
NavMeshHowTo
という名前をつけます。
- コードエディターでスクリプトを開きます。
- 以下の手順で、タップ入力を処理するコードを設定します。
- 「HandleTouch」というプライベートメソッドを作成します。
- エディターでは、「Input.MouseDown」を使用してマウスクリックを検出します。
- スマートフォンでは、「Input.GetTouch」を使用してタップを検出します。
private void HandleTouch()
{
// エディターではマウスクリック、スマートフォンではタップを使用
#if UNITY_EDITOR
if (Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1) || Input.GetMouseButtonDown(2))
#else
//タップがない場合、またはタップでUI要素が選択されている場合
if (Input.touchCount <= 0)
return;
var touch = Input.GetTouch(0);
// タップが始まった瞬間のみカウント
if (touch.phase == UnityEngine.TouchPhase.Began)
#endif
{
// タップで何かのアクションを行う
}
} - 画面のタップポイントを3D座標に変換します。
-
スクリプトの先頭にCameraフィールドを追加します。
[SerializeField]
private Camera _camera;[SerializeField]
を使用すると、プライベートプロパティをInspectorウィンドウに表示できるようになります。
-
:::
-
Unityの
Camera.ScreenPointToRay
関数を使用します。 「HandleTouch」メソッド内でカメラからのレイを作成します。#if UNITY_EDITOR
Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
#else
Ray ray = _camera.ScreenPointToRay(touch.position);
#endif -
「Physics.Raycast」を使ってレイがメッシュに当たるかどうかをチェックし、結果のポイントを取得します。
{
// タップで何かの処理を行う
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
// 3Dポイントを使ってエージェントを誘導
}
} -
タップで取得した3Dポイントを使用してエージェントを誘導する
- 先ほど作成したプレハブからエージェントをインスタンス化します。
- エージェントプレハブ向けに、クラスの上部に
LightshipNavMeshAgent
フィールドを追加します。[SerializeField]
private LightshipNavMeshAgent _agentPrefab; - エージェントのインスタンスとして使用するプライベートの
LightshipNavMeshAgent
フィールドをエージェントプレハブの下に追加します。private LightshipNavMeshAgent _agentInstance;
- エージェントインスタンスは、シーン内でエージェントプレハブから生成された特定のオブジェクトです。 このプレハブはインスタンスを作成するための設計図として使用されます。
- エージェントがまだ存在しない場合は、ヒットポイントで作成します。 存在する場合は、
NavMesh
上での新しい目的地をヒットポイントに設定します。// タップで何かの処理を行う
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
// 3Dポイントを使ってエージェントを誘導
if (_creature == null )
{
_creature = Instantiate(_agentPrefab);
_creature.transform.position = hit.point;
}
else
{
_agent.SetDestination(hit.point);
}
}
-
スクリプトでタッチの有無がフレームごとにチェックされるように、「HandleTouch」メソッドをUpdateメソッドに追加します。
void Update()
{
HandleTouch();
} -
スクリプトを NavMeshManager にアタッチします。
- Hierarchyで NavMeshManager GameObjectを選択し、 Inspector ウィンドウで「Add Component」をクリックします。
- NavMeshHowTo "を検索し、それを選択してコントローラスクリプトをプレハブに追加します。
- Camera と Agent Prefab のプロパティを設定してください。
-
これで、キューブをスポーンさせて ナビゲーション・メッシュ 上の任意のタイルに向けることができるようになりました。
-
NavMesh ビジュアルをオプションにして見た目をきれいにしましょう。
NavMeshHowTo
スクリプトで次の手順を実行します。LightshipNavMeshManager
にフィールドを追加して、レンダラーコンポーネントへの参照を取得します。[SerializeField]
private LightshipNavMeshManager _navmeshManager;- NavMeshRenderer コンポーネントを取得して、そのステートを設定する「 SetVisualization」という新しいメソッドを作成します。
public void SetVisualisation(bool isVisualizationOn)
{
//navmeshのレンダリングをオフにする
_navmeshManager.GetComponent<LightshipNavMeshRenderer>().enabled = isVisualizationOn;
if (_agentInstance != null)
{
//エージェントのパスレンダリングをオフにする
_agentInstance.GetComponent<LightshipNavMeshAgentPathRenderer>().enabled = isVisualizationOn;
}
} - UIボタンやスクリプトから、このメソッドを呼び出します。
クリックして最終的なNavMeshHowToスクリプトを表示
using UnityEngine;
using Niantic.Lightship.AR.NavigationMesh;
/// 概要:
/// LightshipNavMeshSample
/// このサンプルは、LightshipNavMeshを使って、ユーザー主導のポイントとクリックナビゲーションを追加する方法を示します。
/// 画面を最初にタッチすると、エージェントのプレハブが配置されます。
/// 場所をタップすると、エージェントはその場所に移動します。
/// トグルボタンは、ナビゲーション・メッシュとパスの表示/非表示を切り替えます。
/// _agentPrefabにLightshipNavMeshAgentがあると仮定します。
/// 独自のエージェント・タイプを書いている場合は、それを入れ替えるか、継承します。
///
public class NavMeshHowTo : MonoBehaviour
{
[SerializeField]
private Camera _camera;
[SerializeField]
private LightshipNavMeshManager _navmeshManager;
[SerializeField]
private LightshipNavMeshAgent _agentPrefab;
private LightshipNavMeshAgent _agentInstance;
void Update()
{
HandleTouch();
}
public void SetVisualization(bool isVisualizationOn)
{
//navmeshのレンダリングを無効にする
_navmeshManager.GetComponent<LightshipNavMeshRenderer>().enabled = isVisualizationOn;
if (_agentInstance != null)
{
//アクティブなエージェントのパスレンダリングを無効にする
_agentInstance.GetComponent<LightshipNavMeshAgentPathRenderer>().enabled = isVisualizationOn;
}
}
private void HandleTouch()
{
//エディターではマウスクリック、スマートフォンではタップを使用
#if UNITY_EDITOR
if (Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1) || Input.GetMouseButtonDown(2))
#else
var touch = Input.GetTouch(0);
//タップがない場合、またはタップでUI要素が選択されている場合
if (Input.touchCount <= 0)
return;
if (touch.phase == UnityEngine.TouchPhase.Began)
#endif
{
#if UNITY_EDITOR
Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
#else
Ray ray = _camera.ScreenPointToRay(touch.position);
#endif
//スクリーン空間のタップした場所を3D空間に投影し、その位置をエージェントの目的地として設定
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if (_agentInstance == null )
{
_agentInstance = Instantiate(_agentPrefab);
_agentInstance.transform.position = hit.point;
}
else
{
_agentInstance.SetDestination(hit.point);
}
}
}
}
}