public static T SelectWeightedRandom <T>(IList <T> objects, IList <float> weights, Rand.RandSync randSync) { return(SelectWeightedRandom(objects, weights, Rand.GetRNG(randSync))); }
private void Generate() { connections.Clear(); Locations.Clear(); GenerateNoiseMap(generationParams.NoiseOctaves, generationParams.NoisePersistence); List <Vector2> sites = new List <Vector2>(); float mapRadius = size / 2; Vector2 mapCenter = new Vector2(mapRadius, mapRadius); float locationRadius = mapRadius * generationParams.LocationRadius; for (float x = mapCenter.X - locationRadius; x < mapCenter.X + locationRadius; x += generationParams.VoronoiSiteInterval) { for (float y = mapCenter.Y - locationRadius; y < mapCenter.Y + locationRadius; y += generationParams.VoronoiSiteInterval) { float noiseVal = Noise[(int)(x / size * generationParams.NoiseResolution), (int)(y / size * generationParams.NoiseResolution)]; if (Rand.Range(generationParams.VoronoiSitePlacementMinVal, 1.0f, Rand.RandSync.Server) < noiseVal * generationParams.VoronoiSitePlacementProbability) { sites.Add(new Vector2(x, y)); } } } Voronoi voronoi = new Voronoi(0.5f); List <GraphEdge> edges = voronoi.MakeVoronoiGraph(sites, size, size); float zoneRadius = size / 2 / generationParams.DifficultyZones; sites.Clear(); foreach (GraphEdge edge in edges) { if (edge.Point1 == edge.Point2) { continue; } if (Vector2.DistanceSquared(edge.Point1, mapCenter) >= locationRadius * locationRadius || Vector2.DistanceSquared(edge.Point2, mapCenter) >= locationRadius * locationRadius) { 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]; } int zone = MathHelper.Clamp(generationParams.DifficultyZones - (int)Math.Floor(Vector2.Distance(position, mapCenter) / zoneRadius), 1, generationParams.DifficultyZones); newLocations[i] = Location.CreateRandom(position, zone, Rand.GetRNG(Rand.RandSync.Server)); Locations.Add(newLocations[i]); } var newConnection = new LocationConnection(newLocations[0], newLocations[1]); float centerDist = Vector2.Distance(newConnection.CenterPos, mapCenter); newConnection.Difficulty = MathHelper.Clamp(((1.0f - centerDist / mapRadius) * 100) + Rand.Range(-10.0f, 10.0f, Rand.RandSync.Server), 0, 100); connections.Add(newConnection); } //remove connections that are too short float minConnectionDistanceSqr = generationParams.MinConnectionDistance * generationParams.MinConnectionDistance; for (int i = connections.Count - 1; i >= 0; i--) { LocationConnection connection = connections[i]; if (Vector2.DistanceSquared(connection.Locations[0].MapPosition, connection.Locations[1].MapPosition) > minConnectionDistanceSqr) { 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]; } } } HashSet <Location> connectedLocations = new HashSet <Location>(); foreach (LocationConnection connection in connections) { connection.Locations[0].Connections.Add(connection); connection.Locations[1].Connections.Add(connection); connectedLocations.Add(connection.Locations[0]); connectedLocations.Add(connection.Locations[1]); } //remove orphans Locations.RemoveAll(c => !connectedLocations.Contains(c)); //remove locations that are too close to each other float minLocationDistanceSqr = generationParams.MinLocationDistance * generationParams.MinLocationDistance; for (int i = Locations.Count - 1; i >= 0; i--) { for (int j = Locations.Count - 1; j > i; j--) { float dist = Vector2.DistanceSquared(Locations[i].MapPosition, Locations[j].MapPosition); if (dist > minLocationDistanceSqr) { continue; } //move connections from Locations[j] to Locations[i] foreach (LocationConnection connection in Locations[j].Connections) { if (connection.Locations[0] == Locations[j]) { connection.Locations[0] = Locations[i]; } else { connection.Locations[1] = Locations[i]; } Locations[i].Connections.Add(connection); } Locations.RemoveAt(j); } } 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) { float centerDist = Vector2.Distance(connection.CenterPos, mapCenter); connection.Difficulty = MathHelper.Clamp(((1.0f - centerDist / mapRadius) * 100) + Rand.Range(-10.0f, 10.0f, Rand.RandSync.Server), 0, 100); } AssignBiomes(); GenerateNoiseMapProjSpecific(); }
private void Generate() { Connections.Clear(); Locations.Clear(); List <Vector2> voronoiSites = new List <Vector2>(); for (float x = 10.0f; x < Width - 10.0f; x += generationParams.VoronoiSiteInterval.X) { for (float y = 10.0f; y < Height - 10.0f; y += generationParams.VoronoiSiteInterval.Y) { voronoiSites.Add(new Vector2( x + generationParams.VoronoiSiteVariance.X * Rand.Range(-0.5f, 0.5f, Rand.RandSync.Server), y + generationParams.VoronoiSiteVariance.Y * Rand.Range(-0.5f, 0.5f, Rand.RandSync.Server))); } } Voronoi voronoi = new Voronoi(0.5f); List <GraphEdge> edges = voronoi.MakeVoronoiGraph(voronoiSites, Width, Height); float zoneWidth = Width / generationParams.DifficultyZones; Vector2 margin = new Vector2( Math.Min(10, Width * 0.1f), Math.Min(10, Height * 0.2f)); float startX = margin.X, endX = Width - margin.X; float startY = margin.Y, endY = Height - margin.Y; if (!edges.Any()) { throw new Exception($"Generating a campaign map failed (no edges in the voronoi graph). Width: {Width}, height: {Height}, margin: {margin}"); } voronoiSites.Clear(); foreach (GraphEdge edge in edges) { if (edge.Point1 == edge.Point2) { continue; } if (edge.Point1.X < margin.X || edge.Point1.X > Width - margin.X || edge.Point1.Y < startY || edge.Point1.Y > endY) { continue; } if (edge.Point2.X < margin.X || edge.Point2.X > Width - margin.X || edge.Point2.Y < startY || edge.Point2.Y > endY) { 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]; } int zone = MathHelper.Clamp((int)Math.Floor(position.X / zoneWidth) + 1, 1, generationParams.DifficultyZones); newLocations[i] = Location.CreateRandom(position, zone, Rand.GetRNG(Rand.RandSync.Server), requireOutpost: false, Locations); Locations.Add(newLocations[i]); } var newConnection = new LocationConnection(newLocations[0], newLocations[1]); Connections.Add(newConnection); } //remove connections that are too short float minConnectionDistanceSqr = generationParams.MinConnectionDistance * generationParams.MinConnectionDistance; for (int i = Connections.Count - 1; i >= 0; i--) { LocationConnection connection = Connections[i]; if (Vector2.DistanceSquared(connection.Locations[0].MapPosition, connection.Locations[1].MapPosition) > minConnectionDistanceSqr) { 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]; } } } HashSet <Location> connectedLocations = new HashSet <Location>(); foreach (LocationConnection connection in Connections) { connection.Locations[0].Connections.Add(connection); connection.Locations[1].Connections.Add(connection); connectedLocations.Add(connection.Locations[0]); connectedLocations.Add(connection.Locations[1]); } //remove orphans Locations.RemoveAll(c => !connectedLocations.Contains(c)); //remove locations that are too close to each other float minLocationDistanceSqr = generationParams.MinLocationDistance * generationParams.MinLocationDistance; for (int i = Locations.Count - 1; i >= 0; i--) { for (int j = Locations.Count - 1; j > i; j--) { float dist = Vector2.DistanceSquared(Locations[i].MapPosition, Locations[j].MapPosition); if (dist > minLocationDistanceSqr) { continue; } //move connections from Locations[j] to Locations[i] foreach (LocationConnection connection in Locations[j].Connections) { if (connection.Locations[0] == Locations[j]) { connection.Locations[0] = Locations[i]; } else { connection.Locations[1] = Locations[i]; } if (connection.Locations[0] != connection.Locations[1]) { Locations[i].Connections.Add(connection); } else { Connections.Remove(connection); } } Locations[i].Connections.RemoveAll(c => c.OtherLocation(Locations[i]) == Locations[j]); Locations.RemoveAt(j); } } 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 (Location location in Locations) { for (int i = location.Connections.Count - 1; i >= 0; i--) { if (!Connections.Contains(location.Connections[i])) { location.Connections.RemoveAt(i); } } } foreach (LocationConnection connection in Connections) { connection.Difficulty = MathHelper.Clamp((connection.CenterPos.X / Width * 100) + Rand.Range(-10.0f, 0.0f, Rand.RandSync.Server), 1.2f, 100.0f); } AssignBiomes(); CreateEndLocation(); foreach (Location location in Locations) { location.LevelData = new LevelData(location); } foreach (LocationConnection connection in Connections) { connection.LevelData = new LevelData(connection); } }