はじめに
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をドラッグ&ドロップします
テストプレイをしてみると
目的地を入力するとそこまでの経路が表示されます
コメント