using System; using System.Collections; using System.Linq; using TransportGame.Generator; using TransportGame.Model; using TransportGame.Utils; using UnityEngine; public class TerrainGeneratorScript : MonoBehaviour { private Map map = null; public int TerrainWidth = 1024; public int TerrainHeight = 1024; public GameObject WaterObject; public Texture2D[] Textures; // Use this for initialization void Start() { StartCoroutine(GenerateMap()); } private void GenerateTerrainThread() { CityGenerator generator = new CityGenerator(); map = generator.Generate(TerrainWidth, TerrainHeight); } private Mesh GenerateWater() { Mesh water = new Mesh(); water.name = "water"; water.vertices = new[] { new Vector3(0, map.WaterLevel, 0), new Vector3(0, map.WaterLevel, map.Height), new Vector3(map.Width, map.WaterLevel, 0), new Vector3(map.Width, map.WaterLevel, map.Height) }; water.triangles = new[] { 0, 1, 2, 2, 1, 3 }; water.uv = new[] { new Vector2(0, 0), new Vector2(0, 1), new Vector2(1, 0), new Vector2(1, 1) }; water.RecalculateNormals(); return water; } private IEnumerator GenerateMap() { // Generate terrain foreach (var i in Task.RunAsync(GenerateTerrainThread)) yield return i; // Generate terrain data TerrainData terrainData = new TerrainData(); terrainData.heightmapResolution = Mathf.Max(map.Height, map.Width) + 1; terrainData.size = new Vector3(map.Width, map.Biome.Height, map.Height); terrainData.SetDetailResolution(1024, 8); terrainData.SetHeights(0, 0, map.Heightmap); terrainData.name = "Generated Terrain Data"; yield return null; if (map.Biome.Textures != null) { SplatPrototype[] prototypes = new SplatPrototype[map.Biome.Textures.Length]; for (int i = 0; i < map.Biome.Textures.Length; i++) { Texture2D texture = Textures.FirstOrDefault(tex => tex != null && tex.name == map.Biome.Textures[i].Source); if (texture == null) throw new Exception("Texture " + map.Biome.Textures[i].Source + " not found!"); prototypes[i] = new SplatPrototype(); prototypes[i].texture = texture; } terrainData.splatPrototypes = prototypes; yield return null; } // Create terrain object GameObject terrain = Terrain.CreateTerrainGameObject(terrainData); terrain.name = "Generated Terrain"; yield return null; Terrain terrainComp = terrain.GetComponent(); terrainComp.heightmapPixelError = 1; yield return null; // Set water if (WaterObject != null) { MeshFilter waterMesh = WaterObject.GetComponent(); waterMesh.mesh = GenerateWater(); } yield return null; // Set up textures SetupSplatmaps(terrainData); } private void SetupSplatmaps(TerrainData terrainData) { float[, ,] splatData = new float[terrainData.alphamapWidth, terrainData.alphamapHeight, terrainData.alphamapLayers]; Expression[] expressions = new Expression[terrainData.alphamapLayers]; for (int y = 0; y < terrainData.alphamapHeight; y++) for (int x = 0; x < terrainData.alphamapWidth; x++) { float y_01 = (float)y / (float)terrainData.alphamapHeight; float x_01 = (float)x / (float)terrainData.alphamapWidth; int ix = Mathf.RoundToInt(x_01 * TerrainWidth); int iy = Mathf.RoundToInt(y_01 * TerrainHeight); // Get height float height = map.GetHeight(ix, iy); // Get steepness float steepness = map.GetSteepness(ix, iy); // Go through each texture layer float[] weights = new float[terrainData.alphamapLayers]; float sum = 0; for (int t = 0; t < terrainData.alphamapLayers; t++) { // Set up expression if (expressions[t] == null) { expressions[t] = new Expression(map.Biome.Textures[t].Expression); expressions[t].ParseExpression(); } expressions[t].Variables["height"] = height; expressions[t].Variables["steepness"] = steepness; expressions[t].Variables["maxHeight"] = terrainData.size.y; expressions[t].Variables["waterLevel"] = map.WaterLevel - 1f; // Obtain weight weights[t] = expressions[t].Evaluate(); sum += weights[t]; } // Normalize and copy weights for (int t = 0; t < terrainData.alphamapLayers; t++) { splatData[x, y, t] = weights[t] / sum; } } terrainData.SetAlphamaps(0, 0, splatData); } // Update is called once per frame void Update() { } }