public static TerrainData GenerateRiver(TerrainData data, TerrainSettings settings) { for (int i = 0; i < settings.numberOfRivers; i++) { // Find all potential river starting places List <TileData> potentialStarts = GetPotentialRiverStarts(data); if (potentialStarts.Count < settings.numberOfRivers) { return(data); } TileData start = potentialStarts[Random.Range(0, potentialStarts.Count)]; // pick random start potentialStarts.Remove(start); TileData oceanTile = data.GetEdgeAdjacentTilesOfType(start.xCoordinate, start.zCoordinate, TileType.OceanFloor)[0]; start.type = TileType.RiverMouth; // Construct river List <TileData> riverPath = new List <TileData>(); riverPath.Add(start); int nextXCoordinate = start.xCoordinate + (start.xCoordinate - oceanTile.xCoordinate); int nextZCoordinate = start.zCoordinate + (start.zCoordinate - oceanTile.zCoordinate); TileData currentTile = data.GetTileAtCoordinates(nextXCoordinate, nextZCoordinate); currentTile.type = TileType.RiverStraight; TileData nextTile = null; for (int j = 0; j < settings.riverMaxLength; j++) { List <TileData> potentialNextTiles = data.GetEdgeAdjacentTilesOfType(currentTile.xCoordinate, currentTile.zCoordinate, TileType.Plains); potentialNextTiles.Remove(riverPath[j]); // Remove all left turn tiles for (int k = 0; k < potentialNextTiles.Count; k++) { Vector2 pastDirection = new Vector2(riverPath[j].xCoordinate - currentTile.xCoordinate, riverPath[j].zCoordinate - currentTile.zCoordinate); Vector2 futureDirection = new Vector2(potentialNextTiles[k].xCoordinate - currentTile.xCoordinate, potentialNextTiles[k].zCoordinate - currentTile.zCoordinate); if (Vector2.SignedAngle(pastDirection, futureDirection) == -90) { potentialNextTiles.Remove(potentialNextTiles[k]); } } // If no more potential tiles, end river if (potentialNextTiles.Count == 0 || j == settings.riverMaxLength - 1) { currentTile.type = TileType.RiverEnd; } else // otherwise make either straight or right turn { nextTile = potentialNextTiles[Random.Range(0, potentialNextTiles.Count)]; Vector2 directionOne = new Vector2(riverPath[j].xCoordinate - currentTile.xCoordinate, riverPath[j].zCoordinate - currentTile.zCoordinate); Vector2 directionTwo = new Vector2(nextTile.xCoordinate - currentTile.xCoordinate, nextTile.zCoordinate - currentTile.zCoordinate); if (Vector2.SignedAngle(directionOne, directionTwo) == 90) { currentTile.type = TileType.RiverBendRight; } else if (Vector2.SignedAngle(directionOne, directionTwo) == -90) { currentTile.type = TileType.RiverEnd; } else { currentTile.type = TileType.RiverStraight; } } // correctly orient tile Vector3 facingDirection = new Vector3(riverPath[j].xCoordinate - currentTile.xCoordinate, 0, riverPath[j].zCoordinate - currentTile.zCoordinate); facingDirection = facingDirection.normalized; if (facingDirection == Vector3.left) { currentTile.Rotate(0, 90, 0); currentTile.AddPosition(0, 0, settings.tileSize); } else if (facingDirection == Vector3.forward) { currentTile.Rotate(0, 180, 0); currentTile.AddPosition(settings.tileSize, 0, settings.tileSize); } else if (facingDirection == Vector3.right) { currentTile.Rotate(0, -90, 0); currentTile.AddPosition(settings.tileSize, 0, 0); } // if the river has ended, break from the loop if (currentTile.type == TileType.RiverEnd) { break; } riverPath.Add(currentTile); currentTile = nextTile; } } return(data); }
public static TerrainData GenerateCoasts(TerrainData data, TerrainSettings settings) { // first get rid of islands/peninsulas data = RemoveIsolatedOceanTiles(data, settings); data = RemoveIslandsAndPeninsulas(data, settings); for (int x = 0; x < data.xSize; x++) { for (int z = 0; z < data.zSize; z++) { List <TileData> edgeAdjacentOcean = data.GetEdgeAdjacentTilesOfType(x, z, TileType.OceanFloor); if (!data.IsOceanTile(x, z) && edgeAdjacentOcean.Count > 0) { if (edgeAdjacentOcean.Count == 1) // coastal straight { Vector3 direction = edgeAdjacentOcean[0].Position - data.GetTileAtCoordinates(x, z).Position; direction = direction.normalized; Vector3 position = new Vector3(x * settings.tileSize, 0, z * settings.tileSize); TileData tile = data.GetTileAtCoordinates(x, z); tile.ReplaceTile(TileType.CoastStraight, position, Vector3.zero); if (direction == -Vector3.forward) { tile.Rotate(0, 180, 0); tile.AddPosition(new Vector3(settings.tileSize, 0, settings.tileSize)); } else if (direction == Vector3.right) { tile.Rotate(0, 90, 0); tile.AddPosition(new Vector3(0, 0, settings.tileSize)); } else if (direction == -Vector3.right) { tile.Rotate(0, 270, 0); tile.AddPosition(new Vector3(settings.tileSize, 0, 0)); } } else if (edgeAdjacentOcean.Count == 2) { Vector3 directionOne = edgeAdjacentOcean[0].Position - data.GetTileAtCoordinates(x, z).Position; directionOne = directionOne.normalized; Vector3 directionTwo = edgeAdjacentOcean[1].Position - data.GetTileAtCoordinates(x, z).Position; directionTwo = directionTwo.normalized; if (Vector3.Angle(directionOne, directionTwo) <= 90) // coastal outer corner { Vector3 position = new Vector3(x * settings.tileSize, 0, z * settings.tileSize); TileData tile = data.GetTileAtCoordinates(x, z); tile.ReplaceTile(TileType.CoastOuterCorner, position, Vector3.zero); if (directionOne == Vector3.forward && directionTwo == -Vector3.right || directionTwo == Vector3.forward && directionOne == -Vector3.right) { tile.Rotate(0, -90, 0); tile.AddPosition(new Vector3(settings.tileSize, 0, 0)); } else if (directionOne == Vector3.right && directionTwo == -Vector3.forward || directionTwo == Vector3.right && directionOne == -Vector3.forward) { tile.Rotate(0, 90, 0); tile.AddPosition(new Vector3(0, 0, settings.tileSize)); } else if (directionOne == -Vector3.forward && directionTwo == -Vector3.right || directionTwo == -Vector3.forward && directionOne == -Vector3.right) { tile.Rotate(0, 180, 0); tile.AddPosition(new Vector3(settings.tileSize, 0, settings.tileSize)); } } } } List <TileData> cornerAdjacentOcean = data.GetCornerAdjacentTilesOfType(x, z, TileType.OceanFloor); if (cornerAdjacentOcean.Count == 1 && edgeAdjacentOcean.Count == 0) // coastal inner corner { Vector3 direction = cornerAdjacentOcean[0].Position - data.GetTileAtCoordinates(x, z).Position; direction = direction.normalized; Vector3 position = new Vector3(x * settings.tileSize, 0, z * settings.tileSize); TileData tile = data.GetTileAtCoordinates(x, z); tile.ReplaceTile(TileType.CoastInnerCorner, position, Vector3.zero); float angle = Vector3.SignedAngle(direction, Vector3.forward, Vector3.up); if (angle > 90 && angle <= 180) { tile.Rotate(0, -90, 0); tile.AddPosition(new Vector3(settings.tileSize, 0, 0)); } else if (angle < -90 && angle >= -180) { tile.Rotate(0, 180, 0); tile.AddPosition(new Vector3(settings.tileSize, 0, settings.tileSize)); } else if (angle < 0 && angle >= -90) { tile.Rotate(0, 90, 0); tile.AddPosition(new Vector3(0, 0, settings.tileSize)); } } } } // do a final check for islands and peninsulas data = RemoveIslandsAndPeninsulas(data, settings); return(data); }