using UnityEngine; using System; using System.Threading; using System.Collections.Generic; public class MapGenerator : MonoBehaviour { public enum DrawMode { NoiseMap, ColourMap, Mesh, FallOff}; public DrawMode drawMode; public Noise.NormalizeMode normalizeMode; public const int mapChunkSize = 241; [Range(0,6)] public int editorPreviewLOD; public float noiseScale; public int octaves; [Range(0,1)] public float persistance; public float lacunarity; public int seed; public Vector2 offset; public bool useFallOff; public float meshHeightMultiplier; public AnimationCurve meshHeightCurve; public bool autoUpdate; public TerrainType[] regions; float[,] fallOffMap; Queue> mapDataThreadInfoQueue = new Queue>(); Queue> meshDataThreadInfoQueue = new Queue>(); private void Awake() { fallOffMap = FallOffGenerator.GenerateFallOffMap(mapChunkSize); } 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.ColourMap) { display.DrawTexture(TextureGenerator.TextureFromColourMap(mapData.colourMap, mapChunkSize, mapChunkSize)); } else if (drawMode == DrawMode.Mesh) { display.DrawMesh(MeshGenerator.GenerateTerrainMesh(mapData.heightMap, meshHeightMultiplier, meshHeightCurve, editorPreviewLOD), TextureGenerator.TextureFromColourMap(mapData.colourMap, mapChunkSize, mapChunkSize)); }else if (drawMode ==DrawMode.FallOff) { 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, meshHeightMultiplier, meshHeightCurve, lod); lock (meshDataThreadInfoQueue) { meshDataThreadInfoQueue.Enqueue(new MapThreadInfo(callback, meshData)); } } private 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, mapChunkSize, seed, noiseScale, octaves, persistance, lacunarity, centre + offset, normalizeMode); Color[] colourMap = new Color[mapChunkSize * mapChunkSize]; for(int y=0; y= regions[i].height) { colourMap[y*mapChunkSize + x] = regions[i].colour; } else { break; } } } } return new MapData(noiseMap, colourMap); } private void OnValidate() { if (lacunarity < 1) { lacunarity = 1; } if(octaves < 0) { octaves = 0; } fallOffMap = FallOffGenerator.GenerateFallOffMap(mapChunkSize); } struct MapThreadInfo { public readonly Action callback; public readonly T parameter; public MapThreadInfo(Action callback, T parameter) { this.callback = callback; this.parameter = parameter; } } } [System.Serializable] public struct TerrainType { public string name; public float height; public Color colour; } public struct MapData { public readonly float[,] heightMap; public readonly Color[] colourMap; public MapData(float[,] heightMap, Color[] colourMap) { this.heightMap = heightMap; this.colourMap = colourMap; } }