MapGenerator.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. using UnityEngine;
  2. using System.Collections;
  3. using System;
  4. using System.Threading;
  5. using System.Collections.Generic;
  6. using UnityEditor.UI;
  7. public class MapGenerator : MonoBehaviour {
  8. public enum DrawMode {NoiseMap, Mesh, FalloffMap};
  9. public DrawMode drawMode;
  10. public TerrainData terrainData;
  11. public NoiseData noiseData;
  12. public TextureData textureData;
  13. public Material terrainMaterial;
  14. [Range(0,6)]
  15. public int editorPreviewLOD;
  16. public bool autoUpdate;
  17. float[,] falloffMap;
  18. Queue<MapThreadInfo<MapData>> mapDataThreadInfoQueue = new Queue<MapThreadInfo<MapData>>();
  19. Queue<MapThreadInfo<MeshData>> meshDataThreadInfoQueue = new Queue<MapThreadInfo<MeshData>>();
  20. void OnValuesUpdated() {
  21. if (!Application.isPlaying) {
  22. DrawMapInEditor ();
  23. }
  24. }
  25. //void OnTextureValuesUpdated() {
  26. // textureData.ApplyToMaterial (terrainMaterial);
  27. //}
  28. public int mapChunkSize {
  29. get {
  30. if (terrainData.useFlatShading) {
  31. return 95;
  32. } else {
  33. return 239;
  34. }
  35. }
  36. }
  37. public void DrawMapInEditor() {
  38. MapData mapData = GenerateMapData (Vector2.zero);
  39. MapDisplay display = FindFirstObjectByType<MapDisplay> ();
  40. if (drawMode == DrawMode.NoiseMap) {
  41. display.DrawTexture (TextureGenerator.TextureFromHeightMap (mapData.heightMap));
  42. } else if (drawMode == DrawMode.Mesh) {
  43. display.DrawMesh (MeshGenerator.GenerateTerrainMesh (mapData.heightMap, terrainData.meshHeightMultiplier, terrainData.meshHeightCurve, editorPreviewLOD,terrainData.useFlatShading));
  44. } else if (drawMode == DrawMode.FalloffMap) {
  45. display.DrawTexture(TextureGenerator.TextureFromHeightMap(FalloffGenerator.GenerateFalloffMap(mapChunkSize)));
  46. }
  47. }
  48. public void RequestMapData(Vector2 centre, Action<MapData> callback) {
  49. ThreadStart threadStart = delegate {
  50. MapDataThread (centre, callback);
  51. };
  52. new Thread (threadStart).Start ();
  53. }
  54. void MapDataThread(Vector2 centre, Action<MapData> callback) {
  55. MapData mapData = GenerateMapData (centre);
  56. lock (mapDataThreadInfoQueue) {
  57. mapDataThreadInfoQueue.Enqueue (new MapThreadInfo<MapData> (callback, mapData));
  58. }
  59. }
  60. public void RequestMeshData(MapData mapData, int lod, Action<MeshData> callback) {
  61. ThreadStart threadStart = delegate {
  62. MeshDataThread (mapData, lod, callback);
  63. };
  64. new Thread (threadStart).Start ();
  65. }
  66. void MeshDataThread(MapData mapData, int lod, Action<MeshData> callback) {
  67. MeshData meshData = MeshGenerator.GenerateTerrainMesh (mapData.heightMap, terrainData.meshHeightMultiplier, terrainData.meshHeightCurve, lod,terrainData.useFlatShading);
  68. lock (meshDataThreadInfoQueue) {
  69. meshDataThreadInfoQueue.Enqueue (new MapThreadInfo<MeshData> (callback, meshData));
  70. }
  71. }
  72. void Start()
  73. {
  74. //textureData.ApplyToMaterial(terrainMaterial);
  75. noiseData.seed = UnityEngine.Random.Range(0, 100000);
  76. DrawMapInEditor();
  77. MeshFilter mf = GetComponent<MeshFilter>();
  78. AddCollider();
  79. Invoke("DelayedSpawn", 0.2f);
  80. }
  81. void AddCollider()
  82. {
  83. MeshFilter meshFilter = GetComponent<MeshFilter>();
  84. // Add a check to see if DrawMapInEditor actually put a mesh there
  85. if (meshFilter == null) return;
  86. MeshCollider meshCollider = GetComponent<MeshCollider>();
  87. if (meshCollider == null)
  88. {
  89. meshCollider = gameObject.AddComponent<MeshCollider>();
  90. }
  91. if (meshFilter.sharedMesh != null)
  92. {
  93. meshCollider.sharedMesh = meshFilter.sharedMesh;
  94. }
  95. }
  96. void DelayedSpawn()
  97. {
  98. Debug.Log("Attempting to spawn orbs and sync collider...");
  99. MeshFilter mf = GetComponent<MeshFilter>();
  100. MeshCollider meshCollider = GetComponent<MeshCollider>();
  101. // Ensure the collider exists
  102. if (meshCollider == null) meshCollider = gameObject.AddComponent<MeshCollider>();
  103. // If the mesh is still null, DrawMapInEditor might have failed or not finished
  104. if (mf == null || mf.sharedMesh == null)
  105. {
  106. Debug.LogWarning("Mesh not ready yet, retrying in 0.1s...");
  107. Invoke("DelayedSpawn", 0.1f); // Re-try until mesh is ready
  108. return;
  109. }
  110. meshCollider.sharedMesh = null;
  111. meshCollider.sharedMesh = mf.sharedMesh;
  112. TerrainObjectSpawner spawner = GetComponent<TerrainObjectSpawner>();
  113. if (spawner != null)
  114. {
  115. spawner.SpawnOrbs();
  116. spawner.SpawnEnemies();
  117. }
  118. }
  119. void Update() {
  120. if (mapDataThreadInfoQueue.Count > 0) {
  121. for (int i = 0; i < mapDataThreadInfoQueue.Count; i++) {
  122. MapThreadInfo<MapData> threadInfo = mapDataThreadInfoQueue.Dequeue ();
  123. threadInfo.callback (threadInfo.parameter);
  124. }
  125. }
  126. if (meshDataThreadInfoQueue.Count > 0) {
  127. for (int i = 0; i < meshDataThreadInfoQueue.Count; i++) {
  128. MapThreadInfo<MeshData> threadInfo = meshDataThreadInfoQueue.Dequeue ();
  129. threadInfo.callback (threadInfo.parameter);
  130. }
  131. }
  132. }
  133. MapData GenerateMapData(Vector2 centre) {
  134. float[,] noiseMap = Noise.GenerateNoiseMap (mapChunkSize + 2, mapChunkSize + 2, noiseData.seed, noiseData.noiseScale, noiseData.octaves, noiseData.persistance, noiseData.lacunarity, centre + noiseData.offset, noiseData.normalizeMode);
  135. if (terrainData.useFalloff) {
  136. if (falloffMap == null) {
  137. falloffMap = FalloffGenerator.GenerateFalloffMap (mapChunkSize + 2);
  138. }
  139. for (int y = 0; y < mapChunkSize+2; y++) {
  140. for (int x = 0; x < mapChunkSize+2; x++) {
  141. if (terrainData.useFalloff) {
  142. noiseMap [x, y] = Mathf.Clamp01 (noiseMap [x, y] - falloffMap [x, y]);
  143. }
  144. }
  145. }
  146. }
  147. //textureData.UpdateMeshHeights (terrainMaterial, terrainData.minHeight, terrainData.maxHeight);
  148. return new MapData (noiseMap);
  149. }
  150. void OnValidate() {
  151. if (terrainData != null) {
  152. terrainData.OnValuesUpdated -= OnValuesUpdated;
  153. terrainData.OnValuesUpdated += OnValuesUpdated;
  154. }
  155. if (noiseData != null) {
  156. noiseData.OnValuesUpdated -= OnValuesUpdated;
  157. noiseData.OnValuesUpdated += OnValuesUpdated;
  158. }
  159. //if (textureData != null) {
  160. // textureData.OnValuesUpdated -= OnTextureValuesUpdated;
  161. // textureData.OnValuesUpdated += OnTextureValuesUpdated;
  162. //}
  163. }
  164. struct MapThreadInfo<T> {
  165. public readonly Action<T> callback;
  166. public readonly T parameter;
  167. public MapThreadInfo (Action<T> callback, T parameter)
  168. {
  169. this.callback = callback;
  170. this.parameter = parameter;
  171. }
  172. }
  173. }
  174. public struct MapData {
  175. public readonly float[,] heightMap;
  176. public MapData (float[,] heightMap)
  177. {
  178. this.heightMap = heightMap;
  179. }
  180. }