【Unity】RPGを作るチュートリアルその65 ゲームで使うマップの作成

【Unity】RPGを作るチュートリアルその65 ゲームで使うマップの作成

シンプルなRPGをUnityで作るチュートリアルシリーズの65回目です。

第64回ではマップの管理クラスを作成して、エンカウントの動作を確認しました。

今回はゲームで使うマップを作成していきましょう。

 

 

制作環境

MacBook Pro 2023 Apple M2 Max

Unity6 (6000.0.30f1) Silicon

 

作業内容と順序

シンプルなRPGを作る上でどんな作業が必要か、どんな順番で作っていくと良さそうか、別ページで検討しました。基本的にこの流れに沿って進めていきます。

 

チュートリアルの一覧

このシリーズ全体の一覧は以下のページにまとめています。

 

前回の内容

前回はマップの管理クラスを作成して、エンカウントの動作を確認しました。

 

タイルの作成

今回のチュートリアルでは、大きく分けて3種類のマップを作成したいと思います。

  • フィールド
  • 洞窟

最初はそれぞれ1マップとして作っていきます。必要なタイルについてはチュートリアル用に作成してあるため、ダウンロードしてインポートできるようにしてあります。それぞれ個別にダウンロードするのも大変なので、zipでまとめたものもあります。(map_tile.zip)

 

村用タイル

村用マップでは、自宅、村長の家、道具屋を作っていきます。必要なタイルとしては以下のものになります。

家の床
家の床
机
木
壁

 

フィールド用タイル

フィールド用マップでは村や洞窟のアイコン、山などを配置しましょう。

村
洞窟
洞窟
山

 

洞窟用タイル

洞窟用マップでは床、壁を配置していきます。宝箱のタイルも作成してあります。イベントによる制御を入れるため、宝箱はタイルとして配置するのではなく個別のゲームオブジェクトとして配置予定です。

床
壁
宝箱
宝箱
宝箱(空)
宝箱(空)

 

タイルのインポート

必要なタイルをダウンロードしたら、プロジェクトにインポートします。UnityのProjectウィンドウから「Assets/Images/Tiles」のフォルダを開き、ダウンロードしたタイル用画像をインポートします。

タイルのインポート
タイルのインポート

 

インポートした画像を複数選択した状態でインポート設定を行います。タイル用画像に関しては設定のプリセットを作成してあるので、それを適用しましょう。Inspectorウィンドウの右上にあるプリセットボタンをクリックしてウィンドウを開き、「TileImporter」のプリセットをダブルクリックで選択後、Inspectorウィンドウ右下の [Apply] をクリックして適用します。

プリセットの適用
プリセットの適用

 

インポート設定が終わったら、「Tile Palette」のウィンドウを開き、インポートした画像をドラッグ&ドロップします。パレットは既存のものを使い、そこに追加していきます。

タイルの作成
タイルの作成

 

タイルの保存先は、モック用のタイルと同じフォルダである「Assets/Tiles」にします。

タイルの保存
タイルの保存

 

タイルが追加されると以下のように表示されます。今回はタイル数が少ないのでひとつのパレットで管理していますが、規模が大きい場合はパレットを分けておくと便利です。後から分けるとタイルの参照切れなどのリスクもあるので、先にある程度決めておくと手戻りが少ないかもしれません。

パレットにタイルが追加された
パレットにタイルが追加された

 

マップの作成

タイルをインポートしたら、マップを作成していきます。マップの構成はテスト用マップのものを使い、タイルの配置を変えていくイメージで作業を進めます。

 

村のマップの作成

Projectウィンドウから「Assets/Prefabs/Map」のフォルダを開き、テスト用マップのPrefabである「Map_0000_TestMap」を複製します。名前は [Map_0001_Village] にしました。

Prefabを複製
Prefabを複製

 

Inspectorウィンドウでは「Map Id」の値を [1] に、「Map Name」を [村] に変更し、「Encounter Data」に [EncounterData_Village] をアサインします。

マップの設定
マップの設定

 

作成したPrefabは、Hierarchyウィンドウの「Grid」のゲームオブジェクトの下にインスタンス化しましょう。また、既存のテスト用マップのゲームオブジェクトは削除しました。すでにPrefabにしてあるので、すぐに復元できるので安心です。さらに、タイル配置のしやすさを考え、NPCのゲームオブジェクトについては非表示にしました。NPCはマップ内に配置されるので、こちらも後の回で調整しましょう。

インスタンス化と整理
インスタンス化と整理

 

インスタンス化した「Map_0001_Village」のゲームオブジェクトについては、Prefabの編集画面を開いて、タイルを配置していきます。村に関しては壁と木、机を通行禁止タイルに登録予定なので、こちらを使って移動できる範囲を決めていきます。基本方針としては下地に草のタイル、家の範囲は床のタイル、あとはPropsのレイヤーに壁や木などを配置していきます。あとで作る場所移動イベントの位置を調整すればいいので、任意の位置にタイルを配置してください。私は以下のように、左が自宅、上が村長宅、右が道具屋、といった感じで配置してみました。

タイルの範囲外がカメラに映らないように、木のタイルで移動できる範囲を絞り、そこから6マス分くらい多めに下地のタイルを配置しています。

村のマップ
村のマップ

 

編集後はPrefabを保存します。

 

フィールドのマップの作成

Projectウィンドウから「Assets/Prefabs/Map」のフォルダにて、村用マップのPrefabである「Map_0001_Village」を複製します。名前は [Map_0002_Field] にしました。

Prefabを複製
Prefabを複製

 

Inspectorウィンドウでは「Map Id」の値を [2] に、「Map Name」を [フィールド] に変更し、「Encounter Data」に [EncounterData_Field] をアサインします。

フィールド用マップの設定
フィールド用マップの設定

 

作成したPrefabは、村のPrefabと同様にHierarchyウィンドウの「Grid」のゲームオブジェクトの下にインスタンス化しましょう。村のPrefabについては編集内容が保存されていることを確認してから削除します。確認方法としては、Inspectorウィンドウから「Overrides」のプルダウンをクリックして、「No Overrides」の表示があれば保存されているPrefabとの差分がない状態になっています。

No Overridesを確認
No Overridesを確認

 

フィールドについてもタイルを配置していきます。今回は山を通行禁止タイルにして移動できないようにする予定です。ちょっと小さくなっていますが、歩ける領域の左下に村、右上に洞窟を配置しています。フィールドでは村から洞窟への移動を行う想定です。山で囲まれていると魔界塔士Sa・Gaみたいなマップですね。

フィールドマップ
フィールドマップ

 

編集後はPrefabの保存をお忘れなく。

 

洞窟のマップの作成

Projectウィンドウから「Assets/Prefabs/Map」のフォルダにて、村用マップのPrefabである「Map_0001_Village」を複製します。名前は [Map_0003_Dungeon] にしました。

Prefabを複製
Prefabを複製

 

Inspectorウィンドウでは「Map Id」の値を [3] に、「Map Name」を [ダンジョン] に変更し、「Encounter Data」に [EncounterData_Dungeon] をアサインします。

洞窟用マップの設定
洞窟用マップの設定

 

作成したPrefabは、村やフィールドのPrefabと同様にHierarchyウィンドウの「Grid」のゲームオブジェクトの下にインスタンス化しましょう。フィールドのPrefabもOverrideがないことを確認して削除しておきます。インスタンス化したゲームオブジェクトにタイルを配置していきましょう。左側の蛇の尻尾みたいな部分が出入り口で、右側の蛇の頭みたいな部分がボス部屋です。宝箱はタイルとしてではなく、個別のゲームオブジェクトとして配置する予定なので、ここではまだ配置しません。

ダンジョンのマップ
ダンジョンのマップ

 

こちらも編集後はPrefabの保存をお忘れなく。

 

通行禁止タイルの設定

山や木など、通行できないタイルを登録していきます。Projectウィンドウから「Assets/Data」のフォルダを開き、「NoEntryTileData」のタイルを選択します。Inspectorウィンドウから通行できないタイルを追加していきましょう。対象は以下の通りです。

  • ダンジョンの壁
  • フィールドの山
  • 村のテーブル
  • 村の木
  • 村の壁

それぞれ対応するタイルをリストに追加します。

通行禁止タイルの設定
通行禁止タイルの設定

 

PrefabをAddressables Groupに登録

作成したマップをロードできるように、Addressables Groupに登録します。村、フィールド、洞窟のマップのPrefabをドラッグ&ドロップして「Map」のGroupに登録しましょう。コンテキストメニューから「Simplify Addressable Names」を選択して名前をシンプルにしたあと、「Labels」のプルダウンで「Map」を選択します。

Addressables Groupへの登録
Addressables Groupへの登録

 

TilemapManagerへのマップのセット

動的にマップを切り替えるため、キャラクターの位置を参照するためのTilemapが変わっていきます。そのため、「MapManager」から「TilemapManager」に対して、現在表示中のマップに対応するTilemapをセットする処理を追加します。自身のマップに対応するTilemapについては、Inspectorウィンドウから設定できるようにしておきます。テスト用のマップを実装するときに気づけば手間を減らせたのでは……?(1敗)

また、「CharacterMover」でも現在のTilemapを参照して位置を取得しているため、それを新しいマップ上の位置に切り替える処理も行います。

 

TilemapManagerの変更

「TilemapManager」では、新しいマップのTilemapをセットできるメソッドを追加します。また、キャラクターが移動先の位置を予約するためのリストもあるので、マップを切り替えたタイミングでこちらをリセットするようにします。

既存のReservePosition()のメソッドの下に2つのメソッドを追加しました。SetTilemaps()のメソッドは新しいマップのTilemapをセットするためのメソッドで、下地、装飾品、オーバーレイの各レイヤーのTilemapを渡して、フィールドにセットするようにしています。

ResetPositions()のメソッドはキャラクターが予約した移動位置をリセットしています。

 

MapControllerの変更

MapControllerで各Tilemapの参照用フィールドを追加します。また、引数のTilemapManagerにその参照を渡す処理も入れておきます。

 

CharacterMoverの変更

「CharacterMover」ではTilemap上の位置を取得する処理について外部から呼び出せるようにしたいと思います。既存のResumeMoving()の下にResetPosition()のメソッドを追加しました。中で呼んでいるGetCurrentPositionOnTilemap()はStart()の中で呼んでいるものです。

 

CharacterMoverManagerの変更

「CharacterMoverManager」では「CharacterMover」で追加したResetPosition()を呼び出すためのメソッドのResetPositions()を追加しました。既存のResumeCharacterMover()の下に入れています。

 

MapManagerの変更

マップ表示時に上で追加した処理を呼ぶようにします。

フィールドとして、「TilemapManager」と「CharacterMoverManager」への参照を保持できるようにします。こちらはInspectorウィンドウからアサインするようにしましょう。

 

既存のShowMap()のメソッドにて、表示した後の処理としてTilemapの設定、Tilemap上の予約位置のリセット、キャラクターが認識しているタイル上の位置をリセットします。

 

参照のアサイン

スクリプトを保存したら、追加したフィールドの参照をアサインします。

「MapManager」では「TilemapManager」と「CharacterMoverManager」への参照をアサインします。

参照のアサイン
参照のアサイン

 

また、マップ用のPrefabについて、それぞれ対応するTilemapのレイヤーをアサインします。Prefabが4つあって大変ですが、それぞれアサインしていきます。

Tilemapのアサイン
Tilemapのアサイン

 

動作確認

スクリプトをアタッチしたら、ゲームを開始して動作を確認します。と、その前に、「MapManager」にて「Game Start Map Id」の値を [1] にしておきます。これで村からスタートするようになります。

開始マップのIDを設定
開始マップのIDを設定

 

マップ内を移動できること、侵入禁止タイルに設定したタイルの上には移動できないことを確認します。フィールドと洞窟に関してはエンカウントする可能性があるので、確認中はエンカウントしないように定義データのチェックを外しておくと楽ちんです。マップを切り替える際には「MapManager」の「Debug Target Map Id」を変更してチェックを入れると切り替えができます。

また、移動速度を上げるならゲームの実行中に「PlayerMover」の「Move Time」の値を減らすと速く移動できます。

巨人の村かな?
巨人の村かな?

 

もしタイルが配置されていない領域が表示される場合は、Prefabにてタイルをさらに広く配置しておくと良いかと思います。私は洞窟のタイルを広げました。

ここまで確認できたら今回は完了です。

 

今回のブランチ

 

まとめ

今回はゲームで使うマップを作成しました。マップを作って動かせる状態になるとRPGっぽさが増してきますね。

次回はメニュー画面の機能を作るにあたって、方針を決めてUI作成に着手します。

 

     

ゲーム開発の攻略チャートを作りました!

CTA-IMAGE

「ゲームを作ってみたいけど、何から手を付けていいか分からない!」


そんなお悩みをお持ちの方向けに、todoがアプリをリリースした経験を中心に、ゲーム作りの手順や考慮すべき点をまとめたe-bookを作成しました。ゲーム作りはそれ自体がゲームのように楽しいプロセスなので、「攻略チャート」と名付けています。


ゲームを作り始めた時にぶつかる壁である「何をしたら良いのか分からない」という悩みを吹き飛ばしましょう!