tpc18-1

TOPIC 18|Unityで都市を爆走するミニゲームを作る[1/2]|3D都市モデルを使ったゲームを作る

3D都市を車で走り回るミニゲームを作ります。点数を競うゲームで、建物などに衝突すると爆発して加点されます。建物の高さや種類に応じて得点を変える仕組みを実装することで、Unityから3D都市モデルが持つ属性にアクセスする方法も学べます。

Share

TOPIC 18:Unityで都市を爆走するミニゲームを作る

このトピックでは、3D都市を車で走り回るミニゲームを作ります。点数を競うゲームで、建物などに衝突すると爆発して加点されます。建物の高さや種類に応じて得点を変える仕組みを実装することで、Unityから3D都市モデルが持つ属性にアクセスする方法も学べます。

本トピックの内容は「Unity初心者でもOK 好きな都市を爆走するミニゲームの作り方」(2023年度PLATEAU Hands-onアーカイブ動画)でも制作方法をハンズオン形式で紹介しています。

【目次】

18.1  このトピックの見どころ

18.2  想定する環境と事前準備

 18.2.1  Unity及びPLATEAU SDK for Unity

 18.2.2  動作環境

18.3  3D都市モデルのインポート

 18.3.1  プロジェクトの作成とPLATEAU SDK for Unityの導入

 18.3.2  3D都市モデルのインポート

18.4  車をインポートして走行できるようにする

 18.4.1  車のアセットのインポート

 18.4.2  車を動かす

18.5  衝突した建築物を消滅させる

 18.5.1  衝突対象を別のレイヤに分ける

 18.5.2  衝突しても減速しないようにする

 18.5.3  衝突時に地物を消すスクリプトをアタッチする

 18.5.4  動作を確認する

18.1 _ このトピックの見どころ

このトピックでは、PLATEAU SDK for Unityを使って、PLATEAUの3D都市モデルの扱い方を習得します。主な見どころは、以下のとおりです。

◾️ 3D都市モデルのインポート方法

Unityを起動してプロジェクトを作り、PLATEAU SDK for Unityを用いて、任意のエリアの3D都市モデルをインポートする方法を学びます。

◾️ 車のアセットをインポートして走行できるようにする方法

車のアセットをインポートして、3D都市モデル上を走り回れるようにします。

◾️ 衝突したときに爆発するようにする

車が建物などに衝突したときに、爆発するようにします。インポートした3D都市モデルのオブジェクトのうち、衝突の対象となる「建築物」「都市設備」「植生」を別のレイヤに移動して、それらを消える対象としてグループ化します。

爆発のパーティクルを適用することで、単純に消えるだけでなく、爆発のモーションも表現できるようにします。

◾️ スコアを加算する

スコアを表示するUIを作り、スコアを表示します。地物の種類や属性によって、得点を変える仕組みも作ります。具体的には、高いビルとぶつかるほど、高得点になるようにします。

地物の属性を調べる方法は、いくつかありますが、ここではPLATEAU SDKのC# APIを使って、シーン中の属性情報を読み取ることで判別します。

図 18-1 このトピックで作るミニゲーム。建物にぶつかると爆発する

18.2 _ 想定する環境と事前準備

本トピックでは、以下の環境を想定します。

18.2.1 _ Unity及びPLATEAU SDK for Unity

UnityでPLATEAUの3D都市モデルを扱うため、「PLATEAU SDK for Unity」を使います。下記のサイトを参考に、Unityプロジェクトを作成し、PLATEAU SDK for Unityをインストールしてください。

【メモ】

本トピックでは、執筆時点で最新のPLATEAU SDK for Unity Ver 2.0.0-alphaを用います。対応するUnityのバージョンは2021.3ですが、今後のバージョンアップに伴い、変更となる恐れがあります。最新版につきましては、ドキュメントの記載をご確認ください。

【PLATEAU SDK for Unity】

https://project-plateau.github.io/PLATEAU-SDK-for-Unity/

18.2.2 _ 動作環境

本トピックは、下記の環境で、動作確認をしています。

CPUAMD Ryzen 5 5600X
RAM32GB
GPUNVIDIA GeForce RTX 3060

例として、沼津市のLOD3の3D都市モデルを利用します。GPUを搭載していないなど、性能の低いPCで試す場合には、代わりにLOD2やLOD1など、軽量な3D都市モデルを利用してください。

【メモ】

 LODとは詳細度のことです。LODの値が大きいほど細かいディテールまで表現されている一方、データサイズは大きくなります(「TOPIC1  1.3.2 _ LOD」を参照)。

18.3 _ 3D都市モデルのインポート

まずは、3D都市モデルをインポートします。

18.3.1 _ プロジェクトの作成とPLATEAU SDK for Unityの導入

プロジェクトを作成し、PLATEAU SDK for Unityを導入します。

【手順】プロジェクトの作成とPLAEAU SDK for Unityの導入

[1]新規プロジェクトの作成

Unityで新規プロジェクトを作成します。[3D]のテンプレートとして作成します。

図 18-2 3Dのテンプレートを使ってプロジェクトを新規作成する

[2]PLATEAU SDK for Unityの導入

プロジェクトを新規作成したら、PLATEAU SDK for Unityの導入方法のドキュメントに基づき、プロジェクトにPLATESU SDK for Unityをインストールします。

パッケージマネージャから、①配布されているtgzファイルをインストール、②GitHubのURLを指定してインストール、の2通りの方法があります。詳しくは、上述のドキュメントを参照してください。

正しくインストールできると、Unity Editorに[PLATEAU]のメニュー項目が追加されます。

図 18-3 パッケージマネージャからPLATEAU SDK for Unityをインストールする
図 18-4 [PLATEAU]メニューが追加された

18.3.2 _ 3D都市モデルのインポート

導入したPLATEAU SDK for Unityを用いて、3D都市モデルをインポートします。今回は、静岡県沼津市の3D都市モデルをインポートします。

【手順】3D都市モデルのインポート

[1]PLATEAU SDKを起動する

[PLATEAU]メニューから[PLATEAU SDK]を選択し、PLATEAU SDK for Unityを起動します(前述の図 18-4を参照)。

[2]都市と基本座標系を選択する

PLATEAU SDK for Unityのウィンドウが開きます。

すでにダウンロード済みのCityGMLファイルからインポートする[ローカル]か、インターネットからダウンロードしてインポートする[サーバー]の、いずれかの選択肢があります。

ここでは[サーバー]を選択します。すると、地域が表示されるので、[静岡県]の[沼津市]を選択します。

地域に合わせて、[基準座標系]を選択します。ここでは[08:新潟、長野、山梨、静岡]を選択します。

【メモ】

基準座標系とは、どこを原点とするかを定める平面直角座標系のことです。地域によって原点が違うので注意してください(「TOPIC3 3.5.3 _ 平面直角座標系」を参照)

図 18-5 都市と基本座標系を選択する

[3]範囲選択する

そのまま下にスクロールすると、[範囲選択]のボタンがあるので、それをクリックします。

図 18-6 範囲選択をはじめる

すると、地図上でインポートする範囲を決める画面が表示されます。この画面で、オレンジ色の枠を操作して、インポート範囲を選びます。

マウスのホイールを前後に動かすと拡大・縮小、スペースキーを押しながらドラッグすると地図をスクロールできます。拡大していくと、メッシュコード(「TOPIC3 3.2.4 _ メッシュコードによるファイルの分割」を参照)と呼ばれる区域を示す番号と、その区域で、どのようなデータがどのような詳細度で提供されているのかを示すアイコンが表示されます。

ここでは、現時点で詳細度が最も高いLOD3のデータが提供されている沼津市周辺の1エリアを選択します。具体的なメッシュコードで言うと、「52385628」を選択しました。選択したら、ツールバーの[決定]をクリックします。

このエリアを選んだのは、一例であり、どの地域でもかまいません。ここではLOD3のある1エリアを選びましたが、スペックの低いPCでは、1エリアよりも狭い範囲にしたり、LOD2やLOD1などデータ量の少ないエリアを選んだりするなどしてください。

本トピックで説明する都市を爆走するミニゲームは、建物と土地のデータが提供されているエリアであれば、どこでも作成できます。PLATEAUの3D都市モデルは100以上の地方公共団体で整備されているので、好きな場所を選んでください。

【メモ】

LOD1(黒色アイコン)は箱形な大雑把な形状、LOD2(青色アイコン)はある程度の立体感のある形状で、場所によってはテクスチャも提供されています。LOD3(赤色アイコン)は現時点で最も精細度が高いモデルで、ドアや窓などの開口部も表現されています。PLATEAUでは今後、建物の内側まで見られるLOD4の提供も予定されています。

図 18-7 地図が表示された
図 18-8 インポートするエリアを選ぶ(今回は「52385628」の近辺を選んだ)

[4]地物別設定をする

PLATEAU SDK for Unityのウィンドウに戻り、どのようにインポートするかを決めます。

●地物ごとの設定方法

「植生」「建築物」「道路」「土地起伏」「都市計画決定情報」「災害リスク」「土地利用」「都市設備」の、それぞれの項目で、どの地物をどのようにインポートするのかを決めます。

次のように設定します。

(1)インポートしない地物のチェックを外す

デフォルトでは、すべての地物にチェックが付いていますが、今回のミニゲームでは、「都市計画情報」「土地利用」「災害リスク」は利用しないので、これらに関して、[インポートする]のチェックを外します。

(2)インポートの設定

残りの地物については、[インポートする]のチェックを付け、次のようにします。

[テクスチャを含める]にチェック

チェックを付けることで、地物表面のテクスチャも一緒にインポートされるようになります。

・[Mesh Colliderをセットする]にチェック

インポートする際、衝突判定に用いるMesh Colliderを設定します。今回は、車との衝突判定をしたいので、チェックを付けてください。

[LOD描画設定]は[すべて]にする

LOD描画設定では、提供されているどのLODをインポートするかを設定できます。デフォルトでは、「1~3」や「0~3」など、提供されている全LODが選択されているので、そのまま変更しないようにします。

・[モデル結合単位]は[主要地物単位]とする

[モデル結合単位]は、モデルをどの単位でまとめてインポートするのかを設定します。[最小地物単位][主要地物単位][地域単位]の3つの選択肢があります。デフォルトは[主要地物単位]で、建築物などの単位で、1つのオブジェクトとしてインポートされます。今回は、車と建築物がぶつかったときに爆発する処理をしたいので、ここではデフォルトの[主要地物単位]のままとします。

【メモ】

[最小地物単位]を選択すると、屋根や窓、壁などの面ごとにインポートできます。そのぶん、オブジェクトの数が増えますが、より細かい単位で扱いたいときは、この選択肢を選ぶとよいでしょう。[地域単位]を選択すると、地域ごとに1つのオブジェクトとしてインポートできます。背景に使うなど、建築物ごとに分割する必要がない場合は、この選択肢を選ぶとよいでしょう。

図 18-9 地物のインポート方法を選択する

●基準座標系からのオフセット(メートル)

インポートする際、原点位置をどこにするのかを設定します。デフォルトでは、選択範囲の中心点で設定されているので、今回は、デフォルトのままとします。

上記の2つの設定が終わったら、[モデルをインポート]をクリックします。すると、モデルがインポートされます。

インポートが始まると、進捗状態がステータスバーで表示されます。しばらく時間がかかるので、完了まで待ちます。インポートが完了すると、原点付近に、3D都市モデルが配置されます。

図 18-10 基準座標系からのオフセット値を決める
図 18-11 進捗を示すステータスバー
図 18-12 原点付近に配置されたインポートした3D都市モデル
コラム:条件を満たす地物を非表示にする

通常、読み込んだオブジェクトは、すべてデフォルトで表示状態となります。しかし[モデルの調整]タブから条件を指定すると、条件に合うオブジェクトを非表示の状態として読み込むこともできます。

図 18-13 [モデル調整]タブ

18.4 _ 車をインポートして走行できるようにする

次に、車をインポートして、走行できるようにします。

18.4.1 _ 車のアセットのインポート

まずは、車のアセットをインポートします。

【手順】車のアセットのインポート

[1]車のアセットをダウンロードする

ここでは、下記からダウンロードできるアセットを使います。このアセットは、PLATEAU SDK for Unityに含まれているサンプルから、車に関するアセットを抜き出したものです。

【車のサンプルアセット】

https://drive.google.com/drive/folders/1imnzv2sIx54Cask57LqrhjWuQvwS0jlv?usp=drive_link

[2]車のアセットをインポートする

手順[1]でダウンロードしたアセットファイルをダブルクリックします。すると、パッケージに含まれるアセットの一覧が表示されるので、[Import]ボタンをクリックして、すべてをプロジェクトにインポートします。

図 18-14 車のアセットをすべてインポートする

[3]エラーを修正する

手順[2]でインポートすると、下記のエラーが発生します。このアセットでは、車を動かすためにInput Systemを使っているのですが、UnityのInput Systemが導入されていないのが原因です。

図 18-15 Input Systemが不足している

このエラーを解決するため、Input  Systemをインストールします。

[Window]メニューから[Package Manager]をクリックして、Package Managerを開きます。左上から[Unity Registry]を選択し、検索ボックスに「input」と入力すると「Input System」が見つかるので、[Install]をクリックして、インストールします。

図 18-16 Input Systemをインストールする

下図の警告メッセージが表示されたら、[Yes]をクリックします。するとUnityが再起動し、エラーが解消されます。

図 18-17 Input Systemをインストールするために再起動する

[4]車をシーン中に配置する

次に、車をシーン中に配置します。プロジェクトビューから[GameSample]―[CarAsset]―[Prefabs]―[Car]をシーン中にドラッグして配置します。配置場所がスタート地点となるので、駅前の広場などが見栄えとして良いでしょう。車が地面に埋まらないように高さを調整しておきます。

図 18-18 車を配置する

[5]Camera Controllerの設定

インポートした車のアセットには、カメラを制御する「Camera Controller」が含まれています。これをシーン中の[Main Camera]に適用します。

具体的には、[Hierarchy]ウィンドウから[Main Camera]を選択し、[Inspector]から[Add Component]をクリックして、インポートした「Camera Controller」をアタッチします。

アタッチしたら、次の2つのプロパティを設定します。

・[Position Target]には、車についている[CameraPosition]を設定する

・[Look At Target]には、[CameraLookAtTarget]を指定する

図 18-19 Camera Controllerを設定する
図 18-20 [Position Target]と[Look At Target]を設定する

18.4.2 _ 車を動かす

以上で、車を動かすところまでできました。Unityの[Play]ボタンをクリックすると、プレイして、車を動かせます。

操作は、[W]キーでアクセル、[Z]キーでブレーキ、[A]と[S]で、それぞれハンドルを左右に切れます。

図 18-21 車を操作した様子

18.5 _ 衝突した建築物を消滅させる

PLATEAU SDK for Unityで3D都市モデルをインポートする際、[Mesh Colliderをセットする]にチェックをつけているので、建物と車がぶつかると跳ね返り、それ以上進めません。車が衝突したら、その建築物を消えるようにしてみます。

18.5.1 _ 衝突対象を別のレイヤに分ける

処理として、消滅させる対象をレイヤで指定したいため、レイヤに名前を付け、建物や都市設備などを、そのレイヤに移動します。

【手順】衝突対象を別のレイヤに分ける

[1]レイヤ名を付ける

わかりやすくするため、レイヤ6の名称を「DestroyableByCar」に変更します。

右上から[Layers]で[Edit Layers]をクリックします。レイヤのインスペクタが開いたら、[User Layer6]の部分に「DestroyableByCar」と入力します。

図 18-22 レイヤ6の名前を「DestroyableByCar」に変更する

[2]「建築物」「都市設備」「植生」をレイヤ6に移動する

インポートした3D都市モデルのうち、「建築物」「都市設備」「植生」を、いま「DestroyableByCar」と名付けたレイヤ6に移動します。

3D都市モデルが、どのような種類であるのかは、ファイル名の命名規則から判断できます。「建築物」「都市設備」「植生」は、それぞれ、次の名称が含まれています。

建築物bldg
都市設備frn
植生veg

[Hierarchy]ウィンドウで、[Ctrl]キーを押しながら、これらの名称が含まれているものをクリックしてすべてを選択し、[Inspector]の[Layer]のところで[6:DestroyableByCar]を選択します。

子のオブジェクトもレイヤを変更するかを尋ねるメッセージが表示されたら、[Yes, change children]をクリックし、子も併せて変更するようにします。

図 18-23 「建築物」「都市設備」「植生」をレイヤ6に変更する
図 18-24 子オブジェクトも併せてレイヤを変更する

18.5.2 _ 衝突しても減速しないようにする

現在の状態では、車と地物が衝突したときに物理演算によって減速しますが(跳ね返りますが)、ゲームとして爽快感を持たせるため、減速せずに通り抜けられるようにします。そのためには、対象の地物のMeshColliderで[IsTrigger]をTrueに設定します。

【メモ】

Unityでは、IsTriggerがTrueである場合、「衝突した」「範囲内にあるか」などのイベントを発生するためにだけにMeshColliderが用いられ、物理演算は適用されない動作になります。

【手順】衝突しても減速しないようにする

[1]対象のMeshColliderを検索する

[Ctrl]+[K]キーを押し、Searchウィンドウを開きます。Searchウィンドウで「h: t:meshcollider layer=6」と入力して、検索します。

ここで指定している「layer=6」は、DestroyableByCarレイヤの番号です。この検索語句で検索することで、レイヤ6に設置されているすべてのMeshColliderが見つかります。

[2]すべて選択する

検索結果の先頭をクリックし、次に、[Shift]キーを押しながら、末尾をクリックします。これですべてが選択されます。

図 18-25 対象のMeshColliderを検索し、結果をすべて選択する

[3]inspectorで変更する

[Select]ボタンをクリックします。これで、該当のオブジェクトすべてが選択状態となります。

右上の[i]のアイコンをクリックすると、Inspectorが開き、選択状態のオブジェクトのプロパティを変更できます。[MeshCollider]の[Convex]と[IsTrigger]にチェックを付けます。

図 18-26 [Convex]と[IsTrigger]にチェックを付ける

[4][Convex]にできないMeshColliderを削除する

この状態で[▶]を実行すると、「Failed to create Convex Mesh from source mesh ……」というエラーメッセージが表示されます。これは頂点の数が小さすぎるのが理由です。該当のMeshColliderを削除することで解決します。

具体的には、検索ウィンドウに「h: t:meshcollider layer=6 vertices<10」と入力して検索し(vertices<10は頂点の数が10より小さいという意味)、表示された検索結果をすべて選択します。そして[i]をクリックして表示されたインスペクタの[Select]ボタンをクリックしてシーン上ですべて選択状態にします。

いったん検索ウィンドウを閉じて、シーン上で[Delete]キーを押して削除します。

図 18-27 頂点数の少ないMeshColliderを削除する
コラム:エラーが残るときは

それでもエラーが残る場合は、エラーメッセージを確認して、[Hierarchy]ウィンドウから、該当のオブジェクトを検索し、個々に削除してください。

図 18-28 残ったエラーは、個々に削除して解決する

18.5.3 _ 衝突時に地物を消すスクリプトをアタッチする

ここまでで、車が地物を通り抜けるようになりました。次に、衝突のイベント(OnTriggerEnterイベント)に、衝突した地物を削除するスクリプトをアタッチします。

【手順】衝突時に地物を消すスクリプトをアタッチする

[1]スクリプトを追加する

[Hierarchy]ウィンドウから[Car]をクリックして選択し、[Inspector]の[Add Component]―[New Script]をクリックしてスクリプトを追加します。スクリプトの名前は「ExplodeCollidedObject」とします。

図 18-29 スクリプトを追加する

[2]コードを記述する

下記の内容のコードを入力します。このコードは、targetLayersで指定されたレイヤに含まれている場合のみ、衝突したオブジェクトを削除(Destroy)する処理をしています。

using UnityEngine;

public class ExplodeCollidedObject : MonoBehaviour
{
    [SerializeField] private LayerMask targetLayers;

    private void OnTriggerEnter(Collider other)
    {
        // 衝突対象のレイヤがtargetLayersに含まれている場合のみ実行
        if ((targetLayers & (1 << other.gameObject.layer)) == 0) return;
        // 衝突対象を破壊
        Destroy(other.gameObject);
    }
}

[3]targetLayersを設定する

手順[2]のコードで参照しているtargetLayersプロパティを、Inspectorから設定します。ここではすでに対象の地物を配置している[DestroyableByCar]のレイヤを選択します。

図 18-30 targetLayersプロパティを設定する

18.5.4 _ 動作を確認する

以上で、ひととおりの実装が完了しました。[▶]を実行して車を走らせ、衝突した地物が消えることを確認してください。

DestroyableByCarレイヤには、建築物(bldg)だけでなく、都市設備(frn)や植生(veg)も配置しているので、柵やアーケード、木などにぶつかったときも、それらが消えます。

図 18-31 車に衝突した地物が消える

【文】

鈴木智貴(株式会社シナスタジア)、大澤文孝