Esempio n. 1
0
        /// <summary>
        /// Sets the decoration for a specific cell
        /// </summary>
        /// <param name="cell">The cell to set for</param>
        /// <param name="cellMappedData">The cell's mapped data</param>
        /// <param name="mesh">The decoration mesh</param>
        private void SetCellDecoration(Cell cell, CellMappedData cellMappedData, string decoration)
        {
            if (cellMappedData.Decoration.Key == decoration)
            {
                return;
            }

            // Free old decoration
            if (cellMappedData.Decoration.Key != null)
            {
                this.decorations[cellMappedData.Decoration.Key].FreeIndex(cellMappedData.Decoration.Value);
            }

            // Set new decoration
            if (decoration != null && decoration.Length > 0)
            {
                var index = this.decorations[decoration].GetFreeIndex();
                cellMappedData.Decoration = new KeyValuePair <string, int>(decoration, index);
                this.decorations[decoration].SetPosition(index, new Vector3(TopographyHelper.HexToWorld(cell.Coordinates), (float)cell.Elevation));
            }
            else
            {
                cellMappedData.Decoration = new KeyValuePair <string, int>(null, 0);
            }
        }
Esempio n. 2
0
        public void GenerateWorld(int radius)
        {
            double statLowestPoint     = double.MaxValue;
            double statHighestMountain = double.MinValue;
            int    statSeaTiles        = 0;

            Perlin perlin  = new Perlin(5);
            float  boundsX = TopographyHelper.HexToWorld(new Point(radius, 0)).X;
            float  boundsY = TopographyHelper.HexToWorld(new Point(0, radius)).Y;
            var    perlinZ = random.NextDouble();

            scene.WorldMap = new Map(radius);

            for (int p = -radius; p <= radius; p++)
            {
                for (int q = -radius; q <= radius; q++)
                {
                    var currentPoint = new Point(p, q);
                    var cell         = scene.WorldMap.GetCell(p, q);
                    if (cell == null)
                    {
                        continue;
                    }

                    // TODO: Remove Magic Numbers, put them in WorldSettings

                    // Set cell neighbors
                    cell.Neighbours = scene.WorldMap.GetNeighbours(currentPoint);

                    // Set cell height
                    var worldPoint  = TopographyHelper.HexToWorld(currentPoint);
                    var perlinPoint = (worldPoint + new Vector2(boundsX, boundsY)) * 0.01f;
                    var elevation   = perlin.OctavePerlin(perlinPoint.X, perlinPoint.Y, perlinZ, 4, 0.7);
                    // Flat valleys
                    elevation = Math.Pow(elevation, scene.Settings.ElevationPower);

                    // Actually multiply to max height
                    elevation *= scene.Settings.ElevationMultiplier;

                    // Give cells closer to the edge of the map a negative bias. This means the entire map will be surrounded by oceans.
                    var distanceFromEdge = (radius - TopographyHelper.Distance(new Point(0, 0), currentPoint)) / radius;
                    if (distanceFromEdge < 0 || distanceFromEdge > 1)
                    {
                        throw new Exception("Value out of range, check math");
                    }
                    cell.Elevation = elevation * Math.Pow(distanceFromEdge, scene.Settings.EdgeDistancePower);

                    // Update stats
                    if (cell.Elevation > statHighestMountain)
                    {
                        statHighestMountain = cell.Elevation;
                    }
                    if (cell.Elevation < statLowestPoint)
                    {
                        // Now all data has been set, calculate the modifiers
                        statLowestPoint = cell.Elevation;
                    }

                    // Set wetness by rain
                    var rain = perlin.OctavePerlin(perlinPoint.X, perlinPoint.Y, perlinZ * 100, 2, 0.7) * scene.Settings.RainMultiplier;
                    cell.Wetness = rain;
                }
            }

            // Creates oceans by flood filling from map edge
            FloodFillOceans();

            // Do final touchups and modifier calculation
            // TODO: This can contain NULL cells, this is bad
            var cells = scene.WorldMap.Cells;

            foreach (var cell in cells)
            {
                if (cell == null)
                {
                    continue;
                }

                // Remove single-cell 'seas' and islands
                if (cell.IsWater)
                {
                    bool canBeWater = false;
                    foreach (var n in cell.Neighbours)
                    {
                        if (n.IsWater)
                        {
                            canBeWater = true; break;
                        }
                    }
                    cell.IsWater = canBeWater;
                }
                else
                {
                    bool canBeLand = false;
                    foreach (var n in cell.Neighbours)
                    {
                        if (!n.IsWater)
                        {
                            canBeLand = true; break;
                        }
                    }
                    cell.IsWater = !canBeLand;
                }

                // Calculate temperature
                var distanceFromEdge = (radius - TopographyHelper.Distance(new Point(0, 0), cell.Coordinates)) / radius;
                var temperature      = MathHelper.Lerp(scene.Settings.PoleTemperature, scene.Settings.EquatorTemperature,
                                                       (float)Math.Pow(distanceFromEdge, scene.Settings.TemperatureCurvePower));
                var relElevation = (float)cell.Elevation - scene.Settings.SeaLevel;
                if (!cell.IsWater)
                {
                    // Ocean tiles should have temperature at sea level only, otherwise use altitude multiplier
                    temperature += relElevation * scene.Settings.ElevationTemperatureMultiplier;
                }
                cell.Temperature = temperature;

                // Set values
                if (cell.IsWater == true)
                {
                    statSeaTiles++;
                    cell.FoodMod     = random.NextDouble() + random.Next(1, 2);
                    cell.ResourceMod = random.NextDouble() + random.Next(1, 2);
                    cell.MaxHousing  = 0;
                }
                else
                {
                    // Now all data has been set, calculate the modifiers
                    cell.FoodMod     = random.NextDouble() + random.Next(1, 5);
                    cell.ResourceMod = random.NextDouble() + random.Next(1, 5);
                    cell.WealthMod   = random.NextDouble() + random.Next(1, 5);

                    cell.MaxHousing = random.Next(0, 1250) + random.Next(0, 1250) + random.Next(0, 1250) + random.Next(0, 1250);
                }

                // Set biome
                AssignBiome(cell);
            }

            //SimulateWaterflow();

            // Log stats
            Debug.WriteLine("Stats for World Generation");
            Debug.WriteLine("Highest Point: " + statHighestMountain);
            Debug.WriteLine("Lowest Point:  " + statLowestPoint);
            Debug.WriteLine("Ocean Cells:   " + statSeaTiles);
            Debug.WriteLine("Land Cells:    " + (scene.WorldMap.CellCount - statSeaTiles));
            Debug.WriteLine("Water coverage:" + ((float)statSeaTiles / scene.WorldMap.CellCount * 100).ToString("##.##") + "%");
        }
Esempio n. 3
0
        /// <summary>
        /// Generates terrain meshes, cell and biome data from a scene. Can be put in a task.
        /// </summary>
        /// <param name="scene">The scene to generate from</param>
        /// <returns>Results</returns>
        private MeshGenerationResult GenerateMeshesFromScene(Scene scene)
        {
            // Results
            var renderableMeshes = new List <RenderableMesh>();
            var rawMeshes        = new List <Mesh>();
            var cellData         = new Dictionary <Cell, CellMappedData>();
            // Stopwatch used for performance logging
            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            // Create world meshes
            var hexCombiner = new MeshCombiner();
            int range       = scene.WorldMap.Radius;

            for (int p = -range; p <= range; p++)
            {
                for (int q = -range; q <= range; q++)
                {
                    var cell = scene.WorldMap.GetCell(p, q);
                    // Due to the hexagonal shape we might be out of bounds
                    if (cell == null)
                    {
                        continue;
                    }

                    var  worldPoint = TopographyHelper.HexToWorld(new Point(p, q));
                    var  position   = new Vector3(worldPoint, (float)cell.Elevation);
                    var  color      = GetCellColor(cell);
                    Mesh mesh       = biomeMappedData[cell.Biome.Name].HexMesh;

                    // Ensure sea is actually level
                    if (cell.IsWater && cell.Elevation < scene.Settings.SeaLevel)
                    {
                        position.Z = scene.Settings.SeaLevel;
                    }

                    // Add it to the combiner, using the cell's location as a tag so we can later
                    // get the vertexes of this hex inside the larger mesh
                    int meshIndex = hexCombiner.Add(new MeshInstance
                    {
                        mesh     = mesh,
                        matrix   = Matrix.CreateTranslation(position),
                        tag      = new Point(p, q),
                        color    = color,
                        useColor = true,
                    });

                    // Register partial cell mapped data to be used later
                    var cellMappedData = new CellMappedData
                    {
                        MeshIndex = meshIndex
                    };
                    cellData[cell] = cellMappedData;
                }
            }

            // Combine meshes
            var meshList = hexCombiner.GetCombinedMeshes();

            for (int i = 0; i < meshList.Count; i++)
            {
                var renderable = new RenderableMesh(orbis.GraphicsDevice, meshList[i]);
                renderableMeshes.Add(renderable);
            }
            // Finish cell mapped data
            foreach (var cell in cellData)
            {
                var mesh = meshList[cell.Value.MeshIndex];
                cell.Value.VertexIndexes = mesh.TagIndexMap[cell.Key.Coordinates];
            }

            stopwatch.Stop();
            Debug.WriteLine("Generated " + renderableMeshes.Count + " meshes in " + stopwatch.ElapsedMilliseconds + " ms");

            return(new MeshGenerationResult {
                cellData = cellData,
                rawMeshes = rawMeshes,
                renderableMeshes = renderableMeshes
            });
        }