Cooooding!!

Unity(C#)を使ったゲーム開発関連Tipsなど

スクリプトを書かずに無限に広がるマップが作れる『MapMagic』の基本的な使い方【Unity】

概要

少し前にMapMagic World GeneratorというAssetを買いました。
簡単に言えば、スクリプトを書かずにプロシージャルに地形(Terrain)を作ったりその地形の上に木や岩などのオブジェクトを配置できるツールです。あらかじめ決められたルールに従ってランダムに生成されるので無限に広がるマップを作ることができます。

このAssetに含まれているデモではこのようなマップが作られています。
f:id:nyama41:20190519182647p:plainf:id:nyama41:20190519182649p:plain
(その他にもAssetStoreなどで作成例のスクリーンショットや動画が見られます)

このMapMagicの使い方を数日間調べて試してみたのですが、日本語のチュートリアルがなく英語のチュートリアルもわかりにくく苦労したので基本的な使い方の解説を書いてみることにしました。
使い始めたばかりなので間違っている内容も含まれているかもしれません。もし間違いに気付いたらご連絡下さい。

MapMagicの基本的な使い方

MapMagicの機能は大きく分けて「地形の生成」と「オブジェクトの配置」の2つがあります。それぞれを順番に解説しますが まず最初に基本操作だけ説明しておきます。

1.基本操作

新規作成と編集画面の開き方
  1. 新規シーンを作成して開きます
  2. Hierarchyを右クリックして3D Object → Map Magicをクリック
  3. 生成されたGameObject(MapMagic)のInspectorから「Show Editor」を押す
  4. 見やすくなるようにSceneビューのカメラを調整(必要であればMainカメラも)

f:id:nyama41:20190519192335p:plain

編集画面の操作方法
ノードの移動 ノードの上からマウスの左ボタンのドラッグ
全体の移動 ホイールボタンのドラッグ。またはAlt+マウスの左ボタンのドラッグ
ノードの削除 ノードの上で右クリックしてRemoveを押す
ノードの追加 右クリックしてCreateから種類を選択
ノードを繋ぐ 青い〇から青い〇にドラッグ
(後述しますが緑の〇もあります。色の違う〇同士は接続できません)
リンクの切断 ノードの左にある青い〇から何もない場所へドラッグ
Terrainを複数表示する

これ以降の解説ではTerrainを1つだけ表示していますが複数表示することもできます。それぞれのマスで地形が微妙に異なり、隣合うTerrainが綺麗に繋がっていることも確認できます。
f:id:nyama41:20190521002512p:plain
Terrainを表示中の場所を再度クリックすると非表示に戻ります。

変更が反映されないときの対処

グラフを変更してもTerrainやオブジェクトに変更が反映されないことがときどきあります。そういうときはEditor上部の「Force Generate All」を押すと反映されることがあります。
f:id:nyama41:20190521001702p:plain

それでもまだおかしい場合は以下の対処で解決できるかもしれません。

現象 対処方法
地形やオブジェクトのy座標がおかしい Heightノードを追加する
Terrainの色がおかしい Texturesノードを追加する

2.地形の作成

シンプルな地形を作る

新規作成すると既にNoise、Curve、Heightのノードがあり凸凹した地形が生成されていると思います。Curveの説明は後述するので今はCurveを削除してNoiseとHeightを繋ぎましょう。
f:id:nyama41:20190519211408p:plain

Noiseノードは乱数を生成するためのノードで、HeightはTerrainに高さを設定するノードです。Noiseノードのパラメーターを変更すると形が変化します。試しにいろいろ変えて挙動を観察してみましょう。ノード内のテキストボックスに表示されている矢印をドラッグすると変更が簡単です。
f:id:nyama41:20190519201705p:plain
ちなみに、普通のTerrainと同じく高さは一定の範囲に限定されます。Noiseの値が0~1を超えるとClampされます。

乱数(Noise)だけでなくボロノイ分割を使って高さを設定することもできます。

  1. 右クリックして Create → Map → Voronoi を選択
  2. VoronoiノードとHeightノードを繋ぐ

f:id:nyama41:20190519202804p:plain

地形にテクスチャを設定する

次に地形にテクスチャを設定してみます。

  1. 右クリックしてCreate → Output → Texturesを選択
  2. ノードにTerrainLayerを設定

f:id:nyama41:20190519204000p:plain
TerrainLayerはAssets/MapMagic/Demo/TerrainLayersにあるGreenGrassを使っています。

Texturesノードの[+]ボタンを押すともう一つTerrainLayerを設定したり、Noiseなどの出力することができます。

  1. Texturesノードの[+]ボタンを押す
  2. Noiseノードから Texturesノードに追加された青い〇に繋ぐ
  3. (凸凹してるとわかりにくいので)VoronoiノードとHeightノードのリンクを切断

f:id:nyama41:20190519210232p:plain

このとき白く表示される部分がHeightノードでは高く表示され、緑で表示される部分がHeightノードでは低く表示されます。

NoiseノードだけでなくVoronoiノードからTexturesノードに繋ぐこともできます。

地形を変形する

単純にNoiseやVoronoiを出力するだけでなく間にノードを挟むことで形状を変化させることができます。最初に見たCurveノードもその一つです。

  1. 新規シーンでHierarchyを右クリックして 3D Object → Map Magic を押す(新規作成)
  2. Curveノードのグラフをクリックして編集する

f:id:nyama41:20190519212342p:plain

さらに、Invertノードを使うと高さを反転することができます。
f:id:nyama41:20190519213020p:plain

InvertではなくBlurノードを使うとぼけた見た目に(高さの変化がなだらかに)なります。
f:id:nyama41:20190519213543p:plain

Terraceノードを使うと一定間隔ごとに平らな地面を作ることができます。こういう形状の方が使いやすいゲームもありそうです。
f:id:nyama41:20190519214313p:plain

地形のマスク

マスクの説明をする前にまずSimple Formノードの説明をします。以下の図のようにSimple FormノードをHeightノードと繋ぐとコーン型の地形が生成されます。
f:id:nyama41:20190519223608p:plain

このSimple FormをNoiseと一緒に使うと以下のようにコーン型にマスクすることができます。
f:id:nyama41:20190519224256p:plain

Simple Formはコーン型以外の形状にもできるので別の形でマスクすることもできますし、Simple Form以外でも使えるのでNoiseをマスクとしてNoiseを生成することも可能です。

ちなみに、ノードの途中の出力結果を知りたい場合は 青い〇を右クリックして Preview → On Terrain を選択するとTerrain上に色で表示されます。色が赤いほど値が小さく緑に近いほど値が大きくなります。Texturesで出力するより簡単なので便利です。
f:id:nyama41:20190519230307p:plain
この表示を元に戻したいときは Preview → Clear を押します。

その他の機能

その他にも地形の生成に関する機能があるので簡単に紹介します。

ノード名 機能
Blend 複数の出力をAddやOverlayなどの合成方法で混ぜる
Normalize 複数の出力を正規化して出力する
Constant 高さが一定の地形を作る。他のノードと組み合わせて使うことが多い
Intensity/Bias 高低差を強調する
RAW Input 指定された画像で高さを設定する
Shore 指定した高さに境界線を作る。島の海岸を作るときに使う
Erosion 地形が侵食されたような変形をする
Slope どう説明していいのかわからないのでリンク先を参照
Cavity どう説明していいのかわからないのでリンク先を参照

3.オブジェクトの配置

オブジェクトをランダムに配置する

まずは配置するオブジェクト(prefab)を作ります。木や岩のモデルを使ってもいいのですがシンプルな形状の方がわかりやすいと思うのでCylinderを使います。RootのTransformはMapMagicが書き換えることが多いのでEmptyGameObjectにしておいてその子をCylinderにします。また今回は説明用にScaleをかなり大きくします。
f:id:nyama41:20190519232117p:plain

オブジェクトの配置はランダムに座標リストを生成するScatterノードと、指定された座標にオブジェクトを生成するObjectsノードを使います。
f:id:nyama41:20190520003908p:plain

地形が凸凹していてもオブジェクトは地形に沿って生成されます。
f:id:nyama41:20190520004203p:plain
(※ ObjectsのRelative Heightのチェックが外れていると地形に沿わないので注意)

生成するオブジェクトがTree(Terrainで使う木オブジェクト)である場合はObjectsノードではなくTreesノードを使うことができます。Objectsノードとは設定項目が異なりますがその他に何が違うのかはまだよくわかっていません。Treesを試してみたい場合はAssets/MapMagic/Demo/Trees/Pine/PrefabsやAssets/MapMagic/Demo/Trees/Birch/Prefabsにあるprefabが使えます。

生成されるオブジェクトのTransformを変更する

上記の例では全てのオブジェクトが同じサイズでしたがランダムにサイズや姿勢を変えることもできます。
f:id:nyama41:20190520005012p:plain

特定のエリアのみにオブジェクトを生成する

地形の作成でSimple Formをマスクとして使ったようにオブジェクトの生成範囲をマスクすることもできます。
f:id:nyama41:20190520005740p:plain

ここまでの知識を応用してランダムに生成された地形の低い場所ほどオブジェクトが生成されやすくすることもできます。
f:id:nyama41:20190520010921p:plain

森や群れのようなものを生成する

PropagateノードやForrestノードを使うと森や群れのようなものを生成することができます。
f:id:nyama41:20190520211045p:plain

Propagateは単純に増やすだけですが、Forestではサイズ違いのオブジェクトが生成されます。森が広がるように中心ほど大きく、周囲はまばらで小さくなります。最初に作ったprefab(GreenObject)では大きくなりすぎるのでスケールを小さくしたprefabを作って使います。
f:id:nyama41:20190520212204p:plain

生成位置が重ならないようにする

ScatterとObjectsを2つずつ使えば2種類のオブジェクトを生成することもできますが生成位置が重なってしまうことがあります。重なっても違和感がないものであればいいですが岩と木のような組み合わせだとバグに見えてしまいます。
f:id:nyama41:20190520213136p:plain

この問題はSubtractノードを使って解決できます。Subtractは引き算のような処理で Inputに指定された座標からSubtrahendに指定された座標付近のオブジェクトを消します。
f:id:nyama41:20190520214149p:plain

オブジェクト生成位置の土地を平らにする

以下のように凸凹した地形の上にオブジェクトを生成できることは説明済みですが、このオブジェクトが木ではなく宝箱だった場合斜面を転がり落ちてしまうかもしれません。
f:id:nyama41:20190520215302p:plain

この問題はFlattenを使って地面を平らにすれば解決することができます。
f:id:nyama41:20190520215513p:plain

草を生やす

草を生やす場合はScatterやObjectsではなく、GrassノードとNoiseノードなどを組み合わせて実現します。Assets/MapMagic/Demo/Grass以下に草のテクスチャがいくつかあるのでこれで試すことができます。
f:id:nyama41:20190520220957p:plain

その他の機能

その他にもオブジェクトの生成に関する機能があるので簡単に紹介します。

ノード名 機能
Combine 複数の生成位置リストをマージする
Rarefy 生成位置リストの一部を間引く
Clean Up 生成位置のリストにマスクをかける
Slide 生成位置を低い位置にずらす
Stamp 地形生成処理をスタンプのように複数個所に適用する
Split 条件に応じて生成するものを分ける
(はずなんだけど使い方がよくわからなかった…)
Blob 生成位置付近に円を作る

4.その他

グラフを見やすくする

MapMagicにはグラフを見やすくするための機能もいくつかあります。例えば、Portalはリンクが複雑になってしまったのを整理するのに使えます。
f:id:nyama41:20190520232141p:plain

また、Groupはノードのグループ化をすることができます。グループ単位で移動させたり削除したりできます。
f:id:nyama41:20190520232407p:plain

グラフの分割

複雑なマップを作るときにはBiomeを使ってグラフを分割すると見やすくなるかもしれません。まずは1つ目のグラフを作ります。
f:id:nyama41:20190520234804p:plain
f:id:nyama41:20190520235248p:plain
「Exit Biome」を押して元のグラフに戻り、2つ目のグラフを作ります。
f:id:nyama41:20190520235825p:plain
f:id:nyama41:20190520235832p:plain
元のグラフに戻り、以下のように繋ぐと1つ目と2つ目のBiomeを合成することができます。
f:id:nyama41:20190521000432p:plain
1つのグラフの中で全部作るよりだいぶスッキリすると思います。

CustomGenerator

スクリプトが書けるなら新しい種類のノード(Generator)を作ることもできるようです。自分はまだ試していませんがコチラに解説が書かれています。

最後に

もっと複雑なマップを作るには

ここまで解説した内容は基礎だけなので実際にはこれらを組み合わせてもっと複雑なマップを作ることになります。例えばこのAssetに含まれているDemoSceneはこれくらいの複雑さになります。
f:id:nyama41:20190521005041p:plain

ここまでの解説を理解した人ならばそこそこ理解できるのではないかと思いますが、詳しく解説しなかったノードも使われているのでそれらを理解する必要があります。一通りのノードを理解したらDemoSceneのグラフを読み解いてみたり、複雑なマップの解説動画などを見たりして慣れていくことになるかと思います。

また、MapMagicはVoxelandCTSなどと組み合わせて使うこともできるそうなのでこれらと組み合わせることでもっと複雑なマップや綺麗なマップを作れるようになるかもしれません。

MapMagicを使うのに向いてそうなこと、向いてなさそうなこと

MapMagicはとても便利なツールだとは思いますが向き不向きを考えないと逆に苦労することになるかもしれないとは思いました。
例えば、ランダムに生成される迷路を作ろうと思うとどうやってゴールができることを保証するかが問題になると思います。独自のノードを実装すれば不可能ではないと思いますが、そういうことをやり始めると作業コストが増えていきMapMagicの利点が損なわれるかもしれません。
ランダムな宝探しゲームならプレイヤーの移動性能と地形の相性が悪いと全ての宝を取れない可能性があります。プレイヤーがどこへでも移動できるほど性能を高くするか、宝を全て集めなくても問題が発生しない仕様にする必要があるかもしれません。
また、手作業で丁寧に細かく調整したマップと同じレベルのものをMapMagicで作ろうとすると手作業で作ったものほど面白く作れなかったり、面白くできたとしても手作業以上の作業コストがかかるかもしれません。手作業で調整しきれないほど広いマップを作るのであればMapMagicの方が向いていると思います。地形が作りこまれていなくても成立するゲームを考えるというのもアリかもしれません。

MapMagicを有効活用できそうな使い方

MapMagicの有効活用パターンは以下の3つだと思いました。

  1. 非常に広いマップを使うゲームを作る
  2. マップがランダム生成であることを生かしたゲームを作る
    • 不思議なダンジョンのようなゲームや、ランダムマップでの対戦ゲームなど
  3. 試作用にのみ使う
    • (細かいことを気にしなければ)いろんなパターンのマップを大量に素早く作れる
    • デザイナーでなくてもそこそこいい感じのマップが簡単に作れる
    • MapMagicで生成されたマップをベースに手作業で調整するような使い方もできる

自分は3番を主目的として買いました。まだ勉強中であまり活用はできていませんが予想していたよりも汎用性が高く便利そうです。

環境

  • Unity 2018.4.0f1
  • MapMagic 1.10.3