//UNDONE public static List<List<U16Vec2>> CreateClusters(ref Chunk map, GlobalTerrainSettings.ClustersSettings clustersParam) { ushort height = map.Height; ushort width = map.Width; List<List<U16Vec2>> clusters = new List<List<U16Vec2>>(clustersParam.Count); for (byte i = 0; i < clustersParam.Count; ++i) { U16Vec2 pos; pos.X = (ushort)Random.Range(1, width - 1); pos.Y = (ushort)Random.Range(1, height - 1); if ((map.TerrainMatrix[pos.Y, pos.X] & TerrainType.RIVER) == TerrainType.NONE) { clusters.Add(new List<U16Vec2>()); SpreadCluster(map, pos, clustersParam.Size, clusters[i]); } else --i; } return clusters; }
static Stack<U16Vec2> RiverStack; //Стек для постройки реки #endregion Fields #region Methods public static void CreateChunk(ref Chunk map, GlobalTerrainSettings settings, HeighmapNeighboring hmNbHeight, float landscapeRoughness, HeighmapNeighboring hmNbForest, float forestRoughness, float forestDensity) { float?[,] buf = new float?[map.Height, map.Width]; WorldGenerator.CreateHeightmap(ref buf, landscapeRoughness, hmNbHeight); for (ushort y = 0; y < map.Height; ++y) for (ushort x = 0; x < map.Width; ++x) { map.HeightMatrix[y, x] = Mathf.Clamp(buf[y, x].Value, 0, Mathf.Abs(buf[y, x].Value)); buf[y, x] = null; } WorldGenerator.CreateHeightmap(ref buf, forestRoughness, hmNbForest); for (ushort y = 0; y < map.Height; ++y) for (ushort x = 0; x < map.Width; ++x) { buf[y, x] = buf[y, x].Value * forestDensity; map.ForestMatrix[y, x] = Mathf.Clamp(buf[y, x].Value, 0, Mathf.Abs(buf[y, x].Value)); } map.Rivers = WorldGenerator.CreateRivers(map.HeightMatrix, ref map.TerrainMatrix, settings.RiversParam); map.Clusters = WorldGenerator.CreateClusters(ref map, settings.ClustersParam); map.Roads = WorldGenerator.CreateRoads(map.HeightMatrix, ref map.TerrainMatrix, map.Clusters, settings.RoadsParam); WorldGenerator.CreateTerrainmap(ref map.TerrainMatrix, map.HeightMatrix, settings); }
static void DirectRoad(float[,] heightMatrix, TerrainType[,] terrainMatrix, U16Vec2 pos, U16Vec2 destination, List<U16Vec2> road, GlobalTerrainSettings.RoadsSettings roadsParam) { ushort height = (ushort)heightMatrix.GetLength(0); ushort width = (ushort)heightMatrix.GetLength(1); road.Add(pos); terrainMatrix[pos.Y, pos.X] |= TerrainType.ROAD; if (pos.Y > 0 && pos.Y < height - 1 && pos.X > 0 && pos.X < width - 1 && !(destination.X == pos.X && destination.Y == pos.Y)) { byte k = (byte)(pos.X & 1); //TODO Провести рефакторинг. float max = heightMatrix[pos.Y + k, pos.X - 1], avg = 0; float cur = heightMatrix[pos.Y + k, pos.X - 1]; avg += cur; cur = heightMatrix[pos.Y + 1, pos.X]; if (max < cur) max = cur; avg += cur; cur = heightMatrix[pos.Y + k, pos.X + 1]; if (max < cur) max = cur; avg += cur; cur = heightMatrix[pos.Y - 1 + k, pos.X + 1]; if (max < cur) max = cur; avg += cur; cur = heightMatrix[pos.Y - 1, pos.X]; if (max < cur) max = cur; avg += cur; cur = heightMatrix[pos.Y - 1 + k, pos.X - 1]; if (max < cur) max = cur; avg += cur; avg /= 6; max += 0.0001f; //! float weight = 0, buf; sbyte dx = 0, dy = 0; if (!road.Contains(new U16Vec2((ushort)(pos.X - 1), (ushort)(pos.Y + k))) && ((buf = (Mathf.Abs(destination.X - pos.X) - Mathf.Abs(destination.X - (pos.X - 1)) + Mathf.Abs(destination.Y - pos.Y) - Mathf.Abs(destination.Y - (pos.Y + k)) + 3) * (max - Mathf.Abs(heightMatrix[pos.Y + k, pos.X - 1] - avg))) * ((terrainMatrix[pos.Y + k, pos.X - 1] & TerrainType.ROAD) != TerrainType.NONE ? roadsParam.RoadMergeMultiplier : 1) * ((terrainMatrix[pos.Y, pos.X] & terrainMatrix[pos.Y + k, pos.X - 1] & TerrainType.RIVER) != TerrainType.NONE ? roadsParam.GoingAlongRiverMultiplier : 1) > weight)) { weight = buf; dx = -1; dy = (sbyte)k; } if (!road.Contains(new U16Vec2((ushort)(pos.X + 1), (ushort)(pos.Y + k))) && ((buf = (Mathf.Abs(destination.X - pos.X) - Mathf.Abs(destination.X - (pos.X + 1)) + Mathf.Abs(destination.Y - pos.Y) - Mathf.Abs(destination.Y - (pos.Y + k)) + 3) * (max - Mathf.Abs(heightMatrix[pos.Y + k, pos.X + 1] - avg))) * ((terrainMatrix[pos.Y + k, pos.X + 1] & TerrainType.ROAD) != TerrainType.NONE ? roadsParam.RoadMergeMultiplier : 1) * ((terrainMatrix[pos.Y, pos.X] & terrainMatrix[pos.Y + k, pos.X + 1] & TerrainType.RIVER) != TerrainType.NONE ? roadsParam.GoingAlongRiverMultiplier : 1) > weight)) { weight = buf; dx = 1; dy = (sbyte)k; } if (!road.Contains(new U16Vec2(pos.X, (ushort)(pos.Y + 1))) && ((buf = (Mathf.Abs(destination.Y - pos.Y) - Mathf.Abs(destination.Y - (pos.Y + 1)) + 3) * (max - Mathf.Abs(heightMatrix[pos.Y + 1, pos.X] - avg))) * ((terrainMatrix[pos.Y + 1, pos.X] & TerrainType.ROAD) != TerrainType.NONE ? roadsParam.RoadMergeMultiplier : 1) * ((terrainMatrix[pos.Y, pos.X] & terrainMatrix[pos.Y + 1, pos.X] & TerrainType.RIVER) != TerrainType.NONE ? roadsParam.GoingAlongRiverMultiplier : 1) > weight))//!После диагонали { weight = buf; dx = 0; dy = 1; } if (!road.Contains(new U16Vec2((ushort)(pos.X + 1), (ushort)(pos.Y - (k ^ 1)))) && ((buf = (Mathf.Abs(destination.X - pos.X) - Mathf.Abs(destination.X - (pos.X + 1)) + Mathf.Abs(destination.Y - pos.Y) - Mathf.Abs(destination.Y - (pos.Y - (k ^ 1))) + 3) * (max - Mathf.Abs(heightMatrix[pos.Y - (k ^ 1), pos.X + 1] - avg))) * ((terrainMatrix[pos.Y - (k ^ 1), pos.X + 1] & TerrainType.ROAD) != TerrainType.NONE ? roadsParam.RoadMergeMultiplier : 1) * ((terrainMatrix[pos.Y, pos.X] & terrainMatrix[pos.Y - (k ^ 1), pos.X + 1] & TerrainType.RIVER) != TerrainType.NONE ? roadsParam.GoingAlongRiverMultiplier : 1) > weight)) { weight = buf; dx = 1; dy = (sbyte)(-(k ^ 1)); } if (!road.Contains(new U16Vec2((ushort)(pos.X - 1), (ushort)(pos.Y - (k ^ 1)))) && ((buf = (Mathf.Abs(destination.X - pos.X) - Mathf.Abs(destination.X - (pos.X - 1)) + Mathf.Abs(destination.Y - pos.Y) - Mathf.Abs(destination.Y - (pos.Y - (k ^ 1))) + 3) * (max - Mathf.Abs(heightMatrix[pos.Y - (k ^ 1), pos.X - 1] - avg))) * ((terrainMatrix[pos.Y - (k ^ 1), pos.X - 1] & TerrainType.ROAD) != TerrainType.NONE ? roadsParam.RoadMergeMultiplier : 1) * ((terrainMatrix[pos.Y, pos.X] & terrainMatrix[pos.Y - (k ^ 1), pos.X - 1] & TerrainType.RIVER) != TerrainType.NONE ? roadsParam.GoingAlongRiverMultiplier : 1) > weight)) { weight = buf; dx = -1; dy = (sbyte)(-(k ^ 1)); } if (!road.Contains(new U16Vec2(pos.X, (ushort)(pos.Y - 1))) && ((buf = (Mathf.Abs(destination.Y - pos.Y) - Mathf.Abs(destination.Y - (pos.Y - 1)) + 3) * (max - Mathf.Abs(heightMatrix[pos.Y - 1, pos.X] - avg))) * ((terrainMatrix[pos.Y - 1, pos.X] & TerrainType.ROAD) != TerrainType.NONE ? roadsParam.RoadMergeMultiplier : 1) * ((terrainMatrix[pos.Y, pos.X] & terrainMatrix[pos.Y - 1, pos.X] & TerrainType.RIVER) != TerrainType.NONE ? roadsParam.GoingAlongRiverMultiplier : 1) > weight))//!После диагонали { weight = buf; dx = 0; dy = -1; } if (dx == 0 && dy == 0) throw new System.Exception("Infinite recursion detected. Try to check heightmap values."); DirectRoad(heightMatrix, terrainMatrix, new U16Vec2((ushort)(pos.X + dx), (ushort)(pos.Y + dy)), destination, road, roadsParam); } }
public static void CreateTerrainmap(ref TerrainType[,] terrainmap, float[,] matrix, GlobalTerrainSettings terrainParam) { ushort height = (ushort)terrainmap.GetLength(0); ushort width = (ushort)terrainmap.GetLength(1); for (ushort y = 0; y < height; ++y) for (ushort x = 0; x < width; ++x) if (matrix[y, x] < terrainParam.Terrains[0].StartingHeight) terrainmap[y, x] |= terrainParam.BottommostTerrain; else if (matrix[y, x] >= terrainParam.Terrains[terrainParam.Terrains.Length - 1].StartingHeight) terrainmap[y, x] |= terrainParam.Terrains[terrainParam.Terrains.Length - 1].TerrainType; else for (byte i = 1; i < terrainParam.Terrains.Length; ++i) if (matrix[y, x] < terrainParam.Terrains[i].StartingHeight) { terrainmap[y, x] |= terrainParam.Terrains[i - 1].TerrainType; break; } }
public static List<List<U16Vec2>> CreateRoads(float[,] heightMap, ref TerrainType[,] terrainMap, List<List<U16Vec2>> clusters, GlobalTerrainSettings.RoadsSettings roadsParam) { List<List<U16Vec2>> roads = new List<List<U16Vec2>>(); for (byte i = 0; i < clusters.Count >> 1; ++i) { roads.Add(new List<U16Vec2>()); DirectRoad(heightMap, terrainMap, clusters[i][0], clusters[(clusters.Count >> 1) + i][0], roads[i], roadsParam); } return roads; }
/// <summary> /// Создаёт реки. /// </summary> /// <returns>Список рек.</returns> /// <param name="heightMatrix">Карта высот.</param> /// <param name="riverMatrix">[out] Карта рек.</param> public static List<List<U16Vec2>> CreateRivers(float[,] heightMap, ref TerrainType[,] terrainMap, GlobalTerrainSettings.RiversSettings riversParam) { RiverStack = new Stack<U16Vec2>(); ushort height = (ushort)heightMap.GetLength(0); ushort width = (ushort)heightMap.GetLength(1); double avg = 0; foreach (float h in heightMap) avg += h; avg /= height * width; float minRiverHeight = (float)avg * riversParam.Height; List<List<U16Vec2>> rivers = new List<List<U16Vec2>>(); for (byte i = 0; i < riversParam.Count; ++i) { bool riverCreated = false; for (ushort y = 1; y < height - 1 && !riverCreated; ++y) //TODO for (ushort x = 1; x < width - 1 && !riverCreated; ++x) //TODO if (heightMap[y, x] > minRiverHeight && (terrainMap[y, x] & TerrainType.RIVER) == TerrainType.NONE && RiverNeighbours(new U16Vec2(x, y), terrainMap) == 0) //Проверяем, можно ли нам начать создание реки с этого хекса for (byte k = 0; k < riversParam.Attempts && !riverCreated; ++k) { DirectRiver(new U16Vec2(x, y), heightMap, terrainMap, riversParam.FlowHeightKoef); //Запускаем рекурсию if (RiverStack.Count >= riversParam.MinimumLength) { //Если река получилась больше необходим длины, то помечаем ячейки матрицы, иначе пробуем ещё раз foreach (U16Vec2 hex in RiverStack) terrainMap[hex.Y, hex.X] |= TerrainType.RIVER; riverCreated = true; rivers.Add(new List<U16Vec2>(RiverStack)); rivers[rivers.Count - 1].Reverse(); } RiverStack.Clear(); } } RiverStack = null; return rivers; }