using UnityEngine; using System.Collections; using System; using System.Threading; using System.Collections.Generic; using UnityEditor.UI; public class MapGenerator : MonoBehaviour { public enum DrawMode {NoiseMap, Mesh, FalloffMap}; public DrawMode drawMode; public TerrainData terrainData; public NoiseData noiseData; public TextureData textureData; public Material terrainMaterial; [Range(0,6)] public int editorPreviewLOD; public bool autoUpdate; float[,] falloffMap; Queue> mapDataThreadInfoQueue = new Queue>(); Queue> meshDataThreadInfoQueue = new Queue>(); void OnValuesUpdated() { if (!Application.isPlaying) { DrawMapInEditor (); } } //void OnTextureValuesUpdated() { // textureData.ApplyToMaterial (terrainMaterial); //} public int mapChunkSize { get { if (terrainData.useFlatShading) { return 95; } else { return 239; } } } public void DrawMapInEditor() { MapData mapData = GenerateMapData (Vector2.zero); MapDisplay display = FindFirstObjectByType (); if (drawMode == DrawMode.NoiseMap) { display.DrawTexture (TextureGenerator.TextureFromHeightMap (mapData.heightMap)); } else if (drawMode == DrawMode.Mesh) { display.DrawMesh (MeshGenerator.GenerateTerrainMesh (mapData.heightMap, terrainData.meshHeightMultiplier, terrainData.meshHeightCurve, editorPreviewLOD,terrainData.useFlatShading)); } else if (drawMode == DrawMode.FalloffMap) { display.DrawTexture(TextureGenerator.TextureFromHeightMap(FalloffGenerator.GenerateFalloffMap(mapChunkSize))); } } public void RequestMapData(Vector2 centre, Action callback) { ThreadStart threadStart = delegate { MapDataThread (centre, callback); }; new Thread (threadStart).Start (); } void MapDataThread(Vector2 centre, Action callback) { MapData mapData = GenerateMapData (centre); lock (mapDataThreadInfoQueue) { mapDataThreadInfoQueue.Enqueue (new MapThreadInfo (callback, mapData)); } } public void RequestMeshData(MapData mapData, int lod, Action callback) { ThreadStart threadStart = delegate { MeshDataThread (mapData, lod, callback); }; new Thread (threadStart).Start (); } void MeshDataThread(MapData mapData, int lod, Action callback) { MeshData meshData = MeshGenerator.GenerateTerrainMesh (mapData.heightMap, terrainData.meshHeightMultiplier, terrainData.meshHeightCurve, lod,terrainData.useFlatShading); lock (meshDataThreadInfoQueue) { meshDataThreadInfoQueue.Enqueue (new MapThreadInfo (callback, meshData)); } } void Start() { //textureData.ApplyToMaterial(terrainMaterial); noiseData.seed = UnityEngine.Random.Range(0, 100000); DrawMapInEditor(); MeshFilter mf = GetComponent(); AddCollider(); Invoke("DelayedSpawn", 0.2f); } void AddCollider() { MeshFilter meshFilter = GetComponent(); if (meshFilter == null || meshFilter.sharedMesh == null) return; MeshCollider meshCollider = GetComponent(); if (meshCollider == null) { meshCollider = gameObject.AddComponent(); } meshCollider.sharedMesh = meshFilter.sharedMesh; } void DelayedSpawn() { Debug.Log("Attempting to spawn orbs now..."); // 1. Grab the mesh from the filter MeshFilter mf = GetComponent(); if (mf == null || mf.sharedMesh == null) { Debug.LogError("No Mesh found! Spawner can't find the ground."); return; } // 2. Force the collider to update to the NEW mesh shape MeshCollider meshCollider = GetComponent(); if (meshCollider == null) meshCollider = gameObject.AddComponent(); meshCollider.sharedMesh = null; // Reset it meshCollider.sharedMesh = mf.sharedMesh; // Assign new // 3. Now trigger the spawner TerrainObjectSpawner spawner = GetComponent(); if (spawner != null) { spawner.SpawnOrbs(); } else { Debug.LogError("TerrainObjectSpawner component missing on MapGenerator!"); } } void Update() { if (mapDataThreadInfoQueue.Count > 0) { for (int i = 0; i < mapDataThreadInfoQueue.Count; i++) { MapThreadInfo threadInfo = mapDataThreadInfoQueue.Dequeue (); threadInfo.callback (threadInfo.parameter); } } if (meshDataThreadInfoQueue.Count > 0) { for (int i = 0; i < meshDataThreadInfoQueue.Count; i++) { MapThreadInfo threadInfo = meshDataThreadInfoQueue.Dequeue (); threadInfo.callback (threadInfo.parameter); } } } MapData GenerateMapData(Vector2 centre) { float[,] noiseMap = Noise.GenerateNoiseMap (mapChunkSize + 2, mapChunkSize + 2, noiseData.seed, noiseData.noiseScale, noiseData.octaves, noiseData.persistance, noiseData.lacunarity, centre + noiseData.offset, noiseData.normalizeMode); if (terrainData.useFalloff) { if (falloffMap == null) { falloffMap = FalloffGenerator.GenerateFalloffMap (mapChunkSize + 2); } for (int y = 0; y < mapChunkSize+2; y++) { for (int x = 0; x < mapChunkSize+2; x++) { if (terrainData.useFalloff) { noiseMap [x, y] = Mathf.Clamp01 (noiseMap [x, y] - falloffMap [x, y]); } } } } //textureData.UpdateMeshHeights (terrainMaterial, terrainData.minHeight, terrainData.maxHeight); return new MapData (noiseMap); } void OnValidate() { if (terrainData != null) { terrainData.OnValuesUpdated -= OnValuesUpdated; terrainData.OnValuesUpdated += OnValuesUpdated; } if (noiseData != null) { noiseData.OnValuesUpdated -= OnValuesUpdated; noiseData.OnValuesUpdated += OnValuesUpdated; } //if (textureData != null) { // textureData.OnValuesUpdated -= OnTextureValuesUpdated; // textureData.OnValuesUpdated += OnTextureValuesUpdated; //} } struct MapThreadInfo { public readonly Action callback; public readonly T parameter; public MapThreadInfo (Action callback, T parameter) { this.callback = callback; this.parameter = parameter; } } } public struct MapData { public readonly float[,] heightMap; public MapData (float[,] heightMap) { this.heightMap = heightMap; } }