private void GenerateJaggedLines()
 {
     foreach (LocationConnection connection in connections)
     {
         Vector2 start       = connection.Locations[0].MapPosition;
         Vector2 end         = connection.Locations[1].MapPosition;
         int     generations = (int)(Math.Sqrt(Vector2.Distance(start, end) / 10.0f));
         //connection.CrackSegments = MathUtils.GenerateJaggedLine(start, end, generations, 5.0f);
         connection.CrackSegments = MathUtils.GenerateJaggedLine(start, end, generations, 0.0f);
     }
 }
Exemple #2
0
 partial void GenerateLocationConnectionVisuals()
 {
     foreach (LocationConnection connection in Connections)
     {
         Vector2 connectionStart  = connection.Locations[0].MapPosition;
         Vector2 connectionEnd    = connection.Locations[1].MapPosition;
         float   connectionLength = Vector2.Distance(connectionStart, connectionEnd);
         int     iterations       = Math.Min((int)Math.Sqrt(connectionLength * generationParams.ConnectionIndicatorIterationMultiplier), 5);
         connection.CrackSegments.Clear();
         connection.CrackSegments.AddRange(MathUtils.GenerateJaggedLine(
                                               connectionStart, connectionEnd,
                                               iterations, connectionLength * generationParams.ConnectionIndicatorDisplacementMultiplier));
     }
 }
Exemple #3
0
        partial void GenerateNoiseMapProjSpecific()
        {
            if (noiseTexture == null)
            {
                noiseTexture    = new Texture2D(GameMain.Instance.GraphicsDevice, generationParams.NoiseResolution, generationParams.NoiseResolution);
                rawNoiseTexture = new Texture2D(GameMain.Instance.GraphicsDevice, generationParams.NoiseResolution, generationParams.NoiseResolution);
                rawNoiseSprite  = new Sprite(rawNoiseTexture, null, null);
            }

            Color[] crackTextureData    = new Color[generationParams.NoiseResolution * generationParams.NoiseResolution];
            Color[] noiseTextureData    = new Color[generationParams.NoiseResolution * generationParams.NoiseResolution];
            Color[] rawNoiseTextureData = new Color[generationParams.NoiseResolution * generationParams.NoiseResolution];
            for (int x = 0; x < generationParams.NoiseResolution; x++)
            {
                for (int y = 0; y < generationParams.NoiseResolution; y++)
                {
                    noiseTextureData[x + y * generationParams.NoiseResolution]    = Color.Lerp(Color.Black, Color.Transparent, Noise[x, y]);
                    rawNoiseTextureData[x + y * generationParams.NoiseResolution] = Color.Lerp(Color.Black, Color.White, Rand.Range(0.0f, 1.0f));
                }
            }

            float   mapRadius = size / 2;
            Vector2 mapCenter = Vector2.One * mapRadius;

            foreach (LocationConnection connection in connections)
            {
                float centerDist = Vector2.Distance(connection.CenterPos, mapCenter);

                Vector2 connectionStart  = connection.Locations[0].MapPosition;
                Vector2 connectionEnd    = connection.Locations[1].MapPosition;
                float   connectionLength = Vector2.Distance(connectionStart, connectionEnd);
                int     iterations       = (int)(Math.Sqrt(connectionLength * generationParams.ConnectionIndicatorIterationMultiplier));
                connection.CrackSegments = MathUtils.GenerateJaggedLine(
                    connectionStart, connectionEnd,
                    iterations, connectionLength * generationParams.ConnectionIndicatorDisplacementMultiplier);

                iterations = (int)(Math.Sqrt(connectionLength * generationParams.ConnectionIterationMultiplier));
                var visualCrackSegments = MathUtils.GenerateJaggedLine(
                    connectionStart, connectionEnd,
                    iterations, connectionLength * generationParams.ConnectionDisplacementMultiplier);

                float totalLength = Vector2.Distance(visualCrackSegments[0][0], visualCrackSegments.Last()[1]);
                for (int i = 0; i < visualCrackSegments.Count; i++)
                {
                    Vector2 start = visualCrackSegments[i][0] * (generationParams.NoiseResolution / (float)size);
                    Vector2 end   = visualCrackSegments[i][1] * (generationParams.NoiseResolution / (float)size);

                    float length = Vector2.Distance(start, end);
                    for (float x = 0; x < 1; x += 1.0f / length)
                    {
                        Vector2 pos = Vector2.Lerp(start, end, x);
                        SetNoiseColorOnArea(pos, MathHelper.Clamp((int)(totalLength / 30), 2, 5) + Rand.Range(-1, 1), Color.Transparent);
                    }
                }
            }

            void SetNoiseColorOnArea(Vector2 pos, int dist, Color color)
            {
                for (int x = -dist; x < dist; x++)
                {
                    for (int y = -dist; y < dist; y++)
                    {
                        float d = 1.0f - new Vector2(x, y).Length() / dist;
                        if (d <= 0)
                        {
                            continue;
                        }

                        int xIndex = (int)pos.X + x;
                        if (xIndex < 0 || xIndex >= generationParams.NoiseResolution)
                        {
                            continue;
                        }
                        int yIndex = (int)pos.Y + y;
                        if (yIndex < 0 || yIndex >= generationParams.NoiseResolution)
                        {
                            continue;
                        }

                        float perlin = (float)PerlinNoise.CalculatePerlin(
                            xIndex / (float)generationParams.NoiseResolution * 100.0f,
                            yIndex / (float)generationParams.NoiseResolution * 100.0f, 0);

                        byte a = Math.Max(crackTextureData[xIndex + yIndex * generationParams.NoiseResolution].A, (byte)((d * perlin) * 255));

                        crackTextureData[xIndex + yIndex * generationParams.NoiseResolution].A = a;
                    }
                }
            }

            for (int i = 0; i < noiseTextureData.Length; i++)
            {
                float darken    = noiseTextureData[i].A / 255.0f;
                Color pathColor = Color.Lerp(Color.White, Color.Transparent, noiseTextureData[i].A / 255.0f);
                noiseTextureData[i] =
                    Color.Lerp(noiseTextureData[i], pathColor, crackTextureData[i].A / 255.0f * 0.5f);
            }

            noiseTexture.SetData(noiseTextureData);
            rawNoiseTexture.SetData(rawNoiseTextureData);
        }
Exemple #4
0
        private void GenerateLocations()
        {
            Voronoi voronoi = new Voronoi(0.5f);

            List <Vector2> sites = new List <Vector2>();

            for (int i = 0; i < 100; i++)
            {
                sites.Add(new Vector2(Rand.Range(0.0f, size, Rand.RandSync.Server), Rand.Range(0.0f, size, Rand.RandSync.Server)));
            }

            List <GraphEdge> edges = voronoi.MakeVoronoiGraph(sites, size, size);

            sites.Clear();
            foreach (GraphEdge edge in edges)
            {
                if (edge.point1 == edge.point2)
                {
                    continue;
                }

                //remove points from the edge of the map
                if (edge.point1.X == 0 || edge.point1.X == size)
                {
                    continue;
                }
                if (edge.point1.Y == 0 || edge.point1.Y == size)
                {
                    continue;
                }
                if (edge.point2.X == 0 || edge.point2.X == size)
                {
                    continue;
                }
                if (edge.point2.Y == 0 || edge.point2.Y == size)
                {
                    continue;
                }

                Location[] newLocations = new Location[2];
                newLocations[0] = locations.Find(l => l.MapPosition == edge.point1 || l.MapPosition == edge.point2);
                newLocations[1] = locations.Find(l => l != newLocations[0] && (l.MapPosition == edge.point1 || l.MapPosition == edge.point2));

                for (int i = 0; i < 2; i++)
                {
                    if (newLocations[i] != null)
                    {
                        continue;
                    }

                    Vector2[] points = new Vector2[] { edge.point1, edge.point2 };

                    int positionIndex = Rand.Int(1, Rand.RandSync.Server);

                    Vector2 position = points[positionIndex];
                    if (newLocations[1 - i] != null && newLocations[1 - i].MapPosition == position)
                    {
                        position = points[1 - positionIndex];
                    }

                    newLocations[i] = Location.CreateRandom(position);
                    locations.Add(newLocations[i]);
                }
                //int seed = (newLocations[0].GetHashCode() | newLocations[1].GetHashCode());
                connections.Add(new LocationConnection(newLocations[0], newLocations[1]));
            }

            //remove connections that are too short
            float minDistance = 50.0f;

            for (int i = connections.Count - 1; i >= 0; i--)
            {
                LocationConnection connection = connections[i];

                if (Vector2.Distance(connection.Locations[0].MapPosition, connection.Locations[1].MapPosition) > minDistance)
                {
                    continue;
                }

                locations.Remove(connection.Locations[0]);
                connections.Remove(connection);

                foreach (LocationConnection connection2 in connections)
                {
                    if (connection2.Locations[0] == connection.Locations[0])
                    {
                        connection2.Locations[0] = connection.Locations[1];
                    }
                    if (connection2.Locations[1] == connection.Locations[0])
                    {
                        connection2.Locations[1] = connection.Locations[1];
                    }
                }
            }

            foreach (LocationConnection connection in connections)
            {
                connection.Locations[0].Connections.Add(connection);
                connection.Locations[1].Connections.Add(connection);
            }

            for (int i = connections.Count - 1; i >= 0; i--)
            {
                i = Math.Min(i, connections.Count - 1);

                LocationConnection connection = connections[i];

                for (int n = Math.Min(i - 1, connections.Count - 1); n >= 0; n--)
                {
                    if (connection.Locations.Contains(connections[n].Locations[0]) &&
                        connection.Locations.Contains(connections[n].Locations[1]))
                    {
                        connections.RemoveAt(n);
                    }
                }
            }


            foreach (LocationConnection connection in connections)
            {
                Vector2 start       = connection.Locations[0].MapPosition;
                Vector2 end         = connection.Locations[1].MapPosition;
                int     generations = (int)(Math.Sqrt(Vector2.Distance(start, end) / 10.0f));
                connection.CrackSegments = MathUtils.GenerateJaggedLine(start, end, generations, 5.0f);
            }

            AssignBiomes();
        }
Exemple #5
0
        public void Generate(bool mirror = false)
        {
            Stopwatch sw = new Stopwatch();

            sw.Start();

            if (loaded != null)
            {
                loaded.Unload();
            }
            loaded = this;

            positionsOfInterest = new List <InterestingPosition>();

            renderer = new LevelRenderer(this);

            Voronoi voronoi = new Voronoi(1.0);

            List <Vector2> sites = new List <Vector2>();

            bodies = new List <Body>();

            Rand.SetSyncedSeed(ToolBox.StringToInt(seed));

            backgroundColor = generationParams.BackgroundColor;
            float avgValue = (backgroundColor.R + backgroundColor.G + backgroundColor.G) / 3;

            GameMain.LightManager.AmbientLight = new Color(backgroundColor * (10.0f / avgValue), 1.0f);

            float minWidth = 6500.0f;

            if (Submarine.MainSub != null)
            {
                Rectangle dockedSubBorders = Submarine.MainSub.GetDockedBorders();
                minWidth = Math.Max(minWidth, Math.Max(dockedSubBorders.Width, dockedSubBorders.Height));
            }

            startPosition = new Vector2(
                Rand.Range(minWidth, minWidth * 2, false),
                Rand.Range(borders.Height * 0.5f, borders.Height - minWidth * 2, false));

            endPosition = new Vector2(
                borders.Width - Rand.Range(minWidth, minWidth * 2, false),
                Rand.Range(borders.Height * 0.5f, borders.Height - minWidth * 2, false));

            List <Vector2> pathNodes   = new List <Vector2>();
            Rectangle      pathBorders = borders;// new Rectangle((int)minWidth, (int)minWidth, borders.Width - (int)minWidth * 2, borders.Height - (int)minWidth);

            pathBorders.Inflate(-minWidth * 2, -minWidth * 2);

            pathNodes.Add(new Vector2(startPosition.X, borders.Height));

            Vector2 nodeInterval = generationParams.MainPathNodeIntervalRange;

            for (float x = startPosition.X + Rand.Range(nodeInterval.X, nodeInterval.Y, false);
                 x < endPosition.X - Rand.Range(nodeInterval.X, nodeInterval.Y, false);
                 x += Rand.Range(nodeInterval.X, nodeInterval.Y, false))
            {
                pathNodes.Add(new Vector2(x, Rand.Range(pathBorders.Y, pathBorders.Bottom, false)));
            }

            pathNodes.Add(new Vector2(endPosition.X, borders.Height));

            if (pathNodes.Count <= 2)
            {
                pathNodes.Add((startPosition + endPosition) / 2);
            }

            List <List <Vector2> > smallTunnels = new List <List <Vector2> >();

            for (int i = 0; i < generationParams.SmallTunnelCount; i++)
            {
                var tunnelStartPos = pathNodes[Rand.Range(2, pathNodes.Count - 2, false)];
                tunnelStartPos.X = MathHelper.Clamp(tunnelStartPos.X, pathBorders.X, pathBorders.Right);

                float tunnelLength = Rand.Range(
                    generationParams.SmallTunnelLengthRange.X,
                    generationParams.SmallTunnelLengthRange.Y,
                    false);

                var tunnelNodes = MathUtils.GenerateJaggedLine(
                    tunnelStartPos,
                    new Vector2(tunnelStartPos.X, pathBorders.Bottom) + Rand.Vector(tunnelLength, false),
                    4, 1000.0f);

                List <Vector2> tunnel = new List <Vector2>();
                foreach (Vector2[] tunnelNode in tunnelNodes)
                {
                    if (!pathBorders.Contains(tunnelNode[0]))
                    {
                        continue;
                    }
                    tunnel.Add(tunnelNode[0]);
                }

                if (tunnel.Any())
                {
                    smallTunnels.Add(tunnel);
                }
            }

            Vector2 siteInterval = generationParams.VoronoiSiteInterval;
            Vector2 siteVariance = generationParams.VoronoiSiteVariance;

            for (float x = siteInterval.X / 2; x < borders.Width; x += siteInterval.X)
            {
                for (float y = siteInterval.Y / 2; y < borders.Height; y += siteInterval.Y)
                {
                    Vector2 site = new Vector2(
                        x + Rand.Range(-siteVariance.X, siteVariance.X, false),
                        y + Rand.Range(-siteVariance.Y, siteVariance.Y, false));

                    if (smallTunnels.Any(t => t.Any(node => Vector2.Distance(node, site) < siteInterval.Length())))
                    {
                        //add some more sites around the small tunnels to generate more small voronoi cells
                        if (x < borders.Width - siteInterval.X)
                        {
                            sites.Add(new Vector2(x, y) + Vector2.UnitX * siteInterval * 0.5f);
                        }
                        if (y < borders.Height - siteInterval.Y)
                        {
                            sites.Add(new Vector2(x, y) + Vector2.UnitY * siteInterval * 0.5f);
                        }
                        if (x < borders.Width - siteInterval.X && y < borders.Height - siteInterval.Y)
                        {
                            sites.Add(new Vector2(x, y) + Vector2.One * siteInterval * 0.5f);
                        }
                    }

                    if (mirror)
                    {
                        site.X = borders.Width - site.X;
                    }

                    sites.Add(site);
                }
            }

            Stopwatch sw2 = new Stopwatch();

            sw2.Start();

            List <GraphEdge> graphEdges = voronoi.MakeVoronoiGraph(sites, borders.Width, borders.Height);

            Debug.WriteLine("MakeVoronoiGraph: " + sw2.ElapsedMilliseconds + " ms");
            sw2.Restart();

            //construct voronoi cells based on the graph edges
            cells = CaveGenerator.GraphEdgesToCells(graphEdges, borders, GridCellSize, out cellGrid);

            Debug.WriteLine("find cells: " + sw2.ElapsedMilliseconds + " ms");
            sw2.Restart();

            List <VoronoiCell> mainPath = CaveGenerator.GeneratePath(pathNodes, cells, cellGrid, GridCellSize,
                                                                     new Rectangle(pathBorders.X, pathBorders.Y, pathBorders.Width, borders.Height), 0.5f, mirror);

            for (int i = 2; i < mainPath.Count; i += 3)
            {
                positionsOfInterest.Add(new InterestingPosition(mainPath[i].Center, PositionType.MainPath));
            }

            List <VoronoiCell> pathCells = new List <VoronoiCell>(mainPath);

            EnlargeMainPath(pathCells, minWidth);

            foreach (InterestingPosition positionOfInterest in positionsOfInterest)
            {
                WayPoint wayPoint = new WayPoint(positionOfInterest.Position, SpawnType.Enemy, null);
                wayPoint.MoveWithLevel = true;
            }

            startPosition.X = pathCells[0].Center.X;

            foreach (List <Vector2> tunnel in smallTunnels)
            {
                if (tunnel.Count < 2)
                {
                    continue;
                }

                //find the cell which the path starts from
                int startCellIndex = CaveGenerator.FindCellIndex(tunnel[0], cells, cellGrid, GridCellSize, 1);
                if (startCellIndex < 0)
                {
                    continue;
                }

                //if it wasn't one of the cells in the main path, don't create a tunnel
                if (cells[startCellIndex].CellType != CellType.Path)
                {
                    continue;
                }

                var newPathCells = CaveGenerator.GeneratePath(tunnel, cells, cellGrid, GridCellSize, pathBorders);

                positionsOfInterest.Add(new InterestingPosition(tunnel.Last(), PositionType.Cave));

                if (tunnel.Count > 4)
                {
                    positionsOfInterest.Add(new InterestingPosition(tunnel[tunnel.Count / 2], PositionType.Cave));
                }

                pathCells.AddRange(newPathCells);
            }

            Debug.WriteLine("path: " + sw2.ElapsedMilliseconds + " ms");
            sw2.Restart();

            cells = CleanCells(pathCells);

            pathCells.AddRange(CreateBottomHoles(generationParams.BottomHoleProbability, new Rectangle(
                                                     (int)(borders.Width * 0.2f), 0,
                                                     (int)(borders.Width * 0.6f), (int)(borders.Height * 0.8f))));

            foreach (VoronoiCell cell in cells)
            {
                if (cell.Center.Y < borders.Height / 2)
                {
                    continue;
                }
                cell.edges.ForEach(e => e.OutsideLevel = true);
            }

            foreach (VoronoiCell cell in pathCells)
            {
                cell.edges.ForEach(e => e.OutsideLevel = false);

                cell.CellType = CellType.Path;
                cells.Remove(cell);
            }

            //generate some narrow caves
            int caveAmount = 0;// Rand.Int(3, false);
            List <VoronoiCell> usedCaveCells = new List <VoronoiCell>();

            for (int i = 0; i < caveAmount; i++)
            {
                Vector2     startPoint = Vector2.Zero;
                VoronoiCell startCell  = null;

                var caveCells = new List <VoronoiCell>();

                int maxTries = 5, tries = 0;
                while (tries < maxTries)
                {
                    startCell = cells[Rand.Int(cells.Count, false)];

                    //find an edge between the cell and the already carved path
                    GraphEdge startEdge =
                        startCell.edges.Find(e => pathCells.Contains(e.AdjacentCell(startCell)));

                    if (startEdge != null)
                    {
                        startPoint  = (startEdge.point1 + startEdge.point2) / 2.0f;
                        startPoint += startPoint - startCell.Center;

                        //get the cells in which the cave will be carved
                        caveCells = GetCells(startCell.Center, 2);
                        //remove cells that have already been "carved" out
                        caveCells.RemoveAll(c => c.CellType == CellType.Path);

                        //if any of the cells have already been used as a cave, continue and find some other cells
                        if (usedCaveCells.Any(c => caveCells.Contains(c)))
                        {
                            continue;
                        }
                        break;
                    }

                    tries++;
                }

                //couldn't find a place for a cave -> abort
                if (tries >= maxTries)
                {
                    break;
                }

                if (!caveCells.Any())
                {
                    continue;
                }

                usedCaveCells.AddRange(caveCells);

                List <VoronoiCell> caveSolidCells;
                var cavePathCells = CaveGenerator.CarveCave(caveCells, startPoint, out caveSolidCells);

                //remove the large cells used as a "base" for the cave (they've now been replaced with smaller ones)
                caveCells.ForEach(c => cells.Remove(c));

                cells.AddRange(caveSolidCells);

                foreach (VoronoiCell cell in cavePathCells)
                {
                    cells.Remove(cell);
                }

                pathCells.AddRange(cavePathCells);

                for (int j = cavePathCells.Count / 2; j < cavePathCells.Count; j += 10)
                {
                    positionsOfInterest.Add(new InterestingPosition(cavePathCells[j].Center, PositionType.Cave));
                }
            }

            for (int x = 0; x < cellGrid.GetLength(0); x++)
            {
                for (int y = 0; y < cellGrid.GetLength(1); y++)
                {
                    cellGrid[x, y].Clear();
                }
            }

            foreach (VoronoiCell cell in cells)
            {
                int x = (int)Math.Floor(cell.Center.X / GridCellSize);
                int y = (int)Math.Floor(cell.Center.Y / GridCellSize);

                if (x < 0 || y < 0 || x >= cellGrid.GetLength(0) || y >= cellGrid.GetLength(1))
                {
                    continue;
                }

                cellGrid[x, y].Add(cell);
            }

            ruins = new List <Ruin>();
            for (int i = 0; i < generationParams.RuinCount; i++)
            {
                GenerateRuin(mainPath);
            }

            startPosition.Y = borders.Height;
            endPosition.Y   = borders.Height;

            List <VoronoiCell> cellsWithBody = new List <VoronoiCell>(cells);

            List <VertexPositionTexture> bodyVertices;

            bodies = CaveGenerator.GeneratePolygons(cellsWithBody, out bodyVertices);

            renderer.SetBodyVertices(bodyVertices.ToArray());
            renderer.SetWallVertices(CaveGenerator.GenerateWallShapes(cells));

            renderer.PlaceSprites(generationParams.BackgroundSpriteAmount);

            ShaftBody = BodyFactory.CreateEdge(GameMain.World,
                                               ConvertUnits.ToSimUnits(new Vector2(borders.X, 0)),
                                               ConvertUnits.ToSimUnits(new Vector2(borders.Right, 0)));

            ShaftBody.SetTransform(ConvertUnits.ToSimUnits(new Vector2(0.0f, borders.Height)), 0.0f);

            ShaftBody.BodyType            = BodyType.Static;
            ShaftBody.CollisionCategories = Physics.CollisionLevel;

            bodies.Add(ShaftBody);

            foreach (VoronoiCell cell in cells)
            {
                foreach (GraphEdge edge in cell.edges)
                {
                    edge.cell1 = null;
                    edge.cell2 = null;
                    edge.site1 = null;
                    edge.site2 = null;
                }
            }

            //initialize MapEntities that aren't in any sub (e.g. items inside ruins)
            MapEntity.MapLoaded(null);

            Debug.WriteLine("Generatelevel: " + sw2.ElapsedMilliseconds + " ms");
            sw2.Restart();

            if (mirror)
            {
                Vector2 temp = startPosition;
                startPosition = endPosition;
                endPosition   = temp;
            }

            Debug.WriteLine("**********************************************************************************");
            Debug.WriteLine("Generated a map with " + sites.Count + " sites in " + sw.ElapsedMilliseconds + " ms");
            Debug.WriteLine("Seed: " + seed);
            Debug.WriteLine("**********************************************************************************");
        }