地形生成(チャンク&中点変位法)🌽

![fmap.gif](https://qiita-image-store.s3.amazonaws.com/0/213065/91b23e83-57d1-c4fa-3d34-06afb961be26.gif)

世界を創成する闇魔術について解説します。
**今回はチャンクを用いた中点変位法(フラクタル)アルゴリズムを使用します。**

#🌏チャンク生成🌏
![chunk.gif](https://qiita-image-store.s3.amazonaws.com/0/213065/9b0d3391-44d4-3ef5-b622-135d3ccc7d16.gif)

チャンク生成で世界の鱗片を生成します。
今回は16マス×16マスのチャンクを生成しています。

#🌏フラクタル島生成クラス🌏

フラクタルの作成と島生成を行うFractalIslandクラスを作成します。

```cpp:クラス名
namespace dtl {
	template<typename Int>
	class FractalIsland;
}
```

**dtl(Dungeon Template Library)名前空間**に作成します。

```cpp:コンストラクタ(public)
constexpr explicit FractalIsland(STL_& world_map, std::size_t seed_ = 0, const std::int_fast32_t max_value_ = 255) {
	create(world_map, seed_, max_value_);
}
```

コンストラクタから生成関数を呼び出します。

![fmap_b.png](https://qiita-image-store.s3.amazonaws.com/0/213065/136bd3be-c141-0968-1357-91aef93960ff.png)


ひとまず導入する準備が出来ました。
次は**チャンクを配置して島を作ります。**

#🌏チャンク配置🌏

```cpp:worldMapMake関数
constexpr void worldMapMake(const std::size_t x_, const std::size_t y_, const std::size_t size_, const std::size_t t1_, const std::size_t t2_, const std::size_t t3_, const std::size_t t4_, std::array<std::array<Int_, 17>, 17>& map_, const std::size_t max_value_);
```

|標高|名前|色|
|:---|:---|:---|
|0-140|海|**<font color="#2363b2">■■</font>青<font color="#2363b2">■■</font>**|
|140-150|岸|**<font color="#a79f45">■■</font>黄<font color="#a79f45">■■</font>**|
|150-230|陸|**<font color="#359e44">■■</font>緑<font color="#359e44">■■</font>**|
|230-255|山|**<font color="#cccbce">■■</font>白<font color="#cccbce">■■</font>**|

![chunk.gif](https://qiita-image-store.s3.amazonaws.com/0/213065/9b0d3391-44d4-3ef5-b622-135d3ccc7d16.gif)

**`worldMapMake関数`**でチャンクを生成します。
標高は再起して割り出します。
標高を元に地形を生成します。

```cpp:チャンク生成関数
constexpr void worldMapMake(const std::size_t x_, const std::size_t y_, const std::size_t size_, const std::size_t t1_, const std::size_t t2_, const std::size_t t3_, const std::size_t t4_, std::array<std::array<Int_, 17>, 17>& map_, const std::size_t max_value_) const noexcept {
	if (size_ == 0) return;
	const std::size_t vertex_height{ ((t1_ + t2_ + t3_ + t4_) / 4) + static_cast<std::size_t>(2)(rnd((std::int_fast32_t)size_)) };
	map_[x_][y_] = ((vertex_height >= max_value_) ? (Int_)max_value_ : (Int_)vertex_height);
	const std::size_t s1{ ((t1_ + t2_) / 2) };
	const std::size_t s2{ ((t1_ + t3_) / 2) };
	const std::size_t s3{ ((t2_ + t4_) / 2) };
	const std::size_t s4{ ((t3_ + t4_) / 2) };
	map_[x_ + size_][y_] = static_cast<Int_>(s3);
	map_[x_ - size_][y_] = static_cast<Int_>(s2);
	map_[x_][y_ + size_] = static_cast<Int_>(s4);
	map_[x_][y_ - size_] = static_cast<Int_>(s1);
	const std::size_t& size{ size_ / static_cast<std::size_t>(2) };
	worldMapMake(x_ - size, y_ - size, size, t1_, s1, s2, map_[x_][y_], map_, max_value_);
	worldMapMake(x_ + size, y_ - size, size, s1, t2_, map_[x_][y_], s3, map_, max_value_);
	worldMapMake(x_ - size, y_ + size, size, s2, map_[x_][y_], t3_, s4, map_, max_value_);
	worldMapMake(x_ + size, y_ + size, size, map_[x_][y_], s3, s4, t4_, map_, max_value_);
}
```

![roll.gif](https://qiita-image-store.s3.amazonaws.com/0/213065/c96629a3-802b-8d13-b943-1258e8b10c77.gif)

**チャンクを貼り付けてワールドを構築します。**

#🌏岸を複雑にする🌏

```cpp:ノイズを発生させる
namespace dtl {
	template<typename STL_>
	constexpr void noiseShoreBool(STL_& stl_, const double rbool_) noexcept {
		for (std::size_t i{ 1 }; i < stl_.size(); ++i)
			for (std::size_t j{ 1 }; j < stl_[i].size(); ++j) {
				if (!rnd.randBool(rbool_) || (stl_[i][j] == stl_[i][j - 1] && stl_[i][j] == stl_[i - 1][j])) continue;
				if (stl_[i][j]) stl_[i][j] = false;
				else stl_[i][j] = true;
			}
	}
}
```

岸の部分を**`noiseShoreBool関数`**によって削り出します。

![fshima.png](https://qiita-image-store.s3.amazonaws.com/0/213065/563ae925-3651-e302-6c78-32088a8f0004.png)

この生成法では、画面の端を意図的にループさせることが可能です。
また、この手法により**"マインクラフト"**のようなほぼ無限の大きさを持つワールド生成を作り出すことが出来ます。

#🌏完成🌏

![fmap.gif](https://qiita-image-store.s3.amazonaws.com/0/213065/91b23e83-57d1-c4fa-3d34-06afb961be26.gif)

完成です。
**["ボロノイ図法"](https://qiita.com/Gaccho/items/08710de2c57da912b822)と今回の"チャンク&中点変位法"、**
皆さんはどちらがお好きですか？

# [🌏実装ライブラリ(ソースコード)🌏](https://github.com/Kasugaccho/DungeonTemplateLibrary)

今回解説した地形の自動生成は**["Dungeon Template Library"](https://github.com/Kasugaccho/DungeonTemplateLibrary)**に**["Fractal Island"](https://github.com/Kasugaccho/DungeonTemplateLibrary/blob/master/README.md)**として実装されています。
ぜひ、活用してみてください！

[![logo640.gif](https://qiita-image-store.s3.amazonaws.com/0/213065/b84a7834-2042-6704-fbbe-782a31f06091.gif)](https://github.com/Kasugaccho/DungeonTemplateLibrary)
[![fmap3.gif](https://qiita-image-store.s3.amazonaws.com/0/213065/e6c37710-4048-1379-244e-34d224fd7ab0.gif)
](https://github.com/Kasugaccho/DungeonTemplateLibrary)

#🌏ソースコードのライセンス🌏

These codes are licensed under CC0.
[![CC0](https://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg "CC0")](http://creativecommons.org/publicdomain/zero/1.0/deed.ja)

この記事のソースコードはCC0ライセンスとします。
ぜひ、自由に改変して遊んでみてください。

**最後までお読みいただきありがとうございました！**

###関連記事

[[DTL]ローグライク自動生成(ローグライク穴掘り法)💀](https://qiita.com/Gaccho/items/253cb6af577ec11e79cf)
ローグライクダンジョン生成の記事。

[[DTL]地形生成(ボロノイ図法)🌏](https://qiita.com/Gaccho/items/08710de2c57da912b822)
ボロノイ図法の地形生成の記事。