Google Map PlatformゲームサービスとMaps SDK for Unityの開発のコツ
こんにちは、デザイニウムのWilliam(@eminliam)です。Google Map Platformゲームサービスは2019年6月に一般公開されました。その中でUnity開発のためのMaps SDK for Unityも一緒に公開され、自分もMaps SDKを色んなプロジェクトで開発してみました。確かにとても素晴らしいツールでした。なので、今回はGoogle Map PlatformゲームサービスとMaps SDK for Unityで開発するナレッジとコツを共有したいと思います。
サンプル
こちらのサンプルは東京オフィスのMatt(@mechpil0t)がMaps SDKを使って作ったARマップアプリです。
東京タワーの辺りを表示するデモ動画
アプリの流れとしては先ずインタラクティブマップから表示したい範囲を決めます。そしてAR機能が平面検知をすると、その範囲で3DマップがARで表示されます。そこに生成された建物や道路などの3DモデルはGoogle Maps Platformから生成されたものです。このサンプルはマップ上の店や施設などの情報も表示されていますが、それも別のGoogleサービスから提供された情報から生成されたものです。Maps SDKを使えば、Unityでこういうアプリが他の3Dマップサービスより簡単に作れます。そして、生成された3Dモデルのビジュアルは自由に変えられます。
五反田の辺りをMaps SDKのサンプルテキスチャーで表示するデモ動画
五反田の辺りをサイバー風テキスチャーで表示するデモ動画
機能
Maps SDKの中で一番大事なスクリプトはMapFeatureという建物や道路などのゲームオブジェクトを生成するMapsService.csです。生成されたゲームオブジェクトは全部スクリプトが付いている親オブジェクトの子供オブジェクトとして保管されています。
そして、MapsService.csの中に生成されたMapFeatureを管理しているWillCreate(Featureが生成される直前)とDidCreate(Featureが生成される直後)などのイベントにアクセスできます。例えば、建物を生成される前にデフォルトのマテリアルを変更するなどの操作は可能になります。それ以外にMaps SDKはFloating Origin UpdaterやBuilding Texturerなど色んな便利なコンポーネントを提供しています。そういう機能も同じようにMaps SDKの動作を制御できます。
/// <summary>
/// The <see cref="MapsService"/> is the entry point to communicate with to the Maps SDK for
/// Unity. It provides apis to load map regions, and dispatches events throughout the loading
/// process. These events, in particular WillCreate/DidCreate events provide a finer control on
/// each loaded map feature.
/// </summary>
[Tooltip("Required maps service (used to communicate with the Maps plugin).")]
public MapsService MapsService;
/// <summary>
/// In this example, the map setup and loading are done as soon as the loader becomes active in
/// the scene.
/// </summary>
void Start() {
InitFloatingOrigin();
InitStylingOptions();
InitEventListeners();
InitErrorHandling();
// Change Materials
MapsService.Events.SegmentEvents.WillCreate.AddListener(WillCreateHandler);
MapsService.Events.AreaWaterEvents.WillCreate.AddListener(WillCreateHandlerWater);
MapsService.Events.RegionEvents.WillCreate.AddListener(WillCreateHandlerRegion);
MapsService.Events.ModeledStructureEvents.WillCreate.AddListener(WillCreateHandlerModeled);
IsInitialized = true;
if (LoadOnStart) {
LoadMap();
}
}
MapsService.csのイベントにアクセスのサンプルコード
Maps SDKの中にはいくつかの重要なメソッドが提供されています、その一つは正確に経緯度をUnity上の3D座標を変換するメソッドです。例えば、現実の緯度と緯度を使えば、マップ上に相対の位置にゲームオブジェクトを生成することが可能です。
// GMP LatLng conversion
// An immutable representation of a set of geographical coordinates.
// latitude = 緯度 longitude = 経度
LatLng latlng = new LatLng((double)latit, (double)longt);
Vector3 targetLocation = MapsService.Coords.FromLatLngToVector3(latlng);
GameObject place = Instantiate(placeGameobject, targetLocation, transform.rotation);
経緯度を使ってゲームオブジェクトを生成するのサンプルコード
Unity上では遠すぎるオブジェクトの設置に対してはSingle-precision floating-point problems(単精度浮動小数点の問題)が発生しやすいので、プレイヤーがシーンの中央から遠く移動すると、画像がぶれたり、オブジェクトの位置に誤差が出る問題が発生します。なので、そのままGMPを使って長い距離移動しながらマップを生成するのはおすすめしません。
そこでこの問題を解決するソリューションとしてMaps SDKがFloating Originコンポーネントを提供しています。マップが設定した制限距離まで生成すると、ゲーム世界の中心と生成されたFeaturesは全部一回シーンの中央(0, 0)までスムーズに移動するという仕組みです。そうすると、プレイヤーとマップはずっとシーンの中央位置に維持することができます。国と国のような長距離移動も問題が発生しません。
private void TryMoveFloatingOrigin(Vector3 moveAmount) {
if (MapsService == null) {
return;
}
Vector3 newFloatingOrigin = GetCameraPositionOnGroundPlane();
float distance = Vector3.Distance(FloatingOrigin, newFloatingOrigin);
// Reset the world's Floating Origin if (and only if) the Camera has moved far enough.
if (distance < FloatingOriginRange) {
return;
}
// The Camera's current position is given to MapsService's MoveFloatingOrigin function,
// along with any GameObjects to move along with the world (which will at least be the the
// Camera itself). This is so that the world, the Camera, and any extra GameObjects can all be
// moved together, until the Camera is over the origin again. Note that the MoveFloatingOrigin
// function automatically moves all geometry loaded by the Maps Service.
Vector3 originOffset =
MapsService.MoveFloatingOrigin(newFloatingOrigin, AdditionalGameObjects);
// Use event to inform other classes of change in origin. Note that because this is a Unity
// Event a null reference exception will not be triggered if no listeners have been added.
OnFloatingOriginUpdate.Invoke(originOffset);
// Set the new Camera origin. This ensures that we can accurately tell when the Camera has
// moved away from this new origin, and the world needs to be recentered again.
FloatingOrigin = newFloatingOrigin;
// Optionally print a debug message, saying how much the Floating Origin was moved by.
if (DebugFloatingOrigin && !Mathf.Approximately(distance, 0)) {
Debug.LogFormat("Floating Origin moved: world moved by {0}", originOffset);
}
}
Floating Originを更新するのサンプルコード
// Floating Origin更新する時マップと一緒にカメラも移動する
mapsService.MoveFloatingOrigin(
Camera.main.transform.position,
new [] { Camera.main.gameObject });
Floating Originを移動する時に二つのパラメータが必要です。新しい中央いちのVector3座標と一緒に移動するゲームオブジェクトのリストです。ゲームオブジェクトリストに入れたものは全部マップと一緒にシーンの中央から距離によって位置を更新します。
ビジュアル
Maps SDKが主に生成するMapFeatureは以下となります:Structure(建物)、Segment (道路)、Area Water(水面)、Region(エリア、公園など)。生成したゲームオブジェクトは全部メタデータが付いていて、マテリアル変更、プレハブ置換などのビジュアル調整が可能です。
建物はExtruded Structure(2DのGoogle Map地図から生成建物)とModeled Structure(スカイツリーなどモデルが提供しているの特別な建物)二種類あります。
Modeled Structureのスカイツリー
そして、建物が持っているメタデータは以下となります:Name (必ず建物本来の名前を持ってではありません)、PlaceID、とUsage。Usageは建物を種類別で区別しています、Usageを使って建物を分類やフィルタリングすることができます。今GMPが提供しているUsageは以下となります:
Unspecific(非指定)
Bar(バー)
Bank(銀行)
Lodging(宿泊)
Cafe(カフェ)
Restaurant(飲食店)
Event Venue(イベント会場)
Tourist Destination(観光地)
Shopping(ショッピング)
School(学校)
Maps SDKはBuildingWall.shaderというシェーダーを提供しています。それは「9 スライス」という方法で建物の壁を9 つにスライスしたマテリアルを使用して、9 つのエリアの大きさなどの数値を変更し、リピートする部分制御して、建物をテクスチャ処理している方法です。
本来のテクスチャと「9 スライス」ディバグ用テクスチャの比較
あと、BuildingWallのシェーダーはEmissionも対応していて、日光を制御するスクリプトで建物の窓が光る効果もできます。
道路が持っているメタデータは以下となります:Name、PlaceID、isPrivate(プライベートや制限があるなど)。道路は水面とエリアと同じ、マテリアルの変更で外観を変更することができます。
Maps SDKにはRoadNamesUpdaterとBuildingNamesUpdaterなどのコンポーネントがあります。それを使って、NameLabelというプレハブを生成して、建物名と道路名をラベルとして表示することができます。
料金
2019年9月時点では、Google Cloud PlatformはアカウントごとMaps SDKの使用量に毎月$200USDの無料クレジットが提供されています。そして、毎月の料金はDAU(デイリーアクティブユーザー)基準で計算されています。毎日アクセスしたディバイスごとにカウントしています。詳しい計算は以下となります:
例1:毎日500DAUなら一か月は500*30=15,000MAU
料金は15,000/1000*10($10 per 1,000 DAU)=$150
つまり毎日DAU500以下なら実質無料です(無料クレジット$200)
例2:毎日1000DAUなら一か月は1000*30=30,000MAU
料金は30,000/1000*10($10 per 1,000 DAU)=$300
無料クレジットを加えて料金は$100
例3:毎日40,000DAUなら一か月は40,000*30=1,200,000MAU
初1,200,000DAUの料金は1,200,000/1000*10($10 per 1,000 DAU)=$12,000
無料クレジットを加えて料金は$11,800
例4:毎日75,000DAUなら一か月は75,000*30=2,250,000MAU
初1,500,000DAUの料金は1,500,000/1000*10($10 per 1,000 DAU)=$15,000
以降の750,000DAUの料金は750,000/1000*8($8 per 1,000 DAU)=$6,000
無料クレジットを加えて料金は$20,800
現在の料金計算はこちらに参考してください:
まとめ
Google Map Platformゲームサービスは強大なSDKをデベロッパーに提供していて、Google Mapの情報との位置合わせが正確、見た目変更の自由度も凄く高い、そして他の3Dマップサービスが持っている課題を簡単に解決できるのは本当に助かりました。今回触れたのは、Maps SDKの機能はほんの一部なので、今後Google Map Platformゲームサービスで出来ることをもっと探りたいと思います。
編集後記
広報のマリコ(@marikocco)です。今回ご紹介した Google Map PlatformゲームサービスとMaps SDK for Unityを使ってアプリやゲームを開発することで、臨場感あふれるリアルな背景や場面が作り出されるんですね!実際の街と同じ道や建物がある風景を楽しめるのは、コロナ禍の今とても嬉しいですね。今後ますます活用されるのが楽しみです😊
The Designium.inc
・オフィシャルサイト
・Interactive website
・Twitter
・Facebook