UnityでGoogleMapを読み込み、表示させるとこから経路探索まで

目次

はじめに

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 += "&center=" + 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 += "&center=" + 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をドラッグ&ドロップします

テストプレイをしてみると

目的地を入力するとそこまでの経路が表示されます

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

目次