/// <summary> /// creates a biome for a given type of terrain /// </summary> private void createBiome(Terrain.TerrainTypes terrain) { // calculate biome half length proportional to the map size int biomeLenghtValue = (int)(Mathf.Max(WIDTH, HEIGHT) / 7); int biomeHalfLength = random.Next(biomeLenghtValue - 2, biomeLenghtValue + 2); // random anchor spot for biome // index 0 for x and 1 and y coordinate int[] anchor = new int[2]; anchor[0] = random.Next(0, WIDTH); anchor[1] = random.Next(0, HEIGHT); int counter = 0; while (biomeAnchorTooClose(anchor, biomeLenghtValue) && counter < 100) { anchor[0] = random.Next(0, WIDTH); anchor[1] = random.Next(0, HEIGHT); counter++; } // adding anchor to screen MapTile anchorTile = ScriptableObject.CreateInstance <MapTile>(); Vector3Int anchorVector = new Vector3Int(-anchor[0] + WIDTH / 2, -anchor[1] + HEIGHT / 2, 0); Vector3 anchorMappedVector = map.CellToWorld(anchorVector); anchorTile.Canvas = parent; anchorTile.ScreenPosition = anchorMappedVector; biomeAnchors[anchor] = terrain; // occupiedBiomSpots[anchor] = terrain; anchorTile.Terrain = new Terrain(terrain); growBoime(anchor, biomeHalfLength, terrain); // create beach biom if the biome type is Ocean if (terrain.Equals(Terrain.TerrainTypes.Ocean)) { addBeachBiome(anchor, biomeHalfLength); } else if (terrain.Equals(Terrain.TerrainTypes.DesertHill)) { addDessertBiome(anchor, biomeHalfLength); } else if (terrain.Equals(Terrain.TerrainTypes.Grass)) { addMountainBiome(anchor, biomeHalfLength); } }
/// <summary> /// grows a biome /// </summary> private void growBoime(int[] anchor, int biomHalfLength, Terrain.TerrainTypes terrain) { // constants that will be used further down the line float k = Mathf.Sqrt(Mathf.Pow(biomHalfLength, 2) * 2); float a = (float)2.0f / Mathf.Log10(Mathf.Pow(k, 2) - 2.0f); // growing biom for (int i = 0; i < biomHalfLength * 3; i++) { for (int j = 0; j < biomHalfLength * 3; j++) { // current position array where index 0 is X and index 1 is Y coordinate int[] curPos = new int[2]; curPos[0] = anchor[0] - biomHalfLength + i; curPos[1] = anchor[1] - biomHalfLength + j; // check if X and Y values are within the map if (curPos[0] < WIDTH && curPos[0] >= 0 && curPos[1] < HEIGHT && curPos[1] >= 0) { MapTile tile = ScriptableObject.CreateInstance <MapTile>(); // A vector used for hex position Vector3Int vector = new Vector3Int(-curPos[0] + WIDTH / 2, -curPos[1] + HEIGHT / 2, 0); // Find the real position (the position on the screen) Vector3 mappedVector = map.CellToWorld(vector); tile.Canvas = parent; tile.ScreenPosition = mappedVector; // check if terrain is vacant if (getTileTerrain(curPos).Equals(Terrain.TerrainTypes.NotSet)) { // Debug.Log("Cur: X: " + curX + ", Y: " + curY); // weighted random terrain allocation depending on distance from anchor int value = random.Next(0, 100); // weighting is done in such a that: // P = (k^2 - d^2)^a, // where: // P = probability of the biome tile being set // k = a constant (calculated earlier before the nested for loops) // d = absolute distance between the anchor and any potential biome tile // a = a constant (calculated earlier before the nested for loops) // // the formula satisfies the two equations below: // 100 = (k^2 - 2)^a, this ensures that the biome is atleast 3x3 // 0 = (k^2 - d^2)^a, where d is a distance for an arbitrary square just outside the biome half length // // so if biome half length is 7 then k = 11.3 and a = 0.484 float dist = Mathf.Sqrt(Mathf.Pow(anchor[0] - curPos[0], 2) + Mathf.Pow(anchor[1] - curPos[1], 2)); double prob = Mathf.Pow(Mathf.Pow(k, 2) - Mathf.Pow(dist, 2), a); if (value < prob) { occupiedBiomSpots[curPos] = terrain; tile.Terrain = new Terrain(terrain); SetTileTo(vector, tile); // add mountains if the biome is just grass if (terrain.Equals(Terrain.TerrainTypes.Grass)) { StructureFactory mountainFactory = new MountainFactory(); if (mountainFactory.CanBuildOnto(tile, out _)) { mountainFactory.BuildOnto(tile); } } // Refresh the tile whenever its sprite changes. tile.SpriteChange += () => map.RefreshTile(vector); } } } } } }