Esempio n. 1
0
    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();
        }
    }