using UnityEngine; using System.Collections.Generic; using System.Linq; namespace Gaia { /// /// A class to manage tree instances on unity terrain /// public class TreeManager { #pragma warning disable 414 private List m_terrainTrees = new List(); private Quadtree m_terrainTreeLocations = new Quadtree(new Rect(0,0, 10f, 10f)); #pragma warning restore 414 /// /// Load the trees in from the terrain /// public void LoadTreesFromTerrain() { //Destroy previous contents m_terrainTrees = null; m_terrainTreeLocations = null; //Work out the bounds of the environment float minY = float.NaN; float minX = float.NaN; float maxX = float.NaN; float minZ = float.NaN; float maxZ = float.NaN; Terrain sampleTerrain = null; foreach (Terrain terrain in Terrain.activeTerrains) { if (float.IsNaN(minY)) { sampleTerrain = terrain; minY = terrain.transform.position.y; minX = terrain.transform.position.x; minZ = terrain.transform.position.z; maxX = minX + terrain.terrainData.size.x; maxZ = minZ + terrain.terrainData.size.z; } else { if (terrain.transform.position.x < minX) { minX = terrain.transform.position.x; } if (terrain.transform.position.z < minZ) { minZ = terrain.transform.position.z; } if ((terrain.transform.position.x + terrain.terrainData.size.x) > maxX) { maxX = terrain.transform.position.x + terrain.terrainData.size.x; } if ((terrain.transform.position.z + terrain.terrainData.size.z) > maxZ) { maxZ = terrain.transform.position.z + terrain.terrainData.size.z; } } } if (sampleTerrain != null) { Rect terrainBounds = new Rect(minX, minZ, maxX - minX, maxZ - minZ); m_terrainTreeLocations = new Quadtree(terrainBounds, 32); m_terrainTrees = new List(sampleTerrain.terrainData.treePrototypes); foreach (Terrain terrain in Terrain.activeTerrains) { float terrainOffsetX = terrain.transform.position.x; float terrainOffsetZ = terrain.transform.position.z; float terrainWidth = terrain.terrainData.size.x; float terrainDepth = terrain.terrainData.size.z; TreeInstance[] terrainTreeInstances = terrain.terrainData.treeInstances; for (int treeIdx = 0; treeIdx < terrainTreeInstances.Length; treeIdx++) { TreeInstance treeInstance = terrainTreeInstances[treeIdx]; m_terrainTreeLocations.Insert(terrainOffsetX + (treeInstance.position.x * terrainWidth), terrainOffsetZ + (treeInstance.position.z * terrainDepth), terrainTreeInstances[treeIdx].prototypeIndex); } } } } /// /// Add a tree instance into storage - must be called after the initial load call /// /// /// public void AddTree(Vector3 position, int prototypeIdx) { if (m_terrainTreeLocations == null) { return; } m_terrainTreeLocations.Insert(position.x, position.z, prototypeIdx); } /// /// Return the number of trees within range of the location provided /// /// Location to check /// Range around location to check /// Number of trees within range public int Count(Vector3 position, float range) { if (m_terrainTreeLocations == null) { return 0; } Rect query = new Rect(position.x - range, position.z - range, range * 2f, range * 2f); return m_terrainTreeLocations.Find(query).Count(); } /// /// Return the number of trees being managed /// /// Number of trees being managed public int Count() { if (m_terrainTreeLocations == null) { return 0; } return m_terrainTreeLocations.Count; } } }