Terrain のチュートリアルをやってみた。

Youtube の Terrain チュートリアルを試してみました。

35分ぐらいの動画ですが、英語がわかる人ならとてもわかりやすいかもと思います。
(自分は英語が全くわかりませんが…、それでも最後までたどり着けたので、とても良いチュートリアルだと思います。 ^^;

 

まずは、Unity の FPSController を使うために Characters をインポートします。

 

つぎに、Plane を作成し、以下のScript を Attach します。

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GenerateTerrain : MonoBehaviour {

	[SerializeField]
	int heightScale = 20;

	[SerializeField]
	float detailScale = 100.0f;


	// Use this for initialization
	void Start () {
		var mesh = this.GetComponent<MeshFilter> ().mesh;
		var vertices = mesh.vertices;

		var pos = this.transform.position;

		for (int v = 0; v < vertices.Length; v++) {
			vertices [v].y = Mathf.PerlinNoise (
				(vertices [v].x + pos.x) / this.detailScale,
				(vertices [v].z + pos.z) / this.detailScale) * this.heightScale;
		}

		mesh.vertices = vertices;
		mesh.RecalculateBounds ();
		mesh.RecalculateNormals ();
		this.gameObject.AddComponent<MeshCollider> ();
	}
	
	// Update is called once per frame
	void Update () {
	}
}

 

ここでいったん実行すると、山が出来てる…!!

 

次の段階は、空のGameObject (名前:LandScape) を配置し、以下の Script を Attach すると、始点から一定距離を移動するたびに無限に作成(不要なのものを削除)するようになりました。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


class Tile {
	
	private GameObject _theTile;
	public GameObject theTile {
		get { return this._theTile; }
		private set { this._theTile = value; }
	}

	private float _creationTime;
	public float creationTime {
		get { return this._creationTime; }
		set { this._creationTime = value; }
	}

	public Tile(GameObject t, float ct) {
		this.theTile = t;
		this.creationTime = ct;
	}
}


public class GenerateInfinite : MonoBehaviour {

	[SerializeField, Tooltip("Plane Prefab")]
	private GameObject plane;

	[SerializeField]
	private GameObject player;


	private int planeSize = 10;
	//ループ回数 (10 x 2) * (10 x 2) -> 400
	private int halfTilesX = 10;
	private int halfTilesZ = 10;

	private Vector3 startPos = Vector3.zero;

	Hashtable tiles = new Hashtable();


	// Use this for initialization
	void Start () {
		this.gameObject.transform.position = Vector3.zero;
		this.startPos = Vector3.zero;

		float updateTime = Time.realtimeSinceStartup;

		for (int x = -this.halfTilesX; x < this.halfTilesX; x++) {
			for (int z = -this.halfTilesZ; z < this.halfTilesZ; z++) {
				
				var pos = new Vector3 (
					          (x * this.planeSize + this.startPos.x),
					          0,
					          (z * this.planeSize + this.startPos.z));
				
				var t = Instantiate (this.plane, pos, Quaternion.identity) as GameObject;


				var tileName = string.Format ("Tile_{0}_{1}", (int)(pos.x), (int)(pos.z));
				t.name = tileName;

				var tile = new Tile (t, updateTime);
				tiles.Add (tileName, tile);
			}
		}
	}
	
	// Update is called once per frame
	void Update () {
		var playerPos = this.player.transform.position;
		int xMove = (int)(playerPos.x - this.startPos.x);
		int zMove = (int)(playerPos.z - this.startPos.z);

		//移動量
		if ((Mathf.Abs (xMove) >= this.planeSize) ||
		    (Mathf.Abs (zMove) >= this.planeSize)) {

			float updateTime = Time.realtimeSinceStartup;

			int playerX = (int)(Mathf.Floor (playerPos.x / this.planeSize) * this.planeSize);
			int playerZ = (int)(Mathf.Floor (playerPos.z / this.planeSize) * this.planeSize);

			for (int x = -this.halfTilesX; x < this.halfTilesX; x++) {
				for (int z = -this.halfTilesZ; z < this.halfTilesZ; z++) {
					
					var pos = new Vector3 (
						          (x * this.planeSize + playerX),
						          0,
						          (z * this.planeSize + playerZ));
					
					var tileName = string.Format ("Tile_{0}_{1}", (int)(pos.x), (int)(pos.z));

					if (!this.tiles.ContainsKey(tileName)) {
						
						var t = Instantiate( this.plane, pos, Quaternion.identity) as GameObject;
						t.name = tileName;

						var tile = new Tile(t, updateTime);
						this.tiles.Add(tileName, tile);
					} else {
						//creationTime更新 -> 削除しない
						(this.tiles[tileName] as Tile).creationTime = updateTime;
					}
				}
			}

			//不要になるTileを削除、使用するタイルを新しいHashtableに格納
			var newTerrain = new Hashtable ();
			foreach (Tile tile in this.tiles.Values) {
				
				if (tile.creationTime != updateTime) {
					Destroy (tile.theTile);
				} else {
					newTerrain.Add (tile.theTile.name, tile);
				}
			}

			//Hashtable更新
			this.tiles = newTerrain;

			//始点を現在位置に更新
			this.startPos = this.player.transform.position;
		}
	}
}

 

最後に、遠くの方をぼやかす感じの設定をしました。

まずは、Windows – Lighting – Setting を選択し、Fog の Color と Density を設定します。

 

次に、MainCamera を削除し (もしくはEnableのチェックを外し)、FPSController プレハブにある FirstPersonCharacter の Camera の BackColor を Fog の Color に合わせます。

 

結果はこんな感じです。

HTML5に出力してみました。
マウスで視点調整、方向キーで前後左右移動します。(マウスのカーソルをゲーム画面から外すには Escキー を押してください。)


One Comment

Add a Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です