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