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

前回の続き。

 

Terrain の上に 木を配置するチュートリアルをやってみました。

Planeの生成時に配置する木は、あらかじめ生成しておいた中からプーリングして使い回す…という内容です。

 

木のプーリングは 新たに “TreePool” という GameObject を配置し、以下のScriptをアタッチします。

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

//using System.Linq;


public class TreePool : MonoBehaviour {

	static int numTree = 1000;

	static GameObject[] trees;


	[SerializeField]
	GameObject treePrefab;


	// Use this for initialization
	void Awake () {

		TreePool.trees = new GameObject[TreePool.numTree];
		for (int i = 0; i < TreePool.trees.Length; i++) {

			var tree = Instantiate (this.treePrefab, Vector3.zero, Quaternion.identity) as GameObject;
			tree.SetActive (false);

			TreePool.trees [i] = tree;
		}
	}


	static public GameObject getTree() {

//		//LINQ 例 (Terrainのつなぎ目がおかしくなる...原因はわからない)
//		var count = TreePool.trees.Count (t => !t.activeSelf);
//		if (count > 0) {
//			var tree = TreePool.trees.First(t => !t.activeSelf);
//			return tree;
//		}
//
//		return null;

		for (int i = 0; i < TreePool.trees.Length; i++) {
			var tree = TreePool.trees [i];
			if ((tree != null) && (!tree.activeSelf)) {
				return tree;
			}
		}

		return null;
	}
}

LINQ を使ってみたかったのですが、Terrain のつなぎ目がおかしくなるので、やめました。^^;
(LINQの使いどころを勉強中です… ^^;;;

 

Planeの生成の変更点は、新たに”植林”が増えた処理です。

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

public class GenerateTerrain : MonoBehaviour {

	[SerializeField]
	int heightScale = 10;

	[SerializeField]
	float detailScale = 10.0f;

	//自分の所に植林した木
	List<GameObject> myTrees = new List<GameObject>();


	// 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;
			//Debug.Log (vertices [v].y);

			//植林
			if ((vertices [v].y > 2.6f) &&
				(Mathf.PerlinNoise((vertices[v].x+5)/10, (vertices[v].z+5)/10)*10 > 4.6f) &&
				((Random.Range(0, 1000) % 100) == 0)
			) {
				
				var newTree = TreePool.getTree ();
				if (newTree != null) {
					
					var treePos = new Vector3 (
										(vertices [v].x + this.transform.position.x),
									 	(vertices [v].y),
										(vertices [v].z + this.transform.position.z));

					newTree.transform.position = treePos;
					newTree.SetActive (true);

					myTrees.Add (newTree);
				}
			}
		}

		mesh.vertices = vertices;
		mesh.RecalculateBounds ();
		mesh.RecalculateNormals ();
		this.gameObject.AddComponent<MeshCollider> ();
	}


	void OnDestroy() {

		//自分のところに植林した木を見えなくする
		for (int i = 0; i < this.myTrees.Count; i++) {
			var tree = this.myTrees [i];
			if (tree != null) {
				tree.SetActive (false);
			}
		}

		this.myTrees.Clear ();
	}

	
	// Update is called once per frame
	void Update () {
	}
}

Plane 生成時に プールからオブジェクトを参照して SetActive(true) にし、Plane破棄のときに、自分が植林した分を SetActive(false) にするポイントが、なるほどーと思いました。
わかっているようで、結局こういう実装をゼロからできていないので、やっぱり経験不足感を実感してます… ^^;;

 

木が浮いてしまう…のは、どうしたらいいかわからなかったですww ^^;

 

余談ですが…
動画のチュートリアルを試している時、MacBookAirではPlaneの生成するタイミングで処理が重くてカクカクする感じの原因が、まさか Debug.log だと思わず…無駄に実装を追求してましたが…勉強になりました。^^;

 

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


Add a Comment

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