U
タブ 04世界とゲームループ7 レッスン — タップで開く
01 / 07 · 10 分
世界とゲームループ

地形と風景

ここまでのプロジェクト

Assets/

Scenes/

Arena.unity
FloorBlocks (parent)KnightTerrain

Scripts/

TerrainPlacer.cs

Prefabs/

Knight prefabEnemy.prefab

Materials/

terrain layers

all your scripts

すでにあるものこのレッスンで追加

Arena.unity はまだ、キャラクターが入った灰色の箱のままです。このタブではその周りに世界を作ります——すでにあるアリーナの周囲を、置き換えるのではなく。

  1. 1

    Assets/Scenes/Arena.unity を開いてください——タブ 01 から使い続けている同じファイルです。新しいシーンは作らないで:床もブロックもキャラクターも敵もカメラリグも、そのまま全部残します。

  2. 2

    何も触る前に Play を押します。Knight がタブ 03 の最後と同じように歩き、跳び、スキルを撃つはずです。

  3. 3

    何も作り直さないでください。Play を押して歩き回れないなら、丘を一つ作る前にそれを直しましょう。

Terrain は heightmap に駆動される単一の最適化メッシュです。丘を手でモデリングする代わりに、ブラシで高さを書いていきます。

アニメーション図

ブラシが heightmap を持ち上げると、下のメッシュが付いていきます。

Terrain を作る

  1. 1

    GameObject▸3D Object▸Terrain。原点に 1000×1000 m の平面が現れます。

  2. 2

    一つのアリーナには大きすぎます。Terrain Settings の歯車で Terrain Width と Length を 200 にします。

  3. 3

    Heightmap Resolution は 513、Detail Resolution は 512——小さいレベルなら十分で、ずっと軽くなります。

  4. 4

    Terrain を -100, -0.05, -100 に置きます。中心がアリーナの下に来、面はタブ 01 の床のわずかに下にあるので、二つが重なってチカチカすることはありません。

ツールバーの 5 つのツール

  • Raise or Lower Terrain——左クリックで持ち上がり、Shift + 左クリックで下がる。大きく柔らかいブラシを低い Opacity から始めましょう。

  • Set Height——クリックすると範囲全体が正確な高さで平らになります。建設向きの台地はこれで作ります。

  • Smooth Height——ブラシが残したギザギザのノイズをならします。何度も使うことになります。

  • Paint Texture——地面マテリアルのレイヤー:草、岩、砂、道。

  • Paint Trees と Paint Details——木は Prefab、ディテールは草のビルボードです。

レイヤーを描く

  1. 1

    Paint Texture → Edit Terrain Layers → Create Layer。最初のレイヤーは Terrain 全体を覆います。

  2. 2

    各レイヤーの Tiling Size は 8〜15 m。既定の 2 だと繰り返しが丸見えになります。

  3. 3

    岩のレイヤーを足して急な斜面にだけ描き、小さく硬いブラシで道のレイヤーを追加します。

  4. 4

    モバイルでは最大 4 レイヤー。レイヤーが増えるほど 1 ピクセルあたりの texture サンプルが増えます。

木と草と風

  • Terrain ツールで描いた木は、遠くだと自動的にビルボード化——Prefab を手で置いていくよりずっと安上がりです。

  • Terrain Settings で Tree Distance を 120 ほど、Billboard Start を 60 ほどにします。

  • 草は Detail Mesh か Grass texture。Detail Distance はデスクトップで 40、モバイルでは 20 以下。

  • Wind Zone(GameObject > 3D Object > Wind Zone)を使うと木や草が揺れます。レベル全体に 1 つで十分。

コードから地形の高さを読む

place anything on the ground
using UnityEngine;

public class TerrainPlacer : MonoBehaviour
{
    [SerializeField] private GameObject prefab;
    [SerializeField] private int count = 60;
    [SerializeField] private float area = 90f;

    void Start()
    {
        Terrain terrain = Terrain.activeTerrain;

        for (int i = 0; i < count; i++)
        {
            float x = Random.Range(-area, area);
            float z = Random.Range(-area, area);

            // exact ground height at that world position
            float y = terrain.SampleHeight(new Vector3(x, 0f, z)) + terrain.transform.position.y;

            Quaternion rot = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
            Instantiate(prefab, new Vector3(x, y, z), rot, transform);
        }
    }
}