void GenMap() { //print("GenMap"); int col, row; Color cellColor; float temp; // temp in celcius float elevation; // elevation in meters float percipitation; // annual percepitation in cm Vector3 worldPos; Vector2 uv; HexCell hexCell; Hex hex; float percipGraph; float[,] compressionArray; float[,] bluredCompressionArray; temperatureArray = new float[columns, rows]; plateArray = new int[columns, rows]; edgeDistArray = new float[columns, rows]; biomeArray = new Biomes[columns, rows]; terrainArray = new Terrain[columns, rows]; Random.InitState(seed); if (m_icons != null) { // Clear All Icons foreach (GameObject icon in m_icons) { Destroy(icon); } m_icons.Clear(); } m_icons = new List <GameObject>(); // Create Voronoi points // remove existing dots if (m_dots != null) { foreach (GameObject dot in m_dots) { Destroy(dot); } } Plate[] plates; // Calulate Plates plates = GeneratePlates(); Vector2 plateNoiseOffset; plateNoiseOffset.x = Random.value * 1000; plateNoiseOffset.y = Random.value * 1000; elevationArray = new float[columns, rows]; compressionArray = new float[columns, rows]; for (col = 0; col < columns; col++) { for (row = 0; row < rows; row++) { hex = OffsetToHex(col, row); worldPos = HexToWorld(hex); uv = HexToUniform(hex); Vector2 modifiedUV; // Determin plate id float closestDist = 1000000; float secondClosestDist = 1000000; float dist; int firstCellID = -1; int secondCellID = -1; Vector2 noiseCoord = uv + plateNoiseOffset; float noiseValX = FM.Noise(noiseCoord.x, noiseCoord.y, m_plateNoiseFreq, 1, 2, 0.5f, m_plateNoiseOctives); float noiseValY = FM.Noise(noiseCoord.x + 3417, noiseCoord.y, m_plateNoiseFreq, 1, 2, 0.5f, m_plateNoiseOctives); modifiedUV = uv + (new Vector2(noiseValX, noiseValY) - new Vector2(0.5f, 0.5f)) * m_plateNoiseAmp; Vector2 realUV = UniformToUV(modifiedUV); int sampleCol = Mathf.FloorToInt(realUV.x * cellColumns); int sampleRow = Mathf.FloorToInt(realUV.y * cellRows); // This code might be f****d. for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { // offset to check neighbors int cellCol = sampleCol + (i - 1); int cellRow = sampleRow + (j - 1); if (cellRow < 0 || cellRow >= cellRows) // row is above/below map { continue; } int wrapOffset = (cellCol / cellColumns); cellCol = (cellCol + cellColumns) % cellColumns; int plateIndex = cellCol * cellRows + cellRow; Hex vhex = plates[plateIndex].hexLocation; Vector2 plateUV = HexToUniform(vhex); plateUV.x += wrapOffset; //Vector3 vWorld = HexToWorld(vhex); bool useHexDistance = false; if (useHexDistance) { dist = HexDistance(hex, vhex); } else { dist = Vector2.Distance(modifiedUV, plateUV); } if (dist < closestDist) { secondCellID = firstCellID; secondClosestDist = closestDist; firstCellID = plateIndex; closestDist = dist; } else if (dist < secondClosestDist) { secondCellID = plateIndex; secondClosestDist = dist; } } } // calculate compression plateArray[col, row] = firstCellID; Plate firstPlate = plates[firstCellID]; Plate secondPlate = plates[secondCellID]; // if (m_debug) // { // Vector2 firstPlatePostion = HexToUniform(firstPlate.hexLocation); // Vector2 secondPlatePostion = HexToUniform(secondPlate.hexLocation); // Vector2 midPoint = (firstPlatePostion + secondPlatePostion)/2f; // Vector2 axis = (secondPlatePostion - firstPlatePostion); // //float edgeToCenterDist = axis.magnitude /2; // axis.Normalize(); // normalize vector for further math; // float edgeDist = Vector3.Dot((modifiedUV - midPoint),-axis); // find the distance from the edge with vector projection. // //edgeDist /= edgeToCenterDist; // normalize edgeDist; // //float dotProd = Vector2.Dot(firstPlate.force,secondPlate.force); // //float divergence = Utils.Map(dotProd,-1,0,1,0); // remap from -1:1 to 1:0 // float compression = (Vector2.Dot(axis,firstPlate.force) + Vector2.Dot(-axis,secondPlate.force))/2; // //compression *= divergence; // float ridgeDistance = Mathf.Max(0.001f, m_techtonicBorderWidth/10 * Mathf.Abs(compression)); // float edgeWeight = Mathf.Clamp01(1-edgeDist/ridgeDistance); // edgeWeight = Mathf.Pow(edgeWeight,2); // compression *= edgeWeight; // compressionArray[col,row] = compression; // // edgeDistArray[col,row] = edgeWeight; // } // bool isContinental = plates[firstCellID].isContinental; // if (isContinental == true) // { // height = Mathf.Lerp(0.05f, 0.15f, Random.value); // land height // } // else // { // height = Mathf.Lerp(-0.15f, -0.05f, Random.value); // water height // } elevationArray[col, row] = firstPlate.elevation; } } // Calculate Elevation Hex sampleHex; Vector2 direction; if (!m_debug) { for (col = 0; col < columns; col++) { for (row = 0; row < rows; row++) { hex = OffsetToHex(col, row); Plate firstPlate, secondPlate; int cellID = plateArray[col, row]; firstPlate = plates[cellID]; float compression = 0; int sampleCount = 0; int secondCellID; foreach (Hex dir in directions) { sampleHex = new Hex(hex.q + dir.q, hex.r + dir.r); if (IsHexValid(sampleHex)) { OffsetCoords coords = HexToOffset(sampleHex); secondCellID = plateArray[coords.column, coords.row]; sampleCount++; if (secondCellID == cellID) { continue; } secondPlate = plates[secondCellID]; direction = (Vector2)HexToWorld(dir, false).normalized; compression += Vector2.Dot(firstPlate.force, direction); compression += Vector2.Dot(secondPlate.force, direction * -1); } } compression /= sampleCount; if (firstPlate.isContinental) { compression *= 1.5f; } compressionArray[col, row] = compression; } } } bluredCompressionArray = new float[columns, rows]; convolveHexArray(compressionArray, bluredCompressionArray, 3); convolveHexArray(compressionArray, compressionArray, 1); // convovle base a little; convolveHexArray(elevationArray, elevationArray, 3); // randomize noiseOffset Vector2 noiseOffset; noiseOffset.x = Random.value * gridWidth * 10; noiseOffset.y = Random.value * gridHeight * 10; // deform elevation based on compression and noise for (col = 0; col < columns; col++) { for (row = 0; row < rows; row++) { hex = OffsetToHex(col, row); worldPos = HexToWorld(hex); hexCell = GetHexCell(hex); uv = HexToUniform(hex); //int cellID = plateArray[col,row]; //Plate firstPlate = plates[cellID]; float height = elevationArray[col, row]; Vector3 noisePos = worldPos + new Vector3(worldOffset.x, worldOffset.y, 0) * -1.5f + new Vector3(noiseOffset.x, noiseOffset.y, 0); float noiseVal = FM.Noise(noisePos.x, noisePos.y, frequency, 1, lacunarity, gain, octaves); height += Utils.Map(noiseVal, 0, 1, -1f, 1f) * amplitude; float totalMountainHeight = 0; float localMountainHeight = 0; bool isMountain = false; if (m_doTechtonicCompression) { float bluredCompression = bluredCompressionArray[col, row]; float originalCompression = compressionArray[col, row]; float modifiedCompression = Mathf.Max(bluredCompression, originalCompression); bluredCompressionArray[col, row] = modifiedCompression; // for visulization purposes //bluredCompression *= 1f; //bluredCompression = Mathf.Pow(Mathf.Abs(bluredCompression),1.3f) * Mathf.Sign(bluredCompression); // pow 2 totalMountainHeight += modifiedCompression * m_mountainBaseHeight * noiseVal; // Mountain peaks should be random looking in elevation; float mountainRandom = Mathf.Pow(Random.value, 2); localMountainHeight = m_mountainHeight * modifiedCompression * mountainRandom; totalMountainHeight += localMountainHeight; isMountain = mountainRandom > Utils.Map(originalCompression, 0.001f, 0.2f, 1, 0); // magic numbers height += totalMountainHeight; } elevation = Utils.Map(height, -1, 1, -10000, 10000); // elevation in meters if (elevation > 3000) { isMountain = true; } if (isMountain) // add mountain icon to compressed areas { GameObject mountainIconSelection = null; if (elevation < 0) { mountainIconSelection = oceanicMountainIcon; } else if (elevation > 600) { mountainIconSelection = mountainIcon; } if (mountainIconSelection != null) { GameObject mountain = Instantiate(mountainIconSelection, worldPos, Quaternion.identity, transform) as GameObject; m_icons.Add(mountain); } } if (elevation < 0) { terrainArray[col, row] = Terrain.Ocean; } else if (isMountain) { terrainArray[col, row] = Terrain.Mountains; } else { terrainArray[col, row] = Terrain.Plains; } elevationArray[col, row] = elevation; hexCell.elevation = elevation; } } // calculate temp for (col = 0; col < columns; col++) { for (row = 0; row < rows; row++) { hex = OffsetToHex(col, row); worldPos = HexToWorld(hex); hexCell = GetHexCell(hex); uv = HexToUV(hex); elevation = elevationArray[col, row]; // Calculate Temperature float latitude = uv.y * 180 - 90; float temp01 = Mathf.Cos(latitude * Mathf.Deg2Rad); temp = Utils.Map(temp01, 0, 1, minTemp, maxTemp); //Temp by Elevation if (elevation > 0) { temp = temp - lapseRate * (elevation / 1000); } temperatureArray[col, row] = temp; } } // Calculate Climate CalculatePercipitation(); // Final Calculations for (col = 0; col < columns; col++) { for (row = 0; row < rows; row++) { hex = OffsetToHex(col, row); worldPos = HexToWorld(hex); hexCell = GetHexCell(hex); uv = HexToUV(hex); elevation = elevationArray[col, row]; temp = temperatureArray[col, row]; // //Calculate Moisture // waterCells = 0; // int sampleCol; // for (int i = 1; i<=percipSearchDist; i++) // { // sampleCol = (col +i) % columns; // sampleHex = OffsetToHex(sampleCol,row); // sampleCell = GetHexCell(sampleHex); // if (sampleCell.elevation <= 0) // { // waterCells ++; // } // } // percipitation = Utils.Map(waterCells,0,percipSearchDist,0,450); // // Modulate percipitation by temperature; // percipitation *= Utils.Map (temp,-10,30,0,1); percipitation = percipArray[col, row] * 450; if (biomeMap) { elevation = 1; temp = Utils.Map(uv.x, 0, 1, 30, -30); percipitation = Utils.Map(uv.y, 0, 1, 0, 450); } Biomes biome; if (elevation > 0) { // Calculate Biome biome = CalcBiome(temp, percipitation); switch (biome) { case Biomes.Grassland: cellColor = grasslandColor; break; case Biomes.TropicalRainForest: cellColor = tropicalRainForestColor; break; case Biomes.Forrest: cellColor = forrestColor; break; case Biomes.Taiga: cellColor = TaigaColor; break; case Biomes.Tundra: cellColor = tundraColor; break; case Biomes.Desert: cellColor = desertColor; break; case Biomes.Snow: cellColor = snowColor; break; default: cellColor = Color.red; break; } cellColor = Color.Lerp(cellColor, Color.white, (elevation - 750) / 5000); } else // hex is oceanic { biome = Biomes.Oceanic; float lerpValue = Utils.Map(elevation, -10000, 0, 0, 1); cellColor = Color.Lerp(WaterColorBottom, WaterColorTop, lerpValue); } biomeArray[col, row] = biome; float humidity = humidityArray[col, row]; string biomeString = biome == Biomes.TropicalRainForest ? "RainForest" : biome.ToString(); string displayText = string.Format("{0,5:f1}c, {1,5:f0} p, {2,5:f2} h, {3,8:f1} elv, {4}", temp, percipitation, humidity, elevation, biomeString); //displayText = hex.ToString(); hexCell.SetText(displayText); // cellColor = new Color(uv.x,uv.y,0); float tempGraph = Utils.Map(temp, -30, 30, 0, 1); percipGraph = Utils.Map(percipitation, 0, 450, 0, 1); if (showTemp || showPercip) { cellColor = Color.black; if (showTemp) { cellColor.r = tempGraph; } if (showPercip) { cellColor.g = percipGraph; } } if (showPlates) { int cellID = plateArray[col, row]; Plate plate = plates[cellID]; float value = (cellID * 18241.845f) % 1; cellColor = Color.black; if (plate.isContinental) { cellColor.g = Mathf.Lerp(0.3f, 1, value); } else { cellColor.b = Mathf.Lerp(0.3f, 1, value); } cellColor.r = ((value * 3.23f + 0.42f) % 1) / 3; //cellColor = Color.HSVToRGB(value,0.8f,0.8f); } else if (showElevation) { float relElevation = Utils.Map(elevation, -10000, 10000, 0, 1); cellColor = Color.black; if (elevation > 0 || true) { cellColor.r = relElevation; cellColor.g = relElevation; cellColor.b = relElevation; } else { cellColor.b = relElevation * 2; } } else if (showCompression) { float compression = bluredCompressionArray[col, row]; cellColor.r = compression; cellColor.g = 0; cellColor.b = compression * -1; } else if (showEdgeDist) { float edgeDist = edgeDistArray[col, row]; cellColor.r = edgeDist; cellColor.g = cellColor.r; cellColor.b = cellColor.r; } hexCell.SetColor(cellColor); if (showText == true) { hexCell.ShowText(); } else { hexCell.HideText(); } } } // Send event to signal map generation if (OnMapGeneration != null) { OnMapGeneration(); } }