はじめに
『TreasureRogue』というローグライクゲームを作ったので、その際に実装したマップ生成アルゴリズムについて解説します。
『TreasureRogue』は縦長のマップを生成しますが、基本的な実装は「不思議のダンジョン」系のマップ生成にも使えると思います。
マップ生成の基本的な実装
具体的な実装を見る前にまず、大まかにどういった処理を行っているかを確認しておきましょう。
ILevelProcessor
ILevelProcessorインターフェースは「マップにオブジェクトを生成する」など、マップ生成時の処理をするクラスに実装します。
public interface ILevelProcessor {
// fieldに何かしらの非同期処理を行う
IEnumerator Process (IField field);
}
ILevelProcessorの具体的な実装については、後ほど解説します。
マップを生成する処理
ILevelProcessorのコレクションをループで回し、Process関数を順番に呼ぶことで、オブジェクト生成などの処理を行います。
public class Field : IField {
// 省略
// マップ生成を行う関数
IEnumerator GenerateInternal () {
m_IsGenerating.Value = true;
yield return GenerateField();
foreach (ILevelProcessor processor in Processors) {
yield return processor.Process(this);
}
m_IsGenerating.Value = false;
}
}
マップ生成の具体的な実装
どういう処理をしているかをザックリと把握したところで、具体的にどういう実装をしているかを解説していきます。
1.マップの土台を生成
まずマップの土台を生成します。
2.経路を確保する
ランダムでオブジェクトを配置していると、プレイヤーが通ることのできないマップが生成される可能性があるので、まずは「オブジェクトを生成できない位置」を決めておきます。
実際のコード
[SerializeField]
public class SecurePathProcessor : ILevelProcessor {
public static SecurePathProcessor Instance { get; } = new SecurePathProcessor();
public IEnumerator Process (IField field) {
yield return FieldManager.Instance.GraphUpdate();
yield return field.SecurePath(to: new Vector3Int(
Random.Range(0,field.Bounds.size.x),
0,
field.Bounds.zMax
));
}
}
SecurePathProcessorはILevelProcessorを実装しています。つまり、マップ生成時のループでProcess関数が呼ばれることになります。
SecurePath関数では「fieldに登録されているプレイヤー」から「指定した位置」までランダムな経路を生成し、その経路にはオブジェクトが生成されないようになります。
3.アクセス可能なオブジェクトを生成
あとは「アクセス可能なオブジェクト(敵や宝箱)」と「障害物」を生成するだけなのですが、まずはアクセス可能なオブジェクトから生成します。
障害物が生成される前に、「アクセス可能なオブジェクト」への経路を確保する必要があるからです。
実際のコード
[Serializable]
public class MultiSpawnLevelBuilder : ILevelProcessor {
// オブジェクト生成数が多いと、経路の確保処理(経路探索)が重すぎてフリーズする。
// なので生成数が10を超えるときは経路の確保を行わない。
const int k_SecurePathAcceptableQuantity = 10;
[SerializeField]
FieldObject m_Prefab;
[SerializeField]
FieldObjectQuantitiy m_Quantity = new FieldObjectQuantitiy(1);
[SerializeField]
bool m_SecurePath;
public IEnumerator Process (IField field) {
// オブジェクトを生成して、オブジェクトへの経路を確保する処理
// 長いので省略
}
}
MultiSpawnLevelBuilderも同じく、ILevelProcessorを実装しています。
4.障害物を生成
最後に障害物を生成します。確保した経路には障害物は生成されません。
コードは「アクセス可能なオブジェクトを生成」と同じものを使用しています。ただし、経路の確保処理は行いません。(障害物なので)
以上でマップ生成の解説は終わりです。
ピンバック: 【ローグライク】ランダムで敵を選出して生成する【C#】 | Makihiroのdevlog