poprawiono generowanie dzialek
This commit is contained in:
		
							parent
							
								
									bf6c31dd9d
								
							
						
					
					
						commit
						841bdb9ee7
					
				| @ -1,12 +1,9 @@ | |||||||
| using System; | using System; | ||||||
| using System.Collections.Concurrent; |  | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.Linq; | using System.Linq; | ||||||
| using Assets.Cities; | using Assets.Cities; | ||||||
| using Assets.Common; | using Assets.Common; | ||||||
| using Assets.Voronoi; | using Assets.Voronoi; | ||||||
| using UnityEngine.SocialPlatforms.GameCenter; |  | ||||||
| using UnityEngine.UIElements; |  | ||||||
| 
 | 
 | ||||||
| namespace Assets.AnnotationPass | namespace Assets.AnnotationPass | ||||||
| { | { | ||||||
| @ -17,8 +14,10 @@ namespace Assets.AnnotationPass | |||||||
|         private Graph<Point> _voronoiGraph; |         private Graph<Point> _voronoiGraph; | ||||||
| 
 | 
 | ||||||
|         public double MinimumAngle { get; set; } |         public double MinimumAngle { get; set; } | ||||||
|         public double MaxNudgeDistance { get; set; } |         public double MaxNudgeDistance { get; set; } = .25; | ||||||
|         public double MinNudgeDistance { get; set; } |         public double MinNudgeDistance { get; set; } = .75; | ||||||
|  | 
 | ||||||
|  |         public double MinimumRoadLength { get; set; } = 2; | ||||||
| 
 | 
 | ||||||
|         public CityFieldsPass(Random random) |         public CityFieldsPass(Random random) | ||||||
|         { |         { | ||||||
| @ -38,16 +37,52 @@ namespace Assets.AnnotationPass | |||||||
|             FixRoadsDensity(city, MinimumAngle); |             FixRoadsDensity(city, MinimumAngle); | ||||||
|             CreateFieldBoundaries(city); |             CreateFieldBoundaries(city); | ||||||
|             CreateCityFields(city); |             CreateCityFields(city); | ||||||
|  |             RemoveTooShortRoads(city); | ||||||
|             NudgeCityFields(city); |             NudgeCityFields(city); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         private void RemoveTooShortRoads(City city) | ||||||
|  |         { | ||||||
|  |             foreach (var field in city.Fields) | ||||||
|  |             { | ||||||
|  |                 field.Boundary = field.Boundary.Aggregate(new List<Point>(), (boundary, point) => | ||||||
|  |                 { | ||||||
|  |                     if (boundary.Count == 0) | ||||||
|  |                     { | ||||||
|  |                         boundary.Add(point); | ||||||
|  |                     } | ||||||
|  |                     else | ||||||
|  |                     { | ||||||
|  |                         var last = boundary[boundary.Count - 1]; | ||||||
|  | 
 | ||||||
|  |                         if (Point.Dist(last, point) > MinimumRoadLength) | ||||||
|  |                             boundary.Add(point); | ||||||
|  |                         else | ||||||
|  |                             boundary[boundary.Count - 1] = (point + last) / 2; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     return boundary; | ||||||
|  |                 }); | ||||||
|  | 
 | ||||||
|  |                 var f = field.Boundary.First(); | ||||||
|  |                 var l = field.Boundary.Last(); | ||||||
|  |                  | ||||||
|  |                 if (Point.Dist(l, f) < MinimumRoadLength) | ||||||
|  |                 { | ||||||
|  |                     field.Boundary[0] = (f + l) / 2; | ||||||
|  |                     field.Boundary.Remove(l); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             city.Fields = city.Fields.Where(field => field.Boundary.Count > 2).ToList(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         private void NudgeCityFields(City city) |         private void NudgeCityFields(City city) | ||||||
|         { |         { | ||||||
|             foreach (var field in city.Fields) |             foreach (var field in city.Fields) | ||||||
|             { |             { | ||||||
|                 var center = PointUtils.Mean(field.Boundary); |                 var nudge = _random.NextDouble() * MaxNudgeDistance + MinNudgeDistance; | ||||||
|                 var nudge = _random.NextDouble() * (MaxNudgeDistance - MinNudgeDistance) + MinNudgeDistance; |                 field.Boundary = field.Boundary.Zip(PointUtils.CalculateNormals(field.Boundary), (a, b) => (Point: a, Normal: b)).Select(tuple => tuple.Point - tuple.Normal * nudge).ToList(); | ||||||
|                 field.Boundary = field.Boundary.Select(p => p - (p - center).Direction * nudge).ToList(); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -74,8 +109,6 @@ namespace Assets.AnnotationPass | |||||||
|             CityField CreateField(int start, int next) |             CityField CreateField(int start, int next) | ||||||
|             { |             { | ||||||
|                 CityField field = new CityField(); |                 CityField field = new CityField(); | ||||||
|                  |  | ||||||
|                 field.Boundary.Add(city.FieldBoundaries[start]); |  | ||||||
| 
 | 
 | ||||||
|                 int watchdog = 100; |                 int watchdog = 100; | ||||||
|                 int current  = start; |                 int current  = start; | ||||||
| @ -99,7 +132,11 @@ namespace Assets.AnnotationPass | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // remove outside field |             // remove outside field | ||||||
|             city.Fields.Remove(city.Fields.OrderByDescending(field => field.Boundary.Count).First()); |             city.Fields.RemoveAll(field => | ||||||
|  |             { | ||||||
|  |                 var points = field.Boundary.Take(3).ToArray(); | ||||||
|  |                 return !PointUtils.IsClockwise(points[0], points[1], points[2]); | ||||||
|  |             }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void Annotate(Map map) |         public void Annotate(Map map) | ||||||
|  | |||||||
| @ -12,7 +12,7 @@ namespace Assets.Cities | |||||||
|         public Graph<Point> Roads { get; set; } = new Graph<Point>(); |         public Graph<Point> Roads { get; set; } = new Graph<Point>(); | ||||||
|         public Graph<Point> FieldBoundaries { get; set; } = new Graph<Point>(); |         public Graph<Point> FieldBoundaries { get; set; } = new Graph<Point>(); | ||||||
| 
 | 
 | ||||||
|         public List<CityField> Fields { get; } = new List<CityField>(); |         public List<CityField> Fields { get; set; } = new List<CityField>(); | ||||||
| 
 | 
 | ||||||
|         public List<(int, int)> Edges = new List<(int, int)>(); |         public List<(int, int)> Edges = new List<(int, int)>(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,6 +5,6 @@ namespace Assets.Cities | |||||||
| { | { | ||||||
|     public class CityField |     public class CityField | ||||||
|     { |     { | ||||||
|         public ICollection<Point> Boundary { get; set; } = new List<Point>(); |         public IList<Point> Boundary { get; set; } = new List<Point>(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -29,6 +29,16 @@ namespace Assets.Common | |||||||
| 
 | 
 | ||||||
|             return tail.Concat(head); |             return tail.Concat(head); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         public static IEnumerable<T> RotateLeft<T>(this IEnumerable<T> collection, int count = 1) | ||||||
|  |         { | ||||||
|  |             var diff = collection.Count() - count; | ||||||
|  | 
 | ||||||
|  |             var head = collection.Take(count); | ||||||
|  |             var tail = collection.Skip(count).Take(diff); | ||||||
|  | 
 | ||||||
|  |             return tail.Concat(head); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static class HasMetadataExtensions |     public static class HasMetadataExtensions | ||||||
|  | |||||||
| @ -1,5 +1,7 @@ | |||||||
| using System; | using System; | ||||||
|  | using System.Collections; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
|  | using System.Linq; | ||||||
| 
 | 
 | ||||||
| namespace Assets.Common | namespace Assets.Common | ||||||
| { | { | ||||||
| @ -21,6 +23,20 @@ namespace Assets.Common | |||||||
|             return result; |             return result; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         public static IEnumerable<Point> CalculateNormals(IEnumerable<Point> points) | ||||||
|  |         { | ||||||
|  |             var pairs  = points.RotateRight().Zip(points, (a, b) => (a, b)); | ||||||
|  |             var thirds = pairs.Zip(points.RotateLeft(), (pair, c) => (pair.a, pair.b, c)); | ||||||
|  | 
 | ||||||
|  |             return thirds.Select(third => | ||||||
|  |             { | ||||||
|  |                 var left = (third.a - third.b).Direction; | ||||||
|  |                 var right = (third.c - third.b).Direction; | ||||||
|  | 
 | ||||||
|  |                 return ((left + right) / 2).Direction * (IsClockwise(third.a, third.b, third.c) ? -1 : 1); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |          | ||||||
|         public static double AngleBetween(Point center, Point a, Point b) |         public static double AngleBetween(Point center, Point a, Point b) | ||||||
|         { |         { | ||||||
|             a = a - center; |             a = a - center; | ||||||
|  | |||||||
| @ -65,6 +65,8 @@ namespace Assets | |||||||
|         public float minimumNudgeDistance = 0.5f; |         public float minimumNudgeDistance = 0.5f; | ||||||
|         [Range(0f, 4f)] |         [Range(0f, 4f)] | ||||||
|         public float maximumNudgeDistance = 1f; |         public float maximumNudgeDistance = 1f; | ||||||
|  |         [Range(0f, 4f)] | ||||||
|  |         public float minimumRoadLength = 1f; | ||||||
|          |          | ||||||
|         [Range(2.0f, 64.0f)] |         [Range(2.0f, 64.0f)] | ||||||
|         public float radius = 8; |         public float radius = 8; | ||||||
| @ -113,6 +115,7 @@ namespace Assets | |||||||
|                 MinimumAngle = Mathf.Deg2Rad * minimumRoadAngle, |                 MinimumAngle = Mathf.Deg2Rad * minimumRoadAngle, | ||||||
|                 MaxNudgeDistance = maximumNudgeDistance, |                 MaxNudgeDistance = maximumNudgeDistance, | ||||||
|                 MinNudgeDistance = minimumNudgeDistance, |                 MinNudgeDistance = minimumNudgeDistance, | ||||||
|  |                 MinimumRoadLength = minimumRoadLength | ||||||
|             }); |             }); | ||||||
| 
 | 
 | ||||||
|             return generator; |             return generator; | ||||||
| @ -267,9 +270,10 @@ namespace Assets | |||||||
|                     foreach (var field in city.Fields) |                     foreach (var field in city.Fields) | ||||||
|                     { |                     { | ||||||
|                         foreach (var (a, b) in field.Boundary.RotateRight().Zip(field.Boundary, (a, b) => (a, b))) |                         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());    | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -18,7 +18,8 @@ namespace Assets | |||||||
|          |          | ||||||
|         private IList<IRenderer> _renderers = new List<IRenderer> |         private IList<IRenderer> _renderers = new List<IRenderer> | ||||||
|         { |         { | ||||||
|             new LandmassRenderer() |             new LandmassRenderer(), | ||||||
|  |             new CityRenderer(), | ||||||
|         }; |         }; | ||||||
|          |          | ||||||
|         public void GenerateRandom() |         public void GenerateRandom() | ||||||
|  | |||||||
							
								
								
									
										75
									
								
								Assets/Scripts/RenderPass/CityRenderer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								Assets/Scripts/RenderPass/CityRenderer.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | |||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Linq; | ||||||
|  | using Assets.AnnotationPass; | ||||||
|  | using Assets.Cities; | ||||||
|  | using Assets.Common; | ||||||
|  | using UnityEngine; | ||||||
|  | 
 | ||||||
|  | namespace Assets.RenderPass | ||||||
|  | { | ||||||
|  |     public class CityRenderer : IRenderer | ||||||
|  |     { | ||||||
|  |         public void Render(Map map, Component component) | ||||||
|  |         { | ||||||
|  |             var go = new GameObject(); | ||||||
|  |             go.AddComponent<MeshFilter>(); | ||||||
|  |             go.AddComponent<MeshRenderer>(); | ||||||
|  | 
 | ||||||
|  |             var cities = map.GetProperty<IEnumerable<City>>(LocateCitiesPass.CitiesProperty); | ||||||
|  |             var meshes = cities.Select(city => new CombineInstance { mesh = CreateCityMesh(city), transform = component.transform.localToWorldMatrix }); | ||||||
|  |              | ||||||
|  |             var mesh = new Mesh(); | ||||||
|  |             mesh.CombineMeshes(meshes.ToArray()); | ||||||
|  |              | ||||||
|  |             go.GetComponent<MeshFilter>().sharedMesh = mesh; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private Mesh CreateCityMesh(City city) | ||||||
|  |         { | ||||||
|  |             List<Vector3> vertices  = new List<Vector3>(); | ||||||
|  |             List<Vector3> normals  = new List<Vector3>(); | ||||||
|  |             List<int> triangles = new List<int>(); | ||||||
|  | 
 | ||||||
|  |             int start = 0, n = 0; | ||||||
|  |             foreach (var field in city.Fields) | ||||||
|  |             { | ||||||
|  |                 start = vertices.Count; | ||||||
|  |                 n = field.Boundary.Count; | ||||||
|  |                  | ||||||
|  |                 vertices.AddRange(field.Boundary.Select(p => p.ToVector3() + Vector3.up * 5)); | ||||||
|  |                 normals.AddRange(field.Boundary.Select(v => Vector3.up)); | ||||||
|  |                 triangles.AddRange(Triangulate(field).Select(x => x + start)); | ||||||
|  | 
 | ||||||
|  |                 start = vertices.Count; | ||||||
|  |                  | ||||||
|  |                 vertices.AddRange(field.Boundary.Select(p => p.ToVector3() + Vector3.up * 5)); | ||||||
|  |                 normals.AddRange(PointUtils.CalculateNormals(field.Boundary).Select(p => p.ToVector3())); | ||||||
|  |                 vertices.AddRange(field.Boundary.Select(p => p.ToVector3())); | ||||||
|  |                 normals.AddRange(PointUtils.CalculateNormals(field.Boundary).Select(p => p.ToVector3())); | ||||||
|  | 
 | ||||||
|  |                 for (int i = 0; i < n; i++) | ||||||
|  |                 { | ||||||
|  |                     triangles.AddRange(new []{ start + i, start + n + i, start + n + (i + 1) % n }); | ||||||
|  |                     triangles.AddRange(new []{ start + i, start + n + (i + 1) % n, start + (i + 1) % n }); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             return new Mesh | ||||||
|  |             { | ||||||
|  |                 vertices = vertices.ToArray(), | ||||||
|  |                 normals = normals.ToArray(), | ||||||
|  |                 triangles = triangles.ToArray(),  | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private static IEnumerable<int> Triangulate(CityField field) | ||||||
|  |         { | ||||||
|  |             return new Triangulator(field.Boundary.Select(p => new Vector2((float)p.x, (float)p.y)).ToArray()).Triangulate(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void DrawGizmos(Map map, Component component) | ||||||
|  |         { | ||||||
|  |              | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										3
									
								
								Assets/Scripts/RenderPass/CityRenderer.cs.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								Assets/Scripts/RenderPass/CityRenderer.cs.meta
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | fileFormatVersion: 2 | ||||||
|  | guid: 9804b7a1c403484e9a6c51c550be879b | ||||||
|  | timeCreated: 1573942634 | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user