From 476411f6e704386534f85214c7394d7ace418700 Mon Sep 17 00:00:00 2001 From: veniti Date: Thu, 21 Nov 2019 20:40:35 +0100 Subject: [PATCH] =?UTF-8?q?dodano=20strefy=20wp=C5=82yw=C3=B3w=20miast?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Scripts/AnnotationPass/CityFieldsPass.cs | 7 +- .../AnnotationPass/LocateCitiesPass.cs | 58 ++++---- Assets/Scripts/Cities/City.cs | 2 + Assets/Scripts/Cities/CityField.cs | 4 +- Assets/Scripts/LandmassGenerator.cs | 128 ++++++++++++------ 5 files changed, 126 insertions(+), 73 deletions(-) diff --git a/Assets/Scripts/AnnotationPass/CityFieldsPass.cs b/Assets/Scripts/AnnotationPass/CityFieldsPass.cs index cf00fad..1dfa3cb 100644 --- a/Assets/Scripts/AnnotationPass/CityFieldsPass.cs +++ b/Assets/Scripts/AnnotationPass/CityFieldsPass.cs @@ -22,7 +22,6 @@ namespace Assets.AnnotationPass public double MinimumRoadLength { get; set; } = 2; public double BusinessCityFields { get; set; } = 0.3; - public double LivingCityFields { get; set; } = 0.7; public CityFieldsPass(Random random) { @@ -144,20 +143,20 @@ namespace Assets.AnnotationPass // add field types var orderedFields = city.Fields.OrderBy(cf => Point.Dist(cf.Center, city.Center)).ToList(); - orderedFields.First().cityFieldType = CityFieldTypes.MainSquare; + orderedFields.First().Type = FieldType.MainSquare; int businessCityFields = (int)Math.Ceiling((BusinessCityFields*orderedFields.Count())); foreach (var cityField in orderedFields.Skip(1).Take(businessCityFields)) { - cityField.cityFieldType = CityFieldTypes.Business; + cityField.Type = FieldType.Business; } foreach (var cityField in orderedFields.Skip(1+businessCityFields)) { - cityField.cityFieldType = CityFieldTypes.Living; + cityField.Type = FieldType.Living; } } diff --git a/Assets/Scripts/AnnotationPass/LocateCitiesPass.cs b/Assets/Scripts/AnnotationPass/LocateCitiesPass.cs index 599271b..e346387 100644 --- a/Assets/Scripts/AnnotationPass/LocateCitiesPass.cs +++ b/Assets/Scripts/AnnotationPass/LocateCitiesPass.cs @@ -10,7 +10,12 @@ namespace Assets.AnnotationPass { public const string CitiesProperty = "Cities"; public const string CityProperty = "City"; - + public int MaxCitiesCount { get; set; } = 20; + public int MaxPlacementTries { get; set; } = 30; + public float RangeOfInfluence { get; set; } = .5f; + public float CitiesSize { get; set; } = .5f; + + private Graph _locationGraph; private Graph _basicGraph; private Random _random; @@ -20,15 +25,10 @@ namespace Assets.AnnotationPass _random = random ?? new Random(); } - IEnumerable LocateCities() - { - return ChoosePoints(5); - } - City CreateCity(int vertex, int size) { City newCity = new City(); - + var site = _basicGraph.Vertices[vertex]; newCity.Center = site.Center.Clone() as Point; site.Tags.Add("City.Center"); @@ -49,35 +49,47 @@ namespace Assets.AnnotationPass s.Metadata.SetProperty(CityProperty, newCity); } + newCity.RangeOfInfluence = GetCityRangeOfInfluence(newCity); return newCity; } - IEnumerable ChoosePoints(int number) + List CreateCities() { + List cities = new List(); var vertices = new List(); - - for (int i = 0; i < number; i++) + + int guard = MaxPlacementTries; + int createdCitiesCount = 0; + + while (createdCitiesCount < MaxCitiesCount && guard-- > 0) { - var randomLocation = _locationGraph.Vertices[_random.Next(1, _locationGraph.Vertices.Count())]; - var count = randomLocation.Sites.Count(); - var randomPoint = randomLocation.Sites[_random.Next(0, count)]; - vertices.Add(randomPoint.Index); + var randomLocation = _locationGraph.Vertices.Skip(1).RandomElement(_random); + var randomSite = randomLocation.Sites.RandomElement(_random); + + if (cities.Any(c => Point.Dist(PointUtils.Mean(c.Sites.Select(s => s.Center)), randomSite.Center) < c.RangeOfInfluence)) + continue; + + cities.Add(CreateCity(randomSite.Index, (int)Math.Ceiling(CitiesSize * _random.Next(0, 30)))); + guard = MaxPlacementTries; + createdCitiesCount++; } - - return vertices; + + return cities; + + } + + public float GetCityRangeOfInfluence(City city) + { + return RangeOfInfluence*city.Sites.Count; } public void Annotate(Map map) { - _basicGraph = map.Sites.Clone() as Graph; + _basicGraph = map.Sites.Clone() as Graph; _locationGraph = map.Metadata.GetProperty>(LandmassPass.MapLocationsProperty); - var cities = new List(); - var locations = LocateCities(); - - foreach (var index in locations) - cities.Add(CreateCity(index, _random.Next(0, 10))); - + var cities = CreateCities(); + map.Metadata.SetProperty(CitiesProperty, cities); } } diff --git a/Assets/Scripts/Cities/City.cs b/Assets/Scripts/Cities/City.cs index f3f197c..ec73983 100644 --- a/Assets/Scripts/Cities/City.cs +++ b/Assets/Scripts/Cities/City.cs @@ -16,6 +16,7 @@ namespace Assets.Cities public List<(int, int)> Edges = new List<(int, int)>(); public Point Center { get; set; } + public float RangeOfInfluence { get; set; } = 0; public City() { @@ -25,6 +26,7 @@ namespace Assets.Cities { Sites = sites; } + public void AddSite(MapSite site) { diff --git a/Assets/Scripts/Cities/CityField.cs b/Assets/Scripts/Cities/CityField.cs index 59e88ea..8f2d351 100644 --- a/Assets/Scripts/Cities/CityField.cs +++ b/Assets/Scripts/Cities/CityField.cs @@ -3,7 +3,7 @@ using Assets.Common; namespace Assets.Cities { - public enum CityFieldTypes + public enum FieldType { MainSquare, Business, @@ -13,7 +13,7 @@ namespace Assets.Cities public class CityField { public IList Boundary { get; set; } = new List(); - public CityFieldTypes cityFieldType { get; set; } + public FieldType Type { get; set; } public Point Center { get; set; } } } \ No newline at end of file diff --git a/Assets/Scripts/LandmassGenerator.cs b/Assets/Scripts/LandmassGenerator.cs index ca9755a..ae40ae1 100644 --- a/Assets/Scripts/LandmassGenerator.cs +++ b/Assets/Scripts/LandmassGenerator.cs @@ -20,7 +20,7 @@ namespace Assets public class GraphGeneratorDebug { public bool enabled = true; - + public bool displayPoints = true; public bool displayBoundary = true; public bool displayVertices = true; @@ -37,6 +37,7 @@ namespace Assets public bool displayCityFields = true; [NonSerialized] public float generationTime = 0.0f; + public bool displayRangeOfInfluence = false; } [Serializable] @@ -52,22 +53,30 @@ namespace Assets { [NonSerialized] public Map Map; [NonSerialized] public Thread GenerationThread; - + public GraphGeneratorDebug debug; - + public Vector2 size = new Vector2(); public List types = new List(); - + [Range(0f, 360f)] public float minimumRoadAngle = 30f; - + [Range(0f, 1f)] + public float businessCityFields = 0.3f; [Range(0f, 4f)] public float minimumNudgeDistance = 0.5f; [Range(0f, 4f)] public float maximumNudgeDistance = 1f; [Range(0f, 4f)] public float minimumRoadLength = 1f; - + public float rangeOfInfluence = .5f; + [Range(0f, 1f)] + public float citiesSize = .5f; + + + [Range(0, 50)] + public int citiesCount = 20; + [Range(2.0f, 64.0f)] public float radius = 8; public int seed = Environment.TickCount; @@ -80,17 +89,17 @@ namespace Assets { GenerationThread?.Abort(); GenerationThread = new Thread(() => - { + { var generator = CreateMapGenerator(); var result = generator.Generate(size.x, size.y); - + lock (GetType()) { Map = result; onDone(result); } }); - + GenerationThread.Start(); } @@ -109,13 +118,19 @@ namespace Assets var generator = new MapGenerator(new VoronoiGridGenerator(seed, new PoissonDiskSampler(radius) { Generator = new Random(seed) })); generator.AddAnnotationPass(new LandmassPass(types.Prepend(new LocationType { name = "Ocean", height = -1 }).Select(t => new Location { Type = t }), new Random(seed))); - generator.AddAnnotationPass(new LocateCitiesPass(new Random(seed))); + generator.AddAnnotationPass(new LocateCitiesPass(new Random(seed)) + { + MaxCitiesCount = citiesCount, + RangeOfInfluence = rangeOfInfluence, + CitiesSize = citiesSize + }); generator.AddAnnotationPass(new CityFieldsPass(new Random(seed)) { MinimumAngle = Mathf.Deg2Rad * minimumRoadAngle, MaxNudgeDistance = maximumNudgeDistance, MinNudgeDistance = minimumNudgeDistance, - MinimumRoadLength = minimumRoadLength + MinimumRoadLength = minimumRoadLength, + BusinessCityFields = businessCityFields }); return generator; @@ -125,7 +140,7 @@ namespace Assets { GenerationThread?.Abort(); } - + private void DisplayGraphCities(IEnumerable cities) { foreach (City city in cities) @@ -143,7 +158,7 @@ namespace Assets void OnDrawGizmos() { if (!debug.enabled || Map == null) return; - + if (debug.displayBoundary) { Gizmos.color = Color.gray; @@ -153,7 +168,7 @@ namespace Assets Gizmos.DrawLine(new Vector3(size.x, 0, size.y), new Vector3(size.x, 0, 0)); Gizmos.DrawLine(new Vector3(size.x, 0, size.y), new Vector3(0, 0, size.y)); } - + if (debug.displayPoints) { Gizmos.color = Color.white; @@ -177,47 +192,47 @@ namespace Assets Gizmos.color = Color.white; DebugUtils.DisplayGraphEdges(Map.Boundaries); } - + Gizmos.color = Color.blue; if (!Map.Metadata.HasProperty(LandmassPass.MapLocationsProperty)) return; var locations = Map.Metadata.GetProperty>(LandmassPass.MapLocationsProperty); - + if (debug.displayLocationCells) { var cells = Map.Sites.Vertices .Where(s => s.Metadata.HasProperty(LandmassPass.SiteLocationProperty)) .Where(s => s.Metadata.GetProperty(LandmassPass.SiteLocationProperty).Type.name != "Ocean"); - + foreach (var site in cells) { var location = site.Metadata.GetProperty(LandmassPass.SiteLocationProperty); - + Gizmos.color = location.Type.color; Gizmos.DrawSphere(site.Center.ToVector3(), 2); } } -// -// if (debug.displayLocations && _locationGraph != null) -// { -// DisplayGraphEdges(_locationGraph.Morph(a => a.Item1)); -// } -// -// if (debug.displayLocationPoints) -// { -// foreach (var location in _locations.Skip(1)) -// { -// Gizmos.color = location.Type.color; -// foreach (var point in location.BoundaryPoints) -// { -// var v = VoronoiGenerator.Voronoi.Vertices[point].ToVector3(); -// Gizmos.DrawSphere(v, 1); -// if (debug.displayLabels) Handles.Label(v + Vector3.right, $"{point} at {v.x:F2}, {v.y:f2}"); -// } + // + // if (debug.displayLocations && _locationGraph != null) + // { + // DisplayGraphEdges(_locationGraph.Morph(a => a.Item1)); + // } + // + // if (debug.displayLocationPoints) + // { + // foreach (var location in _locations.Skip(1)) + // { + // Gizmos.color = location.Type.color; + // foreach (var point in location.BoundaryPoints) + // { + // var v = VoronoiGenerator.Voronoi.Vertices[point].ToVector3(); + // Gizmos.DrawSphere(v, 1); + // if (debug.displayLabels) Handles.Label(v + Vector3.right, $"{point} at {v.x:F2}, {v.y:f2}"); + // } -// } -// } + // } + // } if (debug.displayLocationEdges) { @@ -230,15 +245,15 @@ namespace Assets } } } - + if (debug.displayCities && Map.Metadata.HasProperty(LocateCitiesPass.CitiesProperty)) { Gizmos.color = Color.magenta; DisplayGraphCities(Map.Metadata.GetProperty>(LocateCitiesPass.CitiesProperty)); } - + var cities = Map.Metadata.GetProperty>(LocateCitiesPass.CitiesProperty); - + if (debug.displayFieldBoundaries) { Gizmos.color = Color.white; @@ -261,19 +276,44 @@ namespace Assets } } + if (debug.displayRangeOfInfluence) + { + foreach (var city in cities) + { + Gizmos.color = Color.yellow; + Gizmos.DrawWireSphere(PointUtils.Mean(city.Sites.Select(s => s.Center)).ToVector3(), city.RangeOfInfluence); + Gizmos.DrawSphere(PointUtils.Mean(city.Sites.Select(s => s.Center)).ToVector3(), 1); + } + } + if (debug.displayCityFields) { - Gizmos.color = Color.green; + Gizmos.color = Color.blue; foreach (var city in cities) { foreach (var field in city.Fields) { + switch (field.Type) + { + case FieldType.Business: + Gizmos.color = Color.green; + break; + case FieldType.Living: + Gizmos.color = Color.yellow; + break; + case FieldType.MainSquare: + Gizmos.color = Color.red; + break; + default: + Gizmos.color = Color.blue; + break; + } foreach (var (a, b) in field.Boundary.RotateRight().Zip(field.Boundary, (a, b) => (a, b))) - Gizmos.DrawLine(a.ToVector3(), b.ToVector3()); - + Gizmos.DrawLine(a.ToVector3(), b.ToVector3()); + foreach (var tuple in field.Boundary.Zip(PointUtils.CalculateNormals(field.Boundary), (a, b) => (Point: a, Normal: a + b))) - Gizmos.DrawLine(tuple.Point.ToVector3(), tuple.Normal.ToVector3()); + Gizmos.DrawLine(tuple.Point.ToVector3(), tuple.Normal.ToVector3()); } } }