Unity Create a Game Series (E12. finishing the map generator)をやってみました。

引き続き、「Unity Create a Game Series」をやりマップの自動生成の作業が完了し、第7回までに作ったトップダウンシューティングゲームに組み込みました。

マップ自動生成をゲームに組み込んだところ
マップ自動生成をゲームに組み込んだところ

今回の第12回は、障害物に高低差を付け、グラデーションを付けれるようにしました。高低差はScaleで変更できるのが容易に想像できますが、Materialをプログラムから操作するのは少ないので、このチュートリアルで扱えてよかったです。また、今回は、Game.unityシーンに、MapGeneratorのオブジェクトをコピーペーストしてゲームに反映させました。MapGenerator.unityはシーンとして独立して保存しているのでいろいろ修正が可能です。

002
Unityエディターで、各マップを設定できるようにしている

MapGeneratorスクリプトには、Mapクラスを作り、その配列をUnityエディターから操作できるようにしたので、ちょっとしたマップの修正を検証するのが簡単になりました。

マップ自動生成の基礎プログラミングを手に入れた

様々なパラメータを修正できる
様々なパラメータを修正できる

今回まで一番の収穫は、プロシージャル・ジェネレーションの基礎を学習できたことです。ローグライク系ゲームのように、フロアを自動生成するような仕組みに作り替えたりはまだできませんが、それをするためのメッシュ生成や配列操作などは学べました。

このプロジェクトの配布

http://hajimete-program.com/games/Unity Create a Game Series (E12. finishing the map generator).zip

Unity Create a Game Series (E11. map navigation)をやってみました。

Unityのナビゲーション・探索システムでは、フィールドにBake(焼く)ことで、NavMeshAgentがそのフィールドを移動でき、NavMeshObstacle(障害物)を用意することで、その領域を移動できなくします。

ナビゲーションの設定は1つ1つのタイルに対して行うのではなく、1つ大きな100×100などのQuadを用意して、そこにBakeします。ちょうど以下のような感じです。NavMeshObstacleコンポーネントが付加されているオブジェクト移動できなくなるため、灰色になり、移動できるところは水色になります。

002
フィールドの外側に最大マップ領域を作ってNavMeshAgentが移動できるようにする

このままでもよいですが、今回は最大領域から落ちたりしないように、四方をマスキングしました。

003
NavMeshObstacleでマスキングして、移動できないようにする

まとめ

マップを自動生成して、NavMeshAgentが移動できるようになったのであとは細かい修正を残すだけとなりました。

Unity Create a Game Series (E10. map connectivity)をやってみました。

Sebastian LagueさんのUnity5チュートリアル「Create a Game (Unity 5)」の
Unity Create a Game Series (E10. map connectivity)をやってみました。

このチュートリアルは、第8回になる「E08. tile map」からは今までのプロジェクトと独立していて、第8回からでもチュートリアルとして始められるようになっています。主なテーマは、マップ生成です。

Unityエディターで様々なマップを自動生成
Unityエディターで様々なマップを自動生成

E08,E09,E10と作業して、上記のような自動生成ができるようになりました。マップ生成は複雑に感じますが、実際にはライフゲーム、倉庫番、テトリスのような二次元配列を使い、隣接するXY要素の衝突判定やフラグ判定を行うときと基本的な仕組みは同じでした。またマップの場合は、道が途切れ内容にする方法が必要ですが、これは、アルゴリズムとして確立していてFlood Fillアルゴリズムを使いました。と言ってもやっているとは簡単で、中心をまず調べ、その隣接する障害物じゃないものを調べ続けるという事再帰的に繰り返していくだけです。

マップが二次元配列になっているので、以下が成り立ちます。

マップ全体の要素数 – 壁の数 = 通れるタイルの数

実際の例に置き換えると、以下のようになります。

10×10のマップ(100要素) – 10個の障害物 = 90個の通れるタイル

よって、Flood Fillアルゴリズムで、通れる道を調べたときに、90個に達しなければどこかの道が壁でおおわれていることになります。この仕組みを、壁を作るときに応用し、壁を作ってみて、その時点で、Flood Fillで道を調べふさがってしまったら、壁をいったん取り消すということを、壁の最大個数にするまで繰り返しマップを作ります。

 

このプロジェクトの配布

http://hajimete-program.com/games/Unity Create a Game Series (E10. map connectivity).zip

まとめ

マップ自動生成の基本部分はできたので、あとはUnityのNavigation対応と、壁などの装飾を残すだけです。1回の動画時間は20分以内ですが、一時停止し細かいロジックを理解するとなると1時間を超える作業になるので、思っている以上に時間がかかり大変です。

4.プロシージャルジェネレーションの動画チュートリアルに挑戦

今回は動画で打ち込んだだけでは動作せず、githubのソースコードと比較してどうにか動かしました。

A04

前回までに、XZ平面に壁を描画したので、今回は洞窟が立体になるように、Y軸に伸びる壁を作成しました。

002

求める方法としては、まだ調べていない頂点1を起点として、隣接する頂点2を調べ、それが上記画像のように、二つの三角形で使われているかどうか調べます。もし使われていなければ、アウトラインエッジ(外周の辺)になります。外周であれば、その辺に続く頂点は、また外周の続きになるので、これを再帰的に調べ上げて、一周し頂点1にたどり着くまでおこないます。

上記を求めるために、動画3までに作成したXZ平面に対して、三角形の一覧情報を保持しなければならないためこの動画4でTriangle構造体を用意しました。

そのため今までのSquareGridのほかにTriangleリストや,Outlineリストが出てきて、描画はインデックスバッファーであることなど、たくさんの状態があるので、注意深く追っていく必要がありました。

英語力不足のせいもあり、わからないところとしては左手座標と描画順を変更したところです。方向を合わせるのはわかりますが、なぜ頂点がその順序になるのかがわかりませんでした。ソースコード上にTODOなどを記述して、先に進めるようにしました。

どのぐらいユーザーが脱落しているか

Youtubeのチュートリアル動画だと、閲覧数が見えるのでどのぐらいの人が1動画ごとに脱落するかわかります。

  • E01 – 53,500再生
  • E02 – 23,400再生
  • E03 – 18,500再生
  • E04 – 17,200再生
  • E05 – 12,600再生
  • E06 – 9,200再生
  • E07 – 9,500再生
  • E08 – 10,400再生
  • E09 – 15,200再生

全9回で、見てみると初回のE01を試しに視聴して難しいと感じ、半数になります。E02からE03で5000再生減り、E04からE05でまた5000再生減っています。ユニークユーザーではないかもしれませんが動画の性質上、かなり特定のユーザーが意図的に見る動画なので、次回E5を乗り越えれば最後まで完走できそうです。

https://github.com/SebLague/Procedural-Cave-Generation

 

まとめ

OpenGLやDirectXでメッシュをプログラムで書いているのと同じなので大変でした。何とか最終章までこぎつけたいです。

3.プロシージャルジェネレーションの動画チュートリアルに挑戦

2.プロシージャルジェネレーションの動画チュートリアルをやってみます ではスクエア構造内に座標8個を保持する構造を用意してまとめました。今回はその情報をもとに、実際に頂点情報、インデックス情報を用意して、プログラムからメッシュを作成しました。動画内で特に説明はありませんでしたが、インデックスバッファーを使った描画のため、OpenGLやDirectXで三角形を描画した経験がないとかなり分からなくなると感じました。

UnityのMeshFilterとMesh Renderer

002

ちょっと動作を試す場合は、プリミティブなキューブやスフィアオブジェクトにマテリアルを付けて試しますが、実際にスクリプトでMeshを作成すると、細かい仕組みがわかりました。Unityはメッシュ情報をMesh Filterが持ち、Mesh Rendererがそれを描画するという、2つのコンポーネント(部品)で成り立っています。

そのため、スクリプトでメッシュを作成する場合は、new Meshでメッシュオブジェクトを作成し、MeshFilter.meshに割り当てます。普段インスペクターでMesh Filterを気にすることはなかったのですが、ちゃんと確認すると、Mesh Filterはmeshを持っていて、Cube meshを参照しています。

データ構造をしっかり確認しておく

003

このチュートリアルでは、スクエアの角4つと、中点の4つ、で、角はコントロールノードで有効無効があり、そこに依存する子ノードとして、中点4つがあります。このデータ構造で、例えば、上記の図の場合、E4とB2が有効の時、4つの三角形が作れます。このデータ構造をしっかり理解することでソースコードがわかるようになります。データ構造を把握しないと、コードを見ただけでは分かりづらいです。

このプロジェクトの配布

http://hajimete-program.com/games/Procedural%20Cave%20Generation%20E03.zip

2.プロシージャルジェネレーションの動画チュートリアルをやってみます

プロシージャル洞窟生成のYoutube動画チュートリアルの二回目をやってみました。今回は、二次元配列をそのまま描画するのではなく、二次元配列から4点を取り(=コントロール・ノード)、各線の中間に点を取り(=センター・ノード)、各頂点に対して、キューブを生成するようになりました。またセンター・ノードのほうは若干小さなキューブを描画するようにしました。

ソースコード解説

このソースコードは下のメソッドから見るとよいです。

  1. 頂点であるXYZ座標を保持するNodeクラスを定義
  2. 自身のNodeと、上と右に隣接するNodeを保持するControlNodeクラスの定義
  3. 4つのControlNode(=4つの頂点座標)を四角形としてまとめるSquareクラスの定義

上記の頂点XYZはNodeクラス、隣接する頂点も管理するControlNode、それを4つに束ねたSquareクラス、このデータ構造を踏まえて、あとは入力された二次元配列が、xy座標を持つので、そこからSquareの二次元配列を作っているだけです。データ構造をしっかり頭に入れていると、SquareGridで生成している部分のコードもすんなり読めるようになります。

このプロジェクトの配布

 

http://hajimete-program.com/games/Procedural%20Cave%20Generation%20E02.zip

 

 

Unity5の洞窟、ダンジョン生成チュートリアル動画の紹介

洞窟やダンジョンは自分で地道に作成するのもよいですが、Unityでは自動生成するアセットや作成方法のチュートリアルが豊富にあるので紹介します。

セルオートマトン(Cellular Automata)の基礎から入っていくチュートリアルです。ライフゲームを作ったことがある人はすんなり入っていくことができます。ライフゲームの仕組みを応用すると洞窟やダンジョンが作れるのがとても驚きです。最初の動画を試してみましたが、単純に生成アルゴリズムなのでUnityだけではなく別の言語やシステムでも使える技術をわかりました。様々な場面で応用できそうです。

Unity公式でも「Basic 2D Dungeon Generation」というチュートリアルがありました。こちらは1時間の動画なのでこちらのほうが学びやすそうです。この動画ではよくあるローグライク系の部屋を生成する方法が学べるようです。

POSTDの記事「手続き型のダンジョン生成アルゴリズム」もダンジョン生成の仕組みを調べるとっかかりになりそうです。