はじめに
Unityで現実世界の地図を表示するにはGoogleMapを使うのが便利です
大規模に使用しない限りは無料で使用できますが、登録のためにクレジットカードが必要になりますので、
必ず、用意しておきましょう
もくじ
Google Maps Platformの登録
GoogleMapを使用するために必要です
こちらよりアクセスして、「使ってみる」をおします
マップ、ルート、プレイスの全てにチェックを入れて、続行をおします
Create New Projectをおし、NEXTをおします
この後に、カードの情報を登録するように言われるので、登録しましょう
登録を既にしている場合は、画像のようになるので、「アカウントを設定」をおします
「次へ」をおします
Your API Keyに表示されてる文字がAPIキーになります
こちらは後で使うので、メモ帳とかにコピペしておき、Doneをおします
APIキーの保護を行う場合には、「認証情報を保護」をおします
APIキーが分からなくなったら、認証情報をおせば確認できます
ここまでできたらUnityを開きます
Unityでの操作
画面の比率の設定
※GoogleMapの表示はスマホで行うため、画面比率を設定する必要があります
左下のFreeAspectをおし、16:9を選択します
緯度・経度を表示するTextの作成
こちらは緯度・経度それぞれ使うのでTextは2つ作成します
文字の作成方法や設定についてはこちらを参考にしてください
Canvasの設定
Canvasを選択し、UI Scale ModeをScale With Screen Sizeにします
これによって文字の表示が変になった場合、文字の設定をキレイに見えるように、位置や大きさを調整してください
CanvasのReferenceResolutionのxを1600、yを900にします
※画面の比率に合わせています
GoogleMapを表示するオブジェクトを出す
Create → 3DObject → Planeを選択します
Planeを選択し、Rotationのxを90、yを⁻270、zを-90にします
スクリプトの作成
以下2つのスクリプトを作成します
スクリプトの作成についてはこちらを参考に作成してください
また、スクリプトの内容についてはこちらを拝借させて頂きました
ありがとうございます
緯度・経度を表示するスクリプト
using System; using UnityEngine; using UnityEngine.UI; public class ShowGPS : MonoBehaviour { public GameObject LatitudeText = null;// 緯度を表示するための文字 public GameObject LongitudeText = null;// 経度を表示するための文字 // Start is called before the first frame update void Start() { Input.location.Start();// GPS機能の利用開始 } // Update is called once per frame void Update() { Text latitude_component = LatitudeText.GetComponent<Text>();// 紐づけたLatitudeTextのオブジェクトを変数に格納 Text longitude_component = LongitudeText.GetComponent<Text>();// 紐づけたLongitudeTextのオブジェクトを変数に格納 latitude_component.text = Convert.ToString(Input.location.lastData.latitude);// Textオブジェクトのtext部分を取得したGPS情報の緯度で上書き longitude_component.text = Convert.ToString(Input.location.lastData.longitude);// Textオブジェクトのtext部分を取得したGPS情報の経度で上書き } }
GoogleMapを表示するスクリプト
using System.Collections; using UnityEngine; using UnityEngine.Networking;// Unity内でネットワークを使用するときに記入する public class StaticMapController : MonoBehaviour { private const string STATIC_MAP_URL = "https://maps.googleapis.com/maps/api/staticmap?key=${APIKey}&zoom=15&size=640x640&scale=2&maptype=terrain&style=element:labels|visibility:off";// Google Maps Static API URL、${APIKey}を作成したapiキーに書き換える private int frame = 0;// マップの更新をする間隔の変数 // Start is called before the first frame update void Start() { StartCoroutine(getStaticMap());// getStaticMapを実行する } // Update is called once per frame void Update() { frame++;// frameを1ずつ変える if (frame >= 300)// もし、frameが300以上なら、 { StartCoroutine(getStaticMap());// getStaticMapを実行する frame = 0;// frameを0にする } } IEnumerator getStaticMap() { var query = "";// queryを初期化する query += "¢er=" + UnityWebRequest.UnEscapeURL(string.Format("{0},{1}", Input.location.lastData.latitude, Input.location.lastData.longitude));// centerで取得するミニマップの中央座標を設定 query += "&markers=" + UnityWebRequest.UnEscapeURL(string.Format("{0},{1}", Input.location.lastData.latitude, Input.location.lastData.longitude));// markersで渡した座標(=現在位置)にマーカーを立てる var req = UnityWebRequestTexture.GetTexture(STATIC_MAP_URL + query);// リクエストの定義 yield return req.SendWebRequest();// リクエスト実行 if (req.error == null)// もし、リクエストがエラーでなければ、 { Destroy(GetComponent<Renderer>().material.mainTexture); //マップをなくす GetComponent<Renderer>().material.mainTexture = ((DownloadHandlerTexture)req.downloadHandler).texture; //マップを貼りつける } } }
private const string STATIC_MAP_URL = "https://maps.googleapis.com/maps/api/staticmap?key=${APIKey}&zoom=15&size=640x640&scale=2&maptype=terrain&style=element:labels|visibility:off";
には、取得したAPIを入れてください
入力例
※APIキーがGetabakoの場合
private const string STATIC_MAP_URL = "https://maps.googleapis.com/maps/api/staticmap?key=Getabako&zoom=15&size=640x640&scale=2&maptype=terrain&style=element:labels|visibility:off";
スクリプトをアタッチ
ShowGPSをCanvasに、StaticMapControllerをPlaneにドラッグ&ドロップします
更に、Canvasを選択し、それぞれのTextをLatitude TextとLongitude Textにドラッグ&ドロップします
テストプレイしてみると
テストプレイはUnityRemote5を使用して行いましょう
GPSはPCのみでは使えないからです
UnityRemoteの使い方はこちらを参考にしてください
緯度と経度が表示されて、GoogleMapが表示されます
目的地までの経路を表示する
経路を表示するためのJSONデータの作成
経路を探索するには膨大なデータがあります。それらを取扱うために別でJSONデータだけ作成し、スクリプトに読み込ませるという方法をとります
コードの書き方は違いますが、GoogleDirectionDataという名前でC#を作成して、以下のスクリプトを入力します
入力するスクリプト
using System.Collections; using System.Runtime.Serialization; using System.Collections.Generic; [DataContract] public class GoogleDirectionData { // DataMemberを付けたオブジェクトは、同じ名前のパラメータが入ったときに自動でマッピングされる([DataMember (name="hoge")]で明示的にマッピングも可能) [DataMember] public List<GeocodedWaypoints> geocoded_waypoints; [DataMember] public List<Route> routes; [DataMember] public string status; public class GeocodedWaypoints { [DataMember] public string geocoder_status; [DataMember] public string place_id; [DataMember] public ArrayList types; } public class Route { [DataMember] public List<Bound> bounds; [DataMember] public string copyrights; [DataMember] public List<Legs> legs; [DataMember] public List<OverviewPolyline> overview_polyline; [DataMember] public string summary; [DataMember] public List<string> warnings; [DataMember] public List<string> waypoint_order; } public class Bound { [DataMember] public Location northeast; [DataMember] public Location southwest; } public class Legs { [DataMember] public Distance distance; [DataMember] public Duration duration; [DataMember] public string start_address; [DataMember] public string end_address; [DataMember] public Location start_location; [DataMember] public Location end_location; [DataMember] public List<Step> steps; } public class OverviewPolyline { [DataMember] public string points; } public class Distance { [DataMember] public string text; [DataMember] public string value; } public class Duration { [DataMember] public string text; [DataMember] public string value; } public class Location { [DataMember] public string lat; [DataMember] public string lng; } public class Step { [DataMember] public Distance distance; [DataMember] public Duration duration; [DataMember] public Location start_location; [DataMember] public Location end_location; [DataMember] public string html_instructions; [DataMember] public Polyline polyline; [DataMember] public string travel_mode; } public class Polyline { [DataMember] public string points; } }
経路探索を行うスクリプトをつけるオブジェクトの作成
Create → CreateEmptyをおす
名前をDirectionControllerにします
InputFieldの作成
目的地を入力するために作成します
Create → UI → InputFieldをおします
InputFieldの位置を丁度いい位置に調整します
経路探索のスクリプト
using System.Collections; using UnityEngine; using UnityEngine.Networking; using System.Runtime.Serialization.Json; using System.Text; using System.IO; using UnityEngine.UI; public class DirectionController : MonoBehaviour { private const string GOOGLE_DIRECTIONS_API_URL = "https://maps.googleapis.com/maps/api/directions/json?key=${APIKey}&mode=walking"; public InputField destination;// 目的地を入力させるInputField public string destinationRoute = "";// APIより取得した経路(staticMapControllerに渡すためのパラメータ) private int frame = 0; void Start() { } void Update() { if (frame >= 300 && destination.text != "")// 更新は5秒に一度、目的地が設定されていない場合は取得しない。 { Debug.Log(UnityWebRequest.UnEscapeURL(destination.text)); StartCoroutine(GetDirection()); frame = 0; } frame++; } private IEnumerator GetDirection() { var query = "&origin=" + UnityWebRequest.UnEscapeURL(string.Format("{0},{1}", Input.location.lastData.latitude, Input.location.lastData.longitude));// origin=開始地点。現在地からの経路を出したいので現在地を渡す。 query += "&destination=" + UnityWebRequest.UnEscapeURL(destination.text);// destination=目的地。InputFieldに入力した文字列をエスケープして渡す。 UnityWebRequest req = UnityWebRequest.Get(GOOGLE_DIRECTIONS_API_URL + query); yield return req.SendWebRequest(); if (req.error == null) { MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(req.downloadHandler.text));// 返ってきたjsonをByte[]形式を処理できるMemoryStreamで受け取る var serializer = new DataContractJsonSerializer(typeof(GoogleDirectionData));// google DirectionのJSONをオブジェクトとして読み込めるようにシリアライザを作成 GoogleDirectionData googleDirectionData = (GoogleDirectionData)serializer.ReadObject(ms);// 作成したJSON用のクラスにデシリアライズ var leg = googleDirectionData.routes[0].legs[0];// データの形式としてroutes[0].legs[0]は固定なので一旦変数に格納 destinationRoute = "";// 書き込み前に初期化 for (int i = 0; i < leg.steps.Count; i++) { destinationRoute += "|" + leg.steps[i].end_location.lat + "," + leg.steps[i].end_location.lng;// 経路は|緯度,経度|という書き方になるので、受け取ったlatitude, longitudeをパイプとカンマを付けて追加していく if (i > 20) break;// 経路が多すぎるとUriFormatExceptionで落ちるため上限を設定しておく。 } } } }
DirectionControllerスクリプトをDirectionControllerにドラッグ&ドロップします
DirectionControllerスクリプトにInputFieldをドラッグ&ドロップします
StaticMapControllerに追記する
using System.Collections; using UnityEngine; using UnityEngine.Networking; public class StaticMapController : MonoBehaviour { //Google Maps API Staticmap URL // ${APIKey}を自分で作成したapiキーに書き換えてください。 private const string STATIC_MAP_URL = "https://maps.googleapis.com/maps/api/staticmap?key=${APIKey}&zoom=15&size=640x640&scale=2&maptype=terrain&style=element:labels|visibility:off"; private int frame = 0; public DirectionController direction = null;// DirectionControllerを付与したオブジェクトを追加する // Start is called before the first frame update void Start() { StartCoroutine(getStaticMap()); } // Update is called once per frame void Update() { if (frame >= 300) { StartCoroutine(getStaticMap()); frame = 0; } frame++; } IEnumerator getStaticMap() { var query = ""; query += "¢er=" + UnityWebRequest.UnEscapeURL(string.Format("{0},{1}", Input.location.lastData.latitude, Input.location.lastData.longitude)); query += "&markers=" + UnityWebRequest.UnEscapeURL(string.Format("{0},{1}", Input.location.lastData.latitude, Input.location.lastData.longitude)); if (direction.destinationRoute != "")// DirectionControllerより経路が格納されていればpathを追加する { query += "&path=color:red|" + UnityWebRequest.UnEscapeURL(string.Format("{0},{1}", Input.location.lastData.latitude, Input.location.lastData.longitude)) + direction.destinationRoute; } var req = UnityWebRequestTexture.GetTexture(STATIC_MAP_URL + query); yield return req.SendWebRequest(); if (req.error == null) { Destroy(GetComponent<Renderer>().material.mainTexture); GetComponent<Renderer>().material.mainTexture = ((DownloadHandlerTexture)req.downloadHandler).texture; } } }
Plane(地図を表示するオブジェクト)を選択し、DirectionControllerをドラッグ&ドロップします
テストプレイをしてみると
目的地を入力するとそこまでの経路が表示されます
コメント