Unity × GPS × GoogleMapsAPI で日常生活にミニマップを

ゲームをしてる時にふと、「日常生活にもミニマップあったら便利なんじゃないか?」と思ったのでUnityを使ってAndroidアプリとして実装してみました。
具体的に言うと「Webカメラを通して見る世界の左下隅に、GPSで取得した現在地の周辺のGoogleMapが常に表示され続けるAndroidアプリをUnityで作ろう」という話です。

実装の際に課題になったものは、
 - UnityをAndroidでビルドできるようにする
 - GPSで現在地の座標を取得する
 - Android のカメラ画像を表示する
 - GoogleMapsAPIで位置情報に応じたマップを表示して現在地にマーカーをたてる
の4点でした。

UnityをAndroidでビルドできるようにする方法は割愛させていただきますが、私が参考にさせていただいたサイトを載せておきます。

ちなみに私はMinimum API Levelの設定で小一時間程悩みましたが、ここはお使いのAndroidのバージョンに合わせてください。私が使ってるバージョンは4.2.2だったのですが、なぜか4.2ではなく4.1でないと通りませんでした。
f:id:unitymas_CS:20150808001936p:plain
また、Virtual Reality Supportedにチェックが入ってるとMinimum API Levelが変更できないのでチェックを外すことを忘れずに。


次に、UnityでGPSを使った位置情報の取得。
これは「Unityで位置情報を取得 - チラ裏Unity」さんを参照してください。全部書かれてます。


カメラの映像を表示するには、WebCamTextureを使用します。

using UnityEngine;
using System.Collections;
public class WebCam : MonoBehaviour {
	public int Width = 1920; //解像度横
	public int Height = 1080; //解像度縦
	public int FPS = 20;
	void Start () {
		WebCamDevice[] devices = WebCamTexture.devices;
		WebCamTexture webcamTexture = new WebCamTexture(devices[0].name, Width, Height, FPS);
		GetComponent<Renderer> ().material.mainTexture = webcamTexture;
		webcamTexture.Play();
	}
}

このスクリプトをPlaneなりQuadなりにアタッチすればAndroidカメラからの映像を見ることができます。


UnityでGoogleMapsAPIを使うには、WWWクラスを使用します。さらに、GPSで取得した現在地と組み合わせるコードはこのようになります。

using UnityEngine;
using System.Collections;
public class MiniMap : MonoBehaviour {
	GUITexture mapGuiTexture;
	private float intervalTime = 0.0f;
	private int width = 300;
	private int height = 200;
	private double longitude;
	private double latitude;
	private int zoom = 16;
	void Start () {
		mapGuiTexture = this.GetComponent<GUITexture> ();
		GetPos ();
		GetMap();
	}
	void Update(){
                //毎フレーム読んでると処理が重くなるので、3秒毎に更新
		intervalTime += Time.deltaTime;
		if (intervalTime >= 3.0f) {
			GetPos ();
			GetMap ();
			intervalTime = 0.0f;
		}
	}
	void GetPos () {
        //GPSで取得した緯度経度を変数に代入
		StartCoroutine (GetGPS());
		longitude = Input.location.lastData.longitude;
		latitude = Input.location.lastData.latitude;
	}
	void GetMap () {
        //マップを取得
		StartCoroutine(GetStreetViewImage(latitude, longitude, zoom));
	}
	private IEnumerator GetGPS() {
		if (!Input.location.isEnabledByUser) {
			yield break;
		}
		Input.location.Start();
		int maxWait =  120;
		while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0) {
			yield return new WaitForSeconds(1);
			maxWait--;
		}
		if (maxWait < 1) {
			print("Timed out");
			yield break;
		}
		if (Input.location.status == LocationServiceStatus.Failed) {
			print("Unable to determine device location");
			yield break;
		} else {
			print("Location: " + 
			      Input.location.lastData.latitude + " " + 
			      Input.location.lastData.longitude + " " + 
			      Input.location.lastData.altitude + " " + 
			      Input.location.lastData.horizontalAccuracy + " " + 
			      Input.location.lastData.timestamp);
		}
		Input.location.Stop();
	}
	private IEnumerator GetStreetViewImage(double latitude, double longitude, double zoom) {
        //現在地マーカーはここの「&markers」以下で編集可能
		string url = "http://maps.googleapis.com/maps/api/staticmap?center=" + latitude + "," + longitude + "&zoom=" + zoom + "&size=" + width + "x" + height + "&markers=size:mid%7Ccolor:red%7C" + latitude + "," + longitude;
		WWW www = new WWW(url);
		yield return www;
        //マップの画像をTextureとして貼り付ける
		mapGuiTexture.texture = www.texture;
        //ミニマップに透明度を与える
		mapGuiTexture.color = new Color (mapGuiTexture.color.r, mapGuiTexture.color.g, mapGuiTexture.color.b, 0.4f);
	}
}

このスクリプトをGUITextureにアタッチすればミニマップが見れるようになります。


少し(というかかなり)GPSの精度が低いのが問題ですが、これで日常生活にミニマップ機能を追加するアプリの完成です。
ハコスコみたいなやつと一緒に使用すれば日常がゲームの世界になったように感じることができるかもしれませんね。