Unityでの開発において、車を扱うアプリで指定したルート上でイベント処理を行う -Vol.1

プログラマーの大角です。Unityで車を扱ったOculus Rift用のVRアプリ開発を行った際の実装の一部をご説明させて頂きます。

# 概要
車を扱う際に様々な機能が有るかと思いますが、今回は決められたルートを走る車が指定したポイントに来た時に様々なイベント処理をする為にルート内での車の位置を把握する部分について説明します。

# 前提
まずは決められたルートを車が走るようにする為に使用するのはUnityStandardAssetsのWaypointProgressTrackerを使用します。WaypointProgressTrackerはWaypointCircuitとセットで使用しますが、この2つのクラスの詳細は割愛させて頂きます。

# 実装工程（１）

実装の準備としまして、WaypointProgressTrackerから取得したい値はcircuitとprogressStyleになりますのでスコープ変更する際にプロパティを定義します。

```csharp:WaypointProgressTracker.cs
　　　　　// A reference to the waypoint-based route we should follow
        [SerializeField] private WaypointCircuit circuit;
        protected WaypointCircuit Circuit { get { return circuit; } }

　　　　　// whether to update the position smoothly along the route (good for curved paths) or just when we reach each waypoint.
        [SerializeField] private ProgressStyle progressStyle = ProgressStyle.SmoothAlongRoute;
        protected ProgressStyle ProgressStyleProperty { get { return progressStyle; } }
```
# 実装工程（２）
WaypointProgressTrackerを継承したWayPointProgressTrackerAuxiliaryForMainCarを作成します。
指定したポイントに来た時に様々なイベント処理をする為にはWaypointProgressTracker内で処理されている値を取得する必要が有ります。

その値はルートのポイントの進行を管理しているprogressNumになります。

WayPointProgressTrackerAuxiliaryForMainCar内にprogressNumの替わりとなるProgressNumForMainCarを定義し、進行に合わせて値の整合性を合わせる為に記述したものが下記になります。

```csharp:WayPointProgressTrackerAuxiliaryForMainCar.cs
using UnityEngine;
using UnityStandardAssets.Utility;

namespace Common {

    /// <summary>
    /// WaypointProgressTrackerの補助機能
    /// 
    /// Autor 大角
    /// </summary>
    public class WayPointProgressTrackerAuxiliaryForMainCar : WaypointProgressTracker {

        /// <summary> ルートのポイントの更新判定専用のターゲットポジション </summary>
        Vector3 m_targetPositionForProgressCountUp;

        /// <summary> プレイヤーの車 </summary>
        [SerializeField] Transform m_car = null;

        /// <summary>スタート時に設定するWaypoint.nullの時は初期位置からスタート</summary>
        [SerializeField] GameObject m_startWayPoint = null;

        /// <summary> メインカー専用でルートの進行管理 </summary>
        public static int ProgressNumForMainCar { get; private set; }

        protected override void Start () {
            base.Start ();
            m_targetPositionForProgressCountUp = target.position;
            ProgressNumForMainCar = 0; // SetInitCarPositionAndTargetより前にリセット
            SetInitCarPositionAndTarget ();
        }

        protected override void Update () {
            base.Update ();
            UpdatePointProgress ();
        }

        /// <summary>
        /// SmoothAlongRouteの時にProgressNumを更新
        /// </summary>
        void UpdatePointProgress () {
            if (ProgressStyleProperty == ProgressStyle.PointToPoint) {
                return;
            }

            Vector3 targetDelta = m_targetPositionForProgressCountUp - transform.position;
            const float POINT_TO_POINT_THRESHOLD = 8f;

            if (targetDelta.magnitude < POINT_TO_POINT_THRESHOLD) {
                ProgressNumForMainCar = (ProgressNumForMainCar + 1) % Circuit.Waypoints.Length;
            }

            m_targetPositionForProgressCountUp = Circuit.Waypoints[ProgressNumForMainCar].position;
        }

        /// <summary>
        /// 車の初期位置とTargetの初期値を設定
        /// </summary>
        void SetInitCarPositionAndTarget() {
            int wayPointIndex = 0;
            if (m_car != null &&
                m_startWayPoint != null) {
                foreach (Transform transform in Circuit.Waypoints) {
                    if (m_startWayPoint.name == transform.name) {
                        // 車のスタート位置
                        m_car.position = m_startWayPoint.transform.position;

                        // 車の向き
                        int nextWayPointIndex = wayPointIndex + 1;
                        if (nextWayPointIndex < Circuit.Waypoints.Length) {
                            m_car.LookAt(Circuit.Waypoints[nextWayPointIndex]);
                        }
                        break;
                    }

                    wayPointIndex++;
                }
            }

            // スタート時の車の位置
            ProgressDistance = Circuit.Distances[wayPointIndex];
            ProgressNumForMainCar = wayPointIndex;
        }
    }
}

```

# あとがき
今回はルート上の何処を走っているかを取得する部分に焦点を当てました、ルート上のポイントとアプリ内の進行との紐付けに関する実装は後日記述したいと思います。

最後まで見て頂き有難う御座いました。