メインコンテンツまでスキップ

グリッドベースの移動システム

MCE は、Unity の Tilemap を土台にしたタイルベースのグリッド移動システムを使います。プレイヤーと NPC は離散的なグリッド上を 1 タイルずつ移動し、衝突判定、地形効果、マップ間の遷移はグリッドシステムが処理します。

1 歩がどう解決されるか

プレイ中のグリッド

プレイヤーは常にちょうど 1 つのタイル上にいます。半歩も、タイル内の位置もなく、 だからこそエンカウント、衝突、マップ間の遷移が、近似ではなく確定的に判定できます。

コアコンポーネント​

GridController​

GridController は、タイルグリッドのシーンごとのマネージャーです。Unity の Grid と同じ GameObject 上にあり(Grid が必須)、次のことを行います。

  • シーンの Tilemap を見つけ、ソート順の高いものから低いものへ、それらをまたいでタイルへの問い合わせに答える。
  • プロジェクトの TileData アセットから各タイルの移動タイプを読み取る(カスタムタイルタイプ を参照)。
  • グリッドに登録されているキャラクターとアクターを追跡する。
  • シーンの SceneInfo を保持する(後述)。
  • 衝突の問い合わせに答える:キャラクターはこのタイルへ、このタイルから移動できるか?

各マップシーンには、グリッドのルートに 1 つの GridController があります。

MCECharacterController​

MCECharacterController は、グリッド上の任意のキャラクター(プレイヤー、NPC、モンスター)の移動を扱います。

  • グリッドにスナップした移動:キャラクターは 1 歩につきちょうど 1 タイル移動します。
  • 4 方向の移動:上、下、左、右。斜め移動はありません。
  • スプライトの描画:スプライトの向きと歩行アニメーションを更新します。
  • 衝突チェック:移動のたびに GridController に問い合わせます。
  • 移動速度:Speed、1 タイルあたりの秒数(デフォルトは 0.25)。

PlayerCharacter​

PlayerCharacter は、コントローラーの上にプレイヤー固有の機能を追加します。

  • 入力処理(キーボードとゲームパッド)。
  • インタラクションのトリガー(NPC/オブジェクトを向いてアクションボタンを押す)。
  • 野生エンカウントの処理、むしよけの歩数、歩数カウンター(GlobalGameData.StepsTaken。タマゴのサイクルとなつき度も駆動します)。
  • 走る、自転車、泳ぐ。
  • フォロワーモンスターの連携とエモートのホットキー。

GlobalGridManager​

GlobalGridManager はマップ間のナビゲーションを扱います。

  • ロード済みのグリッドの一覧を保持し、ワールド座標にタイルを持つグリッドを見つけます。これによりキャラクターはあるマップから隣のマップへ歩いて行けます。
  • 現在のマップの隣接マップと、さらにその隣接マップ(2 ホップの深さ)を加算的にロードするため、中間のマップを横切っても、来たマップはアンロードされません。
  • キャラクターがあるグリッドから別のグリッドへ渡るとき、プレイヤーを引き継ぎます。

タイルタイプ​

すべてのタイルアセットには、TileData アセットで割り当てられる移動タイプ(TileType)があります。

TileType説明
NonExistentタイルにデータがない。空白として扱われる
Walkable通常の地面
NonWalkable固体の障害物(壁、木、岩)
Jumpable段差:一方向にジャンプして越える
Bridge橋の表面。下にあるものの上に重なる
BridgeEntrance地面と橋の間の遷移タイル
Water渡るには泳ぐ必要がある水
Waterfall登れる垂直の水
Slippery氷:障害物にぶつかるまでキャラクターが滑る
WalkableNotBikable徒歩では歩けるが、自転車では通れない

タイプに加えて、タイルの挙動(タイルのプレハブ上のコンポーネント)がロジックを追加します。EncounterTile は野生エンカウントゾーンを示し、OneWayJumpableTile は段差の向きを設定し、ForceCharacterToKeepMoving はベルトコンベアや海流を作り、ほかに TallGrass、LadderUp、WaterfallEdge、WhirlwindInDirection などがあります。すべてカスタムタイルタイプで説明されています。

マップの設定​

ステップ 1:Tilemap 構造を作る​

MCE のマップは、標準的な Unity の Tilemap 階層を使います。

Grid (Grid + GridController)
└── Ground (Tilemap, TilemapRenderer, sorting order 0)
└── GroundOverlay (Tilemap, TilemapRenderer, sorting order 1)
└── Above ... (more Tilemaps as needed)
└── Actors (NPC GameObjects)

ペイントすべき別個の衝突用タイルマップはありません。移動を妨げるのは、ペイントしたタイルの TileType です。

ステップ 2:マップをペイントする​

マップエディターのオーバーレイ、または Unity の Tile Palette(Window > 2D > Tile Palette)でマップをペイントします。

  1. Ground レイヤー:基本の地形(道、草、土、水辺)。
  2. オーバーレイレイヤー:地面の上の装飾(花、岩、影)と、プレイヤーの上に描かれるもの(木の枝葉)。
  3. エンカウントタイル:野生モンスターが出現する、プレハブに EncounterTile を持つタイル。

ステップ 3:GridController を追加する​

  1. Grid のルート GameObject を選択します。
  2. GridController コンポーネントを追加します。
  3. コントローラーは依存性注入でプロジェクトの TileData アセットを受け取ります。ペイントしたすべてのタイルが、正しい TileType でそこに登録されていることを確認してください(アセットの Populate と CheckInvalid ボタンが役立ちます)。登録されていないタイルは歩行可能として扱われ、警告が記録されます。

ステップ 4:SceneInfo を設定する​

各マップシーンには、SceneInfoAsset を指す SceneInfo コンポーネントが必要です(Hub の Database タブの New Scene Info で作成)。そのコンポーネントを GridController の Scene Info フィールドに割り当てます。アセットには次のものが入ります。

フィールド説明
Sceneこの情報が説明するシーン
Localizable Name Key場所の表示名(ヘッダーに表示)
Neighbours / Neighbour Offsetsこのマップに接続するマップと、その位置(タイル単位。シームレスな行き来)
Background Musicこのマップの音楽
Is Affected By Sky、Default Weather、Allowed Weathers昼夜の光と天候
Can Open Storage Here、Can Fly From Here、Can Teleport From Here、Can Escape Rope From Here、Can Fish Hereここでプレイヤーができること
Is Dungeon、Is Darkダンジョンのマップは、すべてのタイルで Cave エンカウントを使う
Region、Tags地方と、ゲームロジックで使うシーンタグ(たとえば「Cave」「Town」「Route」)
Encounters、Battle Scenarios Per Encounter、Own Encounter Chancesマップの野生エンカウント:野生エンカウント を参照

特殊な地形​

橋​

橋を使うと、通常は通れないタイル(水など)の上をキャラクターが歩けます。

  1. 橋には、より高いソート順のタイルマップレイヤーを使います。
  2. 橋のタイルには Bridge タイプを、橋に乗り込むタイルには BridgeEntrance を設定します。
  3. キャラクターは橋に乗ると、橋のレイヤー上を歩きます。

橋のロジックが Z オーダーを処理します -- キャラクターは水より上、橋の欄干より下に描画されます(OverBridgeBodySortOrder)。

滑るタイル(氷)​

氷のタイルでは、キャラクターは壁や氷ではないタイルにぶつかるまで、移動している方向に滑ります。

  1. 氷のタイルに Slippery タイプを設定します。
  2. MCECharacterController が入力を上書きして、移動方向を続けます。
  3. 壁や障害物を加えて、氷のパズルのレイアウトを作ります。

段差​

段差は一方通行のタイルです -- キャラクターは飛び降りられますが、登って戻ることはできません。

  1. タイルに Jumpable タイプを設定し、そのプレハブに OneWayJumpableTile の挙動を追加します。
  2. その Jump Direction を設定します。
  3. キャラクターが段差を越えるときに、ホップのアニメーションが再生されます。

滝​

滝は、適切な能力で登れます。

  1. 滝のタイルに Waterfall タイプを設定します(端には WaterfallEdge が使えます)。
  2. プレイヤーが滝に向かって登る能力を使うと、キャラクターが上昇します。

マップ間の遷移​

シームレスな接続​

直接つながるマップ(1 番道路が北端で 2 番道路に続く、など)では、それぞれのマップを相手の Neighbours に列挙し、位置を決める Neighbour Offsets(タイル単位)を設定します。GlobalGridManager が隣接マップを加算的にロードし、キャラクターは単にあるグリッドから別のグリッドへ歩いて渡ります。現在のグリッドに目的の位置のタイルがなければ、マネージャーがそれを持つロード済みのグリッドを探します。隣接マップのタイルが壁(NonWalkable)または空白(NonExistent)であれば、やはりその一歩は阻まれます。

ワープ(ドア、洞窟、テレポート)​

プレイヤーを別の場所に移動させるには:

  1. ドアや入口のタイルに TriggerActor を置きます(TriggerActor は移動を妨げず、プレイヤーが踏み込むとグラフを実行します)。
  2. その CommandGraph に、行き先をシーンの場所(行き先の SceneInfoAsset とタイル)として指定した TeleportPlayer ノードを追加します。オンライン時は、サーバーがまずテレポートを検証します。
  3. 必要に応じて、OpenDoor、FadeScreenToBlack、サウンドを周囲に加えて、遷移を演出します。

インポートしたマップでは、インポーターのシーン統合がワープを配置します。

プレイヤーの移動設定​

移動速度はキャラクターの Speed フィールドで、1 タイルあたりの秒数です(デフォルトは 0.25、つまり 1 秒に 4 タイル)。キャラクターの状態により、1 タイルあたりの時間が変化します。

状態1 タイルあたりの時間の倍率
歩行1
走る(IsRunning)0.33
自転車(IsBiking)0.15
泳ぐ(IsSwimming)0.66
ジャンプホップは 1 歩の時間の 1.5 倍で再生される

歩数カウンター(GlobalGameData.StepsTaken)は 1 歩ごとに進み、タマゴのサイクルやなつき度のティックを駆動します。

モンスターフォロワー​

MCE は、プレイヤーのパーティの先頭のモンスターがオーバーワールドで後ろを歩くフォロワーシステムに対応しています。

  • MonsterFollowerController がフォロワーの位置とスプライトを管理します。
  • フォロワーはプレイヤーの 1 タイル後ろにとどまり、カットシーンの後で追いつきます。
  • フォロワーのスプライトは、種とフォームごとに MonsterEntry(WorldIdleSprite* と WorldWalkingSprite* のフィールド)で設定します。
  • プレイヤーはフォロワー(向かい合ってアクションボタンを押す)と交流して反応を見られます。インポートしたゲームは独自のトークテーブルを持てて、フォロワーは感情バルーンを表示できます。
フォロワースプライト

モンスターの種にオーバーワールド用のフォロワースプライトが割り当てられていない場合、フォロワーは表示されません。フォロワーのスプライトシートを、4 方向の歩行サイクルシートとして手動で作成してください。

ベストプラクティス​

  1. タイルタイプを一貫させる。ペイントしたすべてのタイルを TileData に登録し、同じ種類の地形には同じタイプを使います。
  2. ワープの接続を両方向でテストする。A から B へ行けて、B から A へ戻れることを確認します。
  3. ロジックにはシーンタグを使う。マップ名をハードコードする代わりに、マップに「Cave」「Water」「Forest」などのタグを付けます。
  4. 大きなマップを最適化する。非常に大きなタイルマップはパフォーマンスに影響します。Neighbours で接続した複数のシーンに分割することを検討してください。
  5. ゲームパッドでテストする。グリッド移動は、キーボードでもコントローラーでも反応よく感じられるべきです。