| ホーム |
フィールドマップ自動生成プログラム
" フェッセンデンが死ぬと、その肉は大地となり、流れ出た血は海となった。
赤血球からはバクテリア、白血球からはユーカリオート、血小板からはアーキアが生まれた。
頭蓋は天蓋となり、右目は太陽、左目は月と呼ばれるようになった。ニューロンは空にて輝く恒星となり、グリア細胞は暗黒物質となった。脳溝は天に張り付く背景放射となって今日もその名残を留める。
これが世界の始まりのあらましである。 "






RPGの地上マップのようなものを自動で作成するプログラムを作ってみました。ここからダウンロード出来ます。
プログラムの流れは、
<陸と海>、山、砂漠、森といった地形の作成
↓
高低差を考慮しながら水を流し、河川を作る
という風になっています。
基本的な地形作成のアルゴリズムですが、格子状に区切られ、0と1の状態変数を持つ各領域が周辺の状態を参照しつつ、自身の状態を変化させる、というのを数十から数百タイムステップの間繰り返します。ライフゲームのような、いわゆるセルオートマトンですね。……セルとオートまでは何となく分かりますが、マトンはあんまり関係ないような。ロイン卿のようなものでしょうか。
具体的には、周辺のセルの状態を調べ、ある状態のセルの個数に対応する確率でそのセルに変化します。
例えば、周辺に状態0のセルが
0個の時 → 0%の確率で状態0になる、100%の確率で状態1になる
1個の時 → 10%の確率で状態0になる、 90%の確率で状態1になる
2個の時 → 20%の確率で状態0になる、 80%の確率で状態1になる
3個の時 → 20%の確率で状態0になる、 80%の確率で状態1になる
4個の時 → 50%の確率で状態0になる、 50%の確率で状態1になる
5個の時 → 80%の確率で状態0になる、 20%の確率で状態1になる
6個の時 → 80%の確率で状態0になる、 20%の確率で状態1になる
7個の時 → 90%の確率で状態0になる、 10%の確率で状態1になる
8個の時 → 100%の確率で状態0になる、 0%の確率で状態1になる
といった感じです。
下の図は、一番左が完全にランダムな初期状態、右に行くに従い、上記の処理を1回、5回、10回、30回、60回、100回繰り返したものとなっています。ちなみに、外周は常に海(黒)になるようにしています。

徐々にパターンが出来ていく過程がみてとれるかと思います。流れをみれば分かるように、初期の複雑な地形が時間が経つに連れて単純化してゆきます。長時間放置した場合、画面中央に殆ど凹凸の無い巨大な大陸が一つ出来ることになります。このため、欲しい地形ができる時間で計算を止める必要があります。
出来上がった地図に対し、小さな飛び地を削除して全体を均してやると基本的な陸と海の地図ができます。
アルゴリズムの出典ですが、森林動態学における、ニッチの似通った樹木種が離散空間分布をとる過程のシミュレーションの結果の図を目にした時に、フィールドマップ生成に使えるのではないかと思いついて今回プログラムを作ってみました。
陸と海が出来た後は山を作ります。アルゴリズム的には上記とほぼ同じで、一点違うのは海と決定されたセルは常に「非山」の状態をとるというところです。これによって海岸線沿いは「非山」の勢力が優勢になり、陸地の奥に山があるような配置が実現されます。
次に砂漠ですが、これも山と同様に海と決定されたセルは常に「非砂漠」の状態をとらせています。このため、山と砂漠は重なることが比較的多くなっています。
森についてですが、これは防砂林やマングローブなどの例もあることですし、海沿いぎりぎりまで来ていても別にいいか、ということで、森地形作成の段階では海が「非森」の状態をとるようにはしていません。最終的には海にかかっている森の領域は削除しますが、海岸線から森の塊が遠ざけられることはなくなります。
また、砂漠と森が接しているのは個人的に違和感があったため、既に砂漠と決定している部分に関しては常に「非森」の状態をとるようにしています。このため、ナウシカにでてくるような森から突如砂漠に出るような地形は基本的に作られなくなっています。
以上で基本となる地形の配置が終わりました。RPGっぽくするには沼や毒の沼なんかもあった方がいいかとも思いましたが、今回は地形の種類はこの程度としておきました。
次に、河川作成のアルゴリズムです。
河川を作るに先立って、まず各セルの持つ海抜を決定します。
最初に、海に面している全ての土地に海抜1を振ります。次に、海に面しておらず、かつ海抜1の土地に接している全ての土地に海抜2を振ります。更に、海と海抜1の土地に接しておらず、かつ海抜2の土地に接している全ての土地に海抜3を振ります。……と、これを繰り返すことで全ての陸地にあるセルに海抜を設定します。

また、地形生成でせっかく作った山地が海抜と無関係というのも何ですので、山地に設定されたセルに関しては海抜を2倍にしてやります。
最後に、全体を平均化し、滑らかにしてやって海抜の設定は終わりです。
続いて、河川の基点を求めます。今回は、あるセルから見て周囲のセル全てが自分よりも海抜が低い時、そこをピークとみなし、そのセルから河川が発生することにしました。
河川の作成の仕方ですが、まず先ほど求めたピークに仮想的な水を置きます。水は基本的には今居るセルの周辺にある一番海抜の低いセルに向かって流れていき、水が移動する際に通過したセルを河川として設定することにします。海に流れ込む、もしくは既に作られた河川に合流するまで水を流し続け、条件を満たせばそれで一つの河川作成の終了です。これを各ピークに対して実行してゆきます。
以上のアルゴリズムに従って河川を作成した場合、基本的に河川はピークから海への最短距離を通りながら直線的に流れます。それでは面白くないため、海抜のピークを求めた後、適当に海抜をランダムに上下させてやると、高くなった部分を避け、低くなった部分に流れ込むなどして川が曲がりながら流れることになります。ちなみに、ピークを求める前にランダム化を行うと、無数のピークが発生し川だらけになるため順序には注意が必要です。
以上でフィールドマップ生成は終了です。出来上がった地形を表示して終わりなのですが、地形とマップチップを一対一で表示するのではなく、標高が一定以上の場合山地、一定以下の場合丘、丘は特にオーバーラップする地形が無いものと丘と砂漠・丘と森がそれぞれオーバーラップしたものと、ある程度の条件分けをして表示させています。
以下、四方山話。
今回のプログラム作成にかかった手間ですが、基本的な地形の生成部分が大体1日、河川の生成が1週間、画面表示が1月くらいかかっています。
画面表示は適当なマップチップを探したのですが、表示しようとしている地形の組み合わせに適合するものが無く、結局ドット打ちからはじめることになりました。また、主に山地と丘についてなのですが、異なる地形が隣り合った際に両者が繋がっている感じにしようと思って表示方法を考えていたのですが、手作業でやるにはパターンが多くなりすぎたため、2種類より多い地形が互いに接する部分の表示をどうするかで大分時間を食いました。さらに、後述しますが知見も無いのにマップチップ作成を見切り発車したしたせいで、プログラム的にかなり面倒な処理をする必要がでてきてしまっています。
河川の生成に関してですが、当初は「あらゆる土地に一定の雨量が降る →各土地の水は地下水となり近隣で最も低い土地に流れる →地下水としての収容限界を超えた水は河川として地上に現れる」という、現実に近いアルゴリズムを考えていたのですが、あまり「それっぽい」感じにならないため、作成原理の物理的な適切さよりもゲーム的リアリティを優先して現在のようなかたちで河川の生成を行うこととしました。
今回のプログラムでやり残したことなど。
ソースを見て頂けると分かるのですが、河川の基点となる海抜ピークの最大個数が100個になっているのがまず問題です。今回はマップ全体のサイズが200×200ということで、ピークの数はこの辺でいいだろうと思い設定したのですが、もしマップサイズの拡張など行おうとした場合、直接的に誤作動の原因となることが予想されます。本当ならばピーク個数を算出した上で動的メモリ確保など行うべきだったとは思うのですが、その辺の勉強不足のため、今回は上限を設けて配列を作ってしまいました。
また、マジックナンバーがプログラム内に点在しているのも問題だとは思うのですが、除去する手間をとるよりは放置することにしてしまいました。
地形の生成に関してですが、セルの変化確率と周囲のある状態のセルの個数の関係は任意に設定できます。
0~3個の時 → 0%の確率で状態0になる、100%の確率で状態1になる
4個の時 → 50%の確率で状態0になる、 50%の確率で状態1になる
5~8個の時 → 100%の確率で状態0になる、 0%の確率で状態1になる
などの場合、陸と海の境界が滑らかで、微妙な凹凸がほとんど無い状態になります。逆に、
0個の時 → 0%の確率で状態0になる、100%の確率で状態1になる
1~3個の時 → 40%の確率で状態0になる、 60%の確率で状態1になる
4個の時 → 50%の確率で状態0になる、 50%の確率で状態1になる
5~7個の時 → 60%の確率で状態0になる、 40%の確率で状態1になる
8個の時 → 100%の確率で状態0になる、 0%の確率で状態1になる
のように、周囲の傾向に逆らう可能性を大きくとることもできますが、この場合は微細な地片と池があちこちに出来ては消えを繰り返す感じで安定した地形は現れません。この変化確率についてはまだ検討の余地がありそうです。
また、今回はセルの元の状態がどうであれ、周囲の状態の影響のみで次の時間ステップでの状態が決まっています。外部からの影響に加え、元々のセルの状態が変化確率に関与するようなアルゴリズムも考えられますが、まあ今回はそれ無しでもそれなりのものが出来たということで組み込んでいません。
出来上がったマップの表示に関しては大分苦闘したのですが、それでも色々と悔いが残っています。
まず最初に、自作のマップチップがあまり取り回しが良くない事があります。
マップチップの境界の整合性ですが、基本的にセルを上下左右に4分割し、それぞれが自分に隣接するセルを見て決めています。

ところが、今回作った山地のマップチップでは、左下(右下)をみて作られたパーツが左上(右上)にはみ出してしまっています。

このため、セルの左上(右上)部分を描画するために本来ならば無視してよい真下や斜め下のセルも監視する必要があり、面倒臭い上に組み合わせパターンが膨大になってしまいました。
普通、世間で流通しているマップチップはメインの山の間にサブの山が挟まりこむような感じになっていますが、それにはこうした訳があった事を知りました。
また、本当は緯度や標高を使って雪山や寒帯林、熱帯雨林などを作ろうと思っていたのですが、組み合わせパターンが更に膨大になるため断念しました。平地や森も一種類だと寂しいのでもう少し色違いや模様違いなどのパターンもランダムで入るようにしようかと思っていましたが、これも同様の理由でペンディングです。
最後に、このプログラムを流用したゲームのアイディアなのですが、
・自作ローグライクの地上マップ
・半熟英雄+ダイスウォーズ的なゲーム
・複数のヒューマノイドの国家と何頭かのドラゴンが互いに争ったりしつつ栄枯盛衰を繰り返すのを眺める環境ゲーム
の3つを今のところ考えていますが、作成の目処は立っていません。
まあ、5年以内にどれか1つものになればいいなー、くらいの感じです。
赤血球からはバクテリア、白血球からはユーカリオート、血小板からはアーキアが生まれた。
頭蓋は天蓋となり、右目は太陽、左目は月と呼ばれるようになった。ニューロンは空にて輝く恒星となり、グリア細胞は暗黒物質となった。脳溝は天に張り付く背景放射となって今日もその名残を留める。
これが世界の始まりのあらましである。 "
RPGの地上マップのようなものを自動で作成するプログラムを作ってみました。ここからダウンロード出来ます。
プログラムの流れは、
<陸と海>、山、砂漠、森といった地形の作成
↓
高低差を考慮しながら水を流し、河川を作る
という風になっています。
基本的な地形作成のアルゴリズムですが、格子状に区切られ、0と1の状態変数を持つ各領域が周辺の状態を参照しつつ、自身の状態を変化させる、というのを数十から数百タイムステップの間繰り返します。ライフゲームのような、いわゆるセルオートマトンですね。……セルとオートまでは何となく分かりますが、マトンはあんまり関係ないような。ロイン卿のようなものでしょうか。
具体的には、周辺のセルの状態を調べ、ある状態のセルの個数に対応する確率でそのセルに変化します。
例えば、周辺に状態0のセルが
0個の時 → 0%の確率で状態0になる、100%の確率で状態1になる
1個の時 → 10%の確率で状態0になる、 90%の確率で状態1になる
2個の時 → 20%の確率で状態0になる、 80%の確率で状態1になる
3個の時 → 20%の確率で状態0になる、 80%の確率で状態1になる
4個の時 → 50%の確率で状態0になる、 50%の確率で状態1になる
5個の時 → 80%の確率で状態0になる、 20%の確率で状態1になる
6個の時 → 80%の確率で状態0になる、 20%の確率で状態1になる
7個の時 → 90%の確率で状態0になる、 10%の確率で状態1になる
8個の時 → 100%の確率で状態0になる、 0%の確率で状態1になる
といった感じです。
下の図は、一番左が完全にランダムな初期状態、右に行くに従い、上記の処理を1回、5回、10回、30回、60回、100回繰り返したものとなっています。ちなみに、外周は常に海(黒)になるようにしています。
徐々にパターンが出来ていく過程がみてとれるかと思います。流れをみれば分かるように、初期の複雑な地形が時間が経つに連れて単純化してゆきます。長時間放置した場合、画面中央に殆ど凹凸の無い巨大な大陸が一つ出来ることになります。このため、欲しい地形ができる時間で計算を止める必要があります。
出来上がった地図に対し、小さな飛び地を削除して全体を均してやると基本的な陸と海の地図ができます。
アルゴリズムの出典ですが、森林動態学における、ニッチの似通った樹木種が離散空間分布をとる過程のシミュレーションの結果の図を目にした時に、フィールドマップ生成に使えるのではないかと思いついて今回プログラムを作ってみました。
陸と海が出来た後は山を作ります。アルゴリズム的には上記とほぼ同じで、一点違うのは海と決定されたセルは常に「非山」の状態をとるというところです。これによって海岸線沿いは「非山」の勢力が優勢になり、陸地の奥に山があるような配置が実現されます。
次に砂漠ですが、これも山と同様に海と決定されたセルは常に「非砂漠」の状態をとらせています。このため、山と砂漠は重なることが比較的多くなっています。
森についてですが、これは防砂林やマングローブなどの例もあることですし、海沿いぎりぎりまで来ていても別にいいか、ということで、森地形作成の段階では海が「非森」の状態をとるようにはしていません。最終的には海にかかっている森の領域は削除しますが、海岸線から森の塊が遠ざけられることはなくなります。
また、砂漠と森が接しているのは個人的に違和感があったため、既に砂漠と決定している部分に関しては常に「非森」の状態をとるようにしています。このため、ナウシカにでてくるような森から突如砂漠に出るような地形は基本的に作られなくなっています。
以上で基本となる地形の配置が終わりました。RPGっぽくするには沼や毒の沼なんかもあった方がいいかとも思いましたが、今回は地形の種類はこの程度としておきました。
次に、河川作成のアルゴリズムです。
河川を作るに先立って、まず各セルの持つ海抜を決定します。
最初に、海に面している全ての土地に海抜1を振ります。次に、海に面しておらず、かつ海抜1の土地に接している全ての土地に海抜2を振ります。更に、海と海抜1の土地に接しておらず、かつ海抜2の土地に接している全ての土地に海抜3を振ります。……と、これを繰り返すことで全ての陸地にあるセルに海抜を設定します。
また、地形生成でせっかく作った山地が海抜と無関係というのも何ですので、山地に設定されたセルに関しては海抜を2倍にしてやります。
最後に、全体を平均化し、滑らかにしてやって海抜の設定は終わりです。
続いて、河川の基点を求めます。今回は、あるセルから見て周囲のセル全てが自分よりも海抜が低い時、そこをピークとみなし、そのセルから河川が発生することにしました。
河川の作成の仕方ですが、まず先ほど求めたピークに仮想的な水を置きます。水は基本的には今居るセルの周辺にある一番海抜の低いセルに向かって流れていき、水が移動する際に通過したセルを河川として設定することにします。海に流れ込む、もしくは既に作られた河川に合流するまで水を流し続け、条件を満たせばそれで一つの河川作成の終了です。これを各ピークに対して実行してゆきます。
以上のアルゴリズムに従って河川を作成した場合、基本的に河川はピークから海への最短距離を通りながら直線的に流れます。それでは面白くないため、海抜のピークを求めた後、適当に海抜をランダムに上下させてやると、高くなった部分を避け、低くなった部分に流れ込むなどして川が曲がりながら流れることになります。ちなみに、ピークを求める前にランダム化を行うと、無数のピークが発生し川だらけになるため順序には注意が必要です。
以上でフィールドマップ生成は終了です。出来上がった地形を表示して終わりなのですが、地形とマップチップを一対一で表示するのではなく、標高が一定以上の場合山地、一定以下の場合丘、丘は特にオーバーラップする地形が無いものと丘と砂漠・丘と森がそれぞれオーバーラップしたものと、ある程度の条件分けをして表示させています。
以下、四方山話。
今回のプログラム作成にかかった手間ですが、基本的な地形の生成部分が大体1日、河川の生成が1週間、画面表示が1月くらいかかっています。
画面表示は適当なマップチップを探したのですが、表示しようとしている地形の組み合わせに適合するものが無く、結局ドット打ちからはじめることになりました。また、主に山地と丘についてなのですが、異なる地形が隣り合った際に両者が繋がっている感じにしようと思って表示方法を考えていたのですが、手作業でやるにはパターンが多くなりすぎたため、2種類より多い地形が互いに接する部分の表示をどうするかで大分時間を食いました。さらに、後述しますが知見も無いのにマップチップ作成を見切り発車したしたせいで、プログラム的にかなり面倒な処理をする必要がでてきてしまっています。
河川の生成に関してですが、当初は「あらゆる土地に一定の雨量が降る →各土地の水は地下水となり近隣で最も低い土地に流れる →地下水としての収容限界を超えた水は河川として地上に現れる」という、現実に近いアルゴリズムを考えていたのですが、あまり「それっぽい」感じにならないため、作成原理の物理的な適切さよりもゲーム的リアリティを優先して現在のようなかたちで河川の生成を行うこととしました。
今回のプログラムでやり残したことなど。
ソースを見て頂けると分かるのですが、河川の基点となる海抜ピークの最大個数が100個になっているのがまず問題です。今回はマップ全体のサイズが200×200ということで、ピークの数はこの辺でいいだろうと思い設定したのですが、もしマップサイズの拡張など行おうとした場合、直接的に誤作動の原因となることが予想されます。本当ならばピーク個数を算出した上で動的メモリ確保など行うべきだったとは思うのですが、その辺の勉強不足のため、今回は上限を設けて配列を作ってしまいました。
また、マジックナンバーがプログラム内に点在しているのも問題だとは思うのですが、除去する手間をとるよりは放置することにしてしまいました。
地形の生成に関してですが、セルの変化確率と周囲のある状態のセルの個数の関係は任意に設定できます。
0~3個の時 → 0%の確率で状態0になる、100%の確率で状態1になる
4個の時 → 50%の確率で状態0になる、 50%の確率で状態1になる
5~8個の時 → 100%の確率で状態0になる、 0%の確率で状態1になる
などの場合、陸と海の境界が滑らかで、微妙な凹凸がほとんど無い状態になります。逆に、
0個の時 → 0%の確率で状態0になる、100%の確率で状態1になる
1~3個の時 → 40%の確率で状態0になる、 60%の確率で状態1になる
4個の時 → 50%の確率で状態0になる、 50%の確率で状態1になる
5~7個の時 → 60%の確率で状態0になる、 40%の確率で状態1になる
8個の時 → 100%の確率で状態0になる、 0%の確率で状態1になる
のように、周囲の傾向に逆らう可能性を大きくとることもできますが、この場合は微細な地片と池があちこちに出来ては消えを繰り返す感じで安定した地形は現れません。この変化確率についてはまだ検討の余地がありそうです。
また、今回はセルの元の状態がどうであれ、周囲の状態の影響のみで次の時間ステップでの状態が決まっています。外部からの影響に加え、元々のセルの状態が変化確率に関与するようなアルゴリズムも考えられますが、まあ今回はそれ無しでもそれなりのものが出来たということで組み込んでいません。
出来上がったマップの表示に関しては大分苦闘したのですが、それでも色々と悔いが残っています。
まず最初に、自作のマップチップがあまり取り回しが良くない事があります。
マップチップの境界の整合性ですが、基本的にセルを上下左右に4分割し、それぞれが自分に隣接するセルを見て決めています。
ところが、今回作った山地のマップチップでは、左下(右下)をみて作られたパーツが左上(右上)にはみ出してしまっています。
このため、セルの左上(右上)部分を描画するために本来ならば無視してよい真下や斜め下のセルも監視する必要があり、面倒臭い上に組み合わせパターンが膨大になってしまいました。
普通、世間で流通しているマップチップはメインの山の間にサブの山が挟まりこむような感じになっていますが、それにはこうした訳があった事を知りました。
また、本当は緯度や標高を使って雪山や寒帯林、熱帯雨林などを作ろうと思っていたのですが、組み合わせパターンが更に膨大になるため断念しました。平地や森も一種類だと寂しいのでもう少し色違いや模様違いなどのパターンもランダムで入るようにしようかと思っていましたが、これも同様の理由でペンディングです。
最後に、このプログラムを流用したゲームのアイディアなのですが、
・自作ローグライクの地上マップ
・半熟英雄+ダイスウォーズ的なゲーム
・複数のヒューマノイドの国家と何頭かのドラゴンが互いに争ったりしつつ栄枯盛衰を繰り返すのを眺める環境ゲーム
の3つを今のところ考えていますが、作成の目処は立っていません。
まあ、5年以内にどれか1つものになればいいなー、くらいの感じです。
スポンサーサイト
トラックバック
| ホーム |