73
40

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

闇の魔術に対する防衛術Advent Calendar 2018

Day 16

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

Last updated at Posted at 2018-12-21

fmap.gif

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

#🌏チャンク生成🌏
chunk.gif

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

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

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

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

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

コンストラクタ(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

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

#🌏チャンク配置🌏

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 ■■■■
140-150 ■■■■
150-230 ■■■■
230-255 ■■■■

chunk.gif

**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_) 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

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

#🌏岸を複雑にする🌏

ノイズを発生させる
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

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

#🌏完成🌏

fmap.gif

完成です。
"ボロノイ図法"と今回の"チャンク&中点変位法"、
皆さんはどちらがお好きですか?

🌏実装ライブラリ(ソースコード)🌏

今回解説した地形の自動生成は**"Dungeon Template Library""Fractal Island"**として実装されています。
ぜひ、活用してみてください!

logo640.gif
fmap3.gif

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

These codes are licensed under CC0.
CC0

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

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

###関連記事

[DTL]ローグライク自動生成(ローグライク穴掘り法)💀
ローグライクダンジョン生成の記事。

[DTL]地形生成(ボロノイ図法)🌏
ボロノイ図法の地形生成の記事。

73
40
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
73
40

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?