Home / Articles

解說 Roguelike 的地圖生成演算法 的文章圖片

解說 Roguelike 的地圖生成演算法

發布日: 2020/06/02 更新日: 2020/06/10

前言

《Treasure Rogue》 是我製作的一款 Roguelike 遊戲,這篇文章會解說我在其中實作的地圖生成演算法。

Treasure Rogue 會生成縱向較長的地圖,但其基本實作應該也能用在《不可思議的迷宮》風格的地圖生成上。

地圖生成的基本實作

在查看具體實作之前,先來確認整體大致會做哪些處理。

ILevelProcessor

ILevelProcessor 介面會由在地圖生成期間執行處理的類別實作,例如在地圖上生成物件。


public interface ILevelProcessor {

	// Perform some asynchronous processing on the field
	IEnumerator Process (IField field);

}

之後會再說明 ILevelProcessor 的具體實作。

生成地圖的處理

透過迴圈巡覽 ILevelProcessor 的集合,依序呼叫 Process,就能執行生成物件等處理。


public class Field : IField {

	// omitted

	// Function that generates the map
	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 {

	// If too many objects are spawned, the path-securing process (pathfinding) becomes too heavy and freezes the game.
	// So when the number of generated objects exceeds 10, the system does not secure paths.
	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) {
		// The object spawning and path-securing process
		// is long, so it is omitted here.
	}
}

MultiSpawnLevelBuilder 同樣也實作了 ILevelProcessor

4. 生成障礙物

最後生成障礙物。在已確保的路徑上不會生成障礙物。

程式碼與「生成可到達的物件」使用的是同一套。不過因為這裡生成的是障礙物,所以不會執行確保路徑的處理。

結語

以上就是《Treasure Rogue》中使用的地圖生成演算法的基本流程。

只要依照想生成的物件與遊戲規則替換各個 ILevelProcessor,就能在維持相同架構的前提下,套用到各種不同的地圖生成需求。

分享

Twitter