Esempio n. 1
0
        public static void PopulateWithInitialData(TimelineLayer board, NamelessGame game)
        {
            var resolution = WorldGenConstants.Resolution;

            var random = new InternalRandom(game.WorldSettings.GlobalRandom.Next());


            for (int x = 0; x < game.WorldSettings.WorldBoardWidth; x++)
            {
                for (int y = 0; y < game.WorldSettings.WorldBoardHeight; y++)
                {
                    var worldTile = new WorldTile(new Microsoft.Xna.Framework.Point(x, y));
                    var tile      = game.WorldSettings.TerrainGen.GetTileWithoutRiverWater(x, y, (float)game.WorldSettings.WorldBoardWidth / resolution);
                    worldTile.Terrain = tile.Terrain;
                    worldTile.Biome   = tile.Biome;

                    board.WorldTiles[x, y] = worldTile;
                }
            }


            //generate elevation map for river gen
            for (int i = 0; i < resolution; i++)
            {
                for (int j = 0; j < resolution; j++)
                {
                    //fill it with terrain heght with current noises using resolution
                    board.ElevationMap[i][j] = game.WorldSettings.TerrainGen.GetHeightNoise(i, j, 1);
                }
            }

            //copy elevationArray
            var fillArray = new TileForGeneration[resolution][];

            for (int i = 0; i < resolution; i++)
            {
                fillArray[i] = new TileForGeneration[resolution];
                for (int j = 0; j < resolution; j++)
                {
                    fillArray[i][j] = new TileForGeneration()
                    {
                        fillValue = board.ElevationMap[i][j], x = i, y = j, isWater = false
                    };
                }
            }

            List <FortuneSite> points = new List <FortuneSite>();
            LinkedList <VEdge> edges  = new LinkedList <VEdge>();

            for (var i = 0; i < resolution; i++)
            {
                points.Add(new FortuneSite(
                               random.Next(0, resolution - 1),
                               random.Next(0, resolution - 1)));
            }

            //uniq the points
            points.Sort((p1, p2) =>
            {
                if (p1.X.ApproxEqual(p2.X))
                {
                    if (p1.Y.ApproxEqual(p2.Y))
                    {
                        return(0);
                    }
                    if (p1.Y < p2.Y)
                    {
                        return(-1);
                    }
                    return(1);
                }
                if (p1.X < p2.X)
                {
                    return(-1);
                }
                return(1);
            });

            var unique = new List <FortuneSite>(points.Count / 2);
            var last   = points.First();

            unique.Add(last);
            for (var index = 1; index < points.Count; index++)
            {
                var point = points[index];
                if (!last.X.ApproxEqual(point.X) ||
                    !last.Y.ApproxEqual(point.Y))
                {
                    unique.Add(point);
                    last = point;
                }
            }
            points = unique;

            edges = FortunesAlgorithm.Run(points, 0, 0, resolution - 1, resolution - 1);

            //VEdge.Start is a VPoint with location VEdge.Start.X and VEdge.End.Y
            //VEdge.End is the ending point for the edge
            //FortuneSite.Neighbors contains the site's neighbors in the Delaunay Triangulation


            var waterBitmap = new Bitmap(resolution, resolution);

            var graphics = Graphics.FromImage(waterBitmap);

            Pen whitePen = new Pen(System.Drawing.Color.White, 1);

            var edgesByTheSea = edges.Where(
                x =>
                board.ElevationMap[(int)x.Start.X][(int)x.Start.Y] < TileNoiseInterpreter.SeaLevelThreshold &&
                board.ElevationMap[(int)x.End.X][(int)x.End.Y] >= TileNoiseInterpreter.SeaLevelThreshold ||

                board.ElevationMap[(int)x.End.X][(int)x.End.Y] < TileNoiseInterpreter.SeaLevelThreshold &&
                board.ElevationMap[(int)x.Start.X][(int)x.Start.Y] >= TileNoiseInterpreter.SeaLevelThreshold
                );

            var allInlandEdges = edges.Where(
                x =>
                board.ElevationMap[(int)x.End.X][(int)x.End.Y] >= TileNoiseInterpreter.SeaLevelThreshold &&
                board.ElevationMap[(int)x.Start.X][(int)x.Start.Y] >= TileNoiseInterpreter.SeaLevelThreshold
                ).ToList();

            //randommly remove some rivers;
            var cullingChance = 15;
            var culledEdges   = allInlandEdges.Where(edge => random.Next(1, 101) > cullingChance).ToList();

            culledEdges.AddRange(edgesByTheSea.Where(edge => random.Next(1, 101) > cullingChance));

            //remove desert rivers with high probability
            var cullingDesertChance = 90;

            //if not in desert biome ignore, if in desert, cull with high probability
            culledEdges = culledEdges.Where(edge =>
                                            (board.WorldTiles[(int)edge.Start.X, (int)edge.Start.Y].Biome.HasFlag(Biomes.Desert | Biomes.Jungle | Biomes.Savannah) &&
                                             board.WorldTiles[(int)edge.End.X, (int)edge.End.Y].Biome.HasFlag(Biomes.Desert | Biomes.Jungle | Biomes.Savannah)) ||
                                            random.Next(1, 101) < cullingDesertChance).ToList();

            var finalEdges = new List <VEdge>();

            finalEdges.AddRange(culledEdges);

            foreach (var edge in finalEdges)
            {
                var pointCountForLerpAndRandomization = 7;

                var listVectorEdgePoints = new List <Vector2>();
                var startVector          = new Vector2((float)edge.Start.X, (float)edge.Start.Y);
                var endVector            = new Vector2((float)edge.End.X, (float)edge.End.Y);
                var perpendicular        = (endVector - startVector);
                perpendicular.Normalize();
                perpendicular = new Vector2(perpendicular.Y, -perpendicular.X);



                listVectorEdgePoints.Add(startVector);

                var riverWiggle = 3;

                for (int i = 1; i < pointCountForLerpAndRandomization - 1; i++)
                {
                    var newPoint = Vector2.Lerp(startVector, endVector, ((float)i / (pointCountForLerpAndRandomization - 1))) + (perpendicular * (random.Next(-riverWiggle, riverWiggle)));
                    listVectorEdgePoints.Add(newPoint);
                }
                listVectorEdgePoints.Add(endVector);

                graphics.DrawCurve(whitePen, listVectorEdgePoints.Select(x => x.ToPoint().ToPoint()).ToArray());
            }

            for (int x = 3; x < resolution - 3; x++)
            {
                for (int y = 3; y < resolution - 3; y++)
                {
                    if (waterBitmap.GetPixel(x, y).R > 0)
                    {
                        //fillArray[x][y].isWater = true;

                        if (board.ElevationMap[x][y] >= TileNoiseInterpreter.SeaLevelThreshold)
                        {
                            fillArray[x][y].isWater = true;
                        }
                        else
                        {
                            Queue <TileForGeneration> neighbours = new Queue <TileForGeneration>();
                            GenerationUtility.GetNeighbours(fillArray, neighbours, x, y, 2);
                            if (neighbours.Any(n => board.ElevationMap[n.x][n.y] >= TileNoiseInterpreter.SeaLevelThreshold))
                            {
                                fillArray[x][y].isWater = true;
                            }
                        }
                    }
                }
            }


            for (int i = 0; i < resolution; i++)
            {
                for (int j = 0; j < resolution; j++)
                {
                    board.RiverMap[i][j] = fillArray[i][j].isWater;
                }
            }

            var riverBorderMapCopyForCalcultaion = new bool[resolution][];

            for (int i = 0; i < resolution; i++)
            {
                riverBorderMapCopyForCalcultaion[i] = new bool[resolution];
                for (int j = 0; j < resolution; j++)
                {
                    if (board.RiverMap[i][j])
                    {
                        bool borderedByAnythingBesidesWater = false;
                        //not really a radius, more like an side lenght of a square
                        var searchRadius = 3;
                        if (i > searchRadius && i < resolution - searchRadius && j > searchRadius && j < resolution - searchRadius)
                        {
                            for (int k = i - searchRadius; k < i + searchRadius + 1; k++)
                            {
                                for (int l = j - searchRadius; l < j + searchRadius + 1; l++)
                                {
                                    if (!board.RiverMap[k][l])
                                    {
                                        borderedByAnythingBesidesWater = true;
                                    }
                                }
                            }
                        }

                        if (borderedByAnythingBesidesWater)
                        {
                            board.RiverBorderMap[i][j]             = true;
                            riverBorderMapCopyForCalcultaion[i][j] = true;
                        }
                    }
                }
            }


            var pointsNotConnectedToStartingPoints = new List <TileForGeneration>();

            for (int i = 0; i < resolution; i++)
            {
                for (int j = 0; j < resolution; j++)
                {
                    if (board.RiverBorderMap[i][j])
                    {
                        pointsNotConnectedToStartingPoints.Add(fillArray[i][j]);
                    }
                }
            }


            GenerationUtility.AnalyzeAndAddLines(pointsNotConnectedToStartingPoints, riverBorderMapCopyForCalcultaion, out var borderLines);


            for (int i = 0; i < resolution; i++)
            {
                for (int j = 0; j < resolution; j++)
                {
                    board.InlandWaterConnectivity[i][j] = new TileForInlandWaterConnectivity()
                    {
                        x       = i,
                        y       = j,
                        isWater = board.RiverMap[i][j]
                    };
                }
            }

            foreach (var borderLine in borderLines)
            {
                var line = new WaterBorderLine()
                {
                    Points = borderLine.Select(p => new Microsoft.Xna.Framework.Point(p.x, p.y)).ToList()
                };
                board.BorderLines.Add(line);
                foreach (var p in line.Points)
                {
                    board.InlandWaterConnectivity[p.X][p.Y].WaterBorderLines.Add(line);
                }
            }
#if DEBUG
            ImageWriter.WaterWriteImage(board.RiverMap, board.ElevationMap, resolution, "C:\\11\\RiverMap.png", new Color(1, 0, 0, 1f));

            ImageWriter.WaterWriteImage(board.RiverBorderMap, board.ElevationMap, resolution, "C:\\11\\RiverBorderMap.png", new Color(1, 0, 0, 1f));

            ImageWriter.RiverBordersWriteImage(borderLines, board.ElevationMap, resolution, "C:\\11\\riverBordersLines.png");
#endif

            for (int x = 0; x < game.WorldSettings.WorldBoardWidth; x++)
            {
                for (int y = 0; y < game.WorldSettings.WorldBoardHeight; y++)
                {
                    var worldTile = board.WorldTiles[x, y];

                    if (board.RiverMap[x][y] && worldTile.Terrain != TerrainTypes.Water)
                    {
                        worldTile.Terrain = TerrainTypes.Water;
                        worldTile.Biome   = Biomes.River;
                    }
                }
            }
        }