// Generate houses based on noise height value private void GenerateHouses() { int aboveGroundPlaceholderY = 10; int checkForEveryCoordinates = 50; float minNoiseHeight = 0.05f; float[,] noiseMap = GenerateCityNoiseMap(this.mapWidth, this.mapHeight, this.offsets); for (int y = 0; y < mapHeight; y += checkForEveryCoordinates) { for (int x = 0; x < mapWidth; x += checkForEveryCoordinates) { // If the current location is within the noisemap position if (noiseMap[x, y] <= minNoiseHeight) { Vector3 position = new Vector3(x + this.offsets.x, aboveGroundPlaceholderY, y + this.offsets.y); // Get random building index from thhe list of buildings GameObject building = buildingGenerator.Generate(position); building.SetActive(false); // Calculate bounds and calculate the houseposition for the center of the house, also get the correct Y value for the building Bounds houseBounds = CalculateBounds(building); Vector3 housePosition = PositionCorrection(position); Vector3 tilePosition = new Vector3(this.offsets.x, 0, this.offsets.y); // Get tile and check if it exists before making a house Tile tile = WorldBuilder.GetTile(tilePosition); // Check if valid position if (tile != null && ValidHousePosition(housePosition, houseBounds)) { building.transform.position = housePosition; building.SetActive(true); // Turn house with consistent random numbers int xRandomIndex = terrainGenerator.RandomNumbers[(x + 1) * (y + 1) * Math.Abs((int)this.offsets.x) % terrainGenerator.RandomNumbers.Length]; int zRandomIndex = terrainGenerator.RandomNumbers[(x + 1) * (y + 1) * Math.Abs((int)this.offsets.y) % (terrainGenerator.RandomNumbers.Length - 1)]; Vector3 lookAtPosition = new Vector3(xRandomIndex, building.transform.position.y, zRandomIndex); building.transform.LookAt(lookAtPosition); // Add house to tile tile.AddBuilding(building); } else { Destroy(building); } } } } }
private SafeMesh GenerateCaveMap(Vector3 offsets) { int size = WorldBuilder.CHUNK_SIZE + 1; Tile currentTile = WorldBuilder.GetTile(offsets); // Gets added to coordinates, is a decimal to make sure it does not end up at an integer float addendum = 1000.17777f; // Coordinates are divided by scale, larger scale = larger/more spread out caves float scale = 20f; float[,,] caveMap = new float[size, CAVE_DEPTH * 2, size]; for (int x = 0; x < size; x++) { for (int z = 0; z < size; z++) { // -5 to make the amount of rocks sticking out of the terrain lower int coordinateHeight = Mathf.FloorToInt(currentTile.HeightMap[x, z]) - 5; int caveHeight = coordinateHeight + CAVE_DEPTH; // Cave height make height dynamic based on heightmap[x,z] for (int y = 0; y < caveHeight; y++) { if (y == 0) { caveMap[x, y, z] = 1; } else if (y <= 2) { double tempVal = ridgedMultifractal.GetValue((z + offsets.z + addendum) / scale, (y + addendum) / scale, (x + offsets.x + addendum) / scale); int isCave = tempVal < 0 ? 0 : 1; caveMap[x, y, z] = isCave; } else { double tempVal = ridgedMultifractal.GetValue((x + offsets.x + addendum) / scale, (y + addendum) / scale, (z + offsets.z + addendum) / scale); int isCave = tempVal < 0.35 ? 0 : 1; caveMap[x, y, z] = isCave; } } } } SafeMesh safeMesh = MarchingCubes.BuildMesh(caveMap); safeMesh.position = offsets; return(safeMesh); }
private void OnCaveDataReceived(SafeMesh safeMesh) { Tile currentTile = WorldBuilder.GetTile(safeMesh.position); // Check if currentTile is not already unloaded if (currentTile != null) { Mesh mesh = new Mesh(); mesh.vertices = safeMesh.Vertices; mesh.triangles = safeMesh.Triangles; currentTile.Cave.MeshFilter.mesh = mesh; mesh.uv = GenerateUV.CalculateUVs(safeMesh.Vertices, 1); mesh.RecalculateNormals(); currentTile.Cave.MeshCollider.sharedMesh = mesh; currentTile.Cave.GameObject.SetActive(true); } }
//Generate Decorations based on Perlin noise public void Generate(float[,] heightMap, Vector3 position) { Tile tile = WorldBuilder.GetTile(position); bool placeTree = true; float scale = 0.17777f; for (int y = 0; y < 11; y = y + interval) { for (int x = 0; x < 11; x = x + interval) { double sampleX = (x + position.x) / scale; double sampleY = (y + position.z) / scale; float noiseHeight = (float)(perlin.GetValue(sampleY, 0, sampleX) + 1) / 2; Biome biome = terrainGenerator.GetBiomeByCoordinates(new Vector2(position.x + x, position.z + y)); if (biome.BiomeType is DefaultBiomeType || biome.BiomeType is ForestBiomeType || biome.BiomeType is PlainsBiomeType || biome.BiomeType is ShrublandBiomeType) { if (noiseHeight >= PlantThreshold && noiseHeight <= PlantThreshold + MarginThreshold) { Vector3 pos = new Vector3((position.x + x), heightMap[x, y], (position.z + y)); tile.AddDecoration(fractalTree.GeneratePlants(pos, biome.BiomeType)); } if (noiseHeight >= TreeThreshold && placeTree && noiseHeight <= TreeThreshold + MarginThreshold) { int jitterValue = Mathf.RoundToInt((float)(perlin.GetValue(sampleY + terrainGenerator.RandomNumbers[x], 0, sampleX + terrainGenerator.RandomNumbers[y])) * 5); // Prevent jitterValue to exceed index elemends if (jitterValue > 5 || jitterValue < -5) { jitterValue = 5; } Vector3 pos = new Vector3(position.x + 5 + jitterValue, heightMap[5 + jitterValue, 5 + jitterValue], position.z + 5 + jitterValue); // Check Biome again for Tree Placement Biome biome2 = terrainGenerator.GetBiomeByCoordinates(new Vector2(pos.x, pos.z)); if (biome2.BiomeType is DefaultBiomeType || biome2.BiomeType is ForestBiomeType || biome2.BiomeType is PlainsBiomeType || biome2.BiomeType is ShrublandBiomeType) { tile.AddDecoration(fractalTree.GenerateTree(pos, biome.BiomeType)); placeTree = false; } } } } } }
// When thread is done set all the unity specific values private void OnTileDataReceived(TileData tileData) { Tile currentTile = WorldBuilder.GetTile(tileData.offsets); // Check to see if the current tile is not already unloaded if (currentTile != null) { Vector2 offsets = new Vector2(tileData.offsets.x, tileData.offsets.z); Vector2 cityOffsets = new Vector2(tileData.offsets.x - 5, tileData.offsets.z - 5); currentTile.HeightMap = tileData.heightMap; caveBuilder.Instantiate(tileData.offsets); grassMap = new Texture2D(TILE_DIMENSION, TILE_DIMENSION); splatmapsArray = new Texture2DArray(TILE_DIMENSION, TILE_DIMENSION, 3, TextureFormat.RGBA32, true); int levelOfDetail = WorldBuilder.GetTile(tileData.offsets).LevelOfDetail; splatmapsArray.SetPixels(tileData.splatMap1, 0); splatmapsArray.SetPixels(tileData.splatMap2, 1); splatmapsArray.SetPixels(tileData.splatMap3, 2); grassMap.SetPixels(tileData.grassMap); splatmapsArray.wrapMode = TextureWrapMode.Clamp; splatmapsArray.Apply(); grassMap.wrapMode = TextureWrapMode.Clamp; grassMap.Apply(); Material[] matArray = currentTile.Terrain.MeshRenderer.materials; matArray[0].SetTexture("_SplatMaps", splatmapsArray); matArray[1].SetTexture("_GrassSplatMap", grassMap); currentTile.Terrain.MeshRenderer.materials = matArray; GameObject ocean = currentTile.Ocean.GameObject; ocean.SetActive(tileData.hasOcean); MeshData meshData = GenerateMesh(levelOfDetail, tileData.heightMap, false); SetMesh(meshData.CreateMesh(), currentTile); currentTile.Terrain.GameObject.SetActive(true); cityGenerator.Generate(cityOffsets); decorationGenerator.Generate(tileData.heightMap, tileData.offsets); } }