poprawiono generowanie dzialek
This commit is contained in:
parent
bf6c31dd9d
commit
841bdb9ee7
@ -1,12 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Assets.Cities;
|
||||
using Assets.Common;
|
||||
using Assets.Voronoi;
|
||||
using UnityEngine.SocialPlatforms.GameCenter;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Assets.AnnotationPass
|
||||
{
|
||||
@ -17,8 +14,10 @@ namespace Assets.AnnotationPass
|
||||
private Graph<Point> _voronoiGraph;
|
||||
|
||||
public double MinimumAngle { get; set; }
|
||||
public double MaxNudgeDistance { get; set; }
|
||||
public double MinNudgeDistance { get; set; }
|
||||
public double MaxNudgeDistance { get; set; } = .25;
|
||||
public double MinNudgeDistance { get; set; } = .75;
|
||||
|
||||
public double MinimumRoadLength { get; set; } = 2;
|
||||
|
||||
public CityFieldsPass(Random random)
|
||||
{
|
||||
@ -38,16 +37,52 @@ namespace Assets.AnnotationPass
|
||||
FixRoadsDensity(city, MinimumAngle);
|
||||
CreateFieldBoundaries(city);
|
||||
CreateCityFields(city);
|
||||
RemoveTooShortRoads(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)
|
||||
{
|
||||
foreach (var field in city.Fields)
|
||||
{
|
||||
var center = PointUtils.Mean(field.Boundary);
|
||||
var nudge = _random.NextDouble() * (MaxNudgeDistance - MinNudgeDistance) + MinNudgeDistance;
|
||||
field.Boundary = field.Boundary.Select(p => p - (p - center).Direction * nudge).ToList();
|
||||
var nudge = _random.NextDouble() * MaxNudgeDistance + MinNudgeDistance;
|
||||
field.Boundary = field.Boundary.Zip(PointUtils.CalculateNormals(field.Boundary), (a, b) => (Point: a, Normal: b)).Select(tuple => tuple.Point - tuple.Normal * nudge).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,8 +109,6 @@ namespace Assets.AnnotationPass
|
||||
CityField CreateField(int start, int next)
|
||||
{
|
||||
CityField field = new CityField();
|
||||
|
||||
field.Boundary.Add(city.FieldBoundaries[start]);
|
||||
|
||||
int watchdog = 100;
|
||||
int current = start;
|
||||
@ -99,7 +132,11 @@ namespace Assets.AnnotationPass
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
@ -12,7 +12,7 @@ namespace Assets.Cities
|
||||
public Graph<Point> Roads { 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)>();
|
||||
|
||||
|
@ -5,6 +5,6 @@ namespace Assets.Cities
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Assets.Common
|
||||
{
|
||||
@ -21,6 +23,20 @@ namespace Assets.Common
|
||||
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)
|
||||
{
|
||||
a = a - center;
|
||||
|
@ -65,6 +65,8 @@ namespace Assets
|
||||
public float minimumNudgeDistance = 0.5f;
|
||||
[Range(0f, 4f)]
|
||||
public float maximumNudgeDistance = 1f;
|
||||
[Range(0f, 4f)]
|
||||
public float minimumRoadLength = 1f;
|
||||
|
||||
[Range(2.0f, 64.0f)]
|
||||
public float radius = 8;
|
||||
@ -113,6 +115,7 @@ namespace Assets
|
||||
MinimumAngle = Mathf.Deg2Rad * minimumRoadAngle,
|
||||
MaxNudgeDistance = maximumNudgeDistance,
|
||||
MinNudgeDistance = minimumNudgeDistance,
|
||||
MinimumRoadLength = minimumRoadLength
|
||||
});
|
||||
|
||||
return generator;
|
||||
@ -267,9 +270,10 @@ namespace Assets
|
||||
foreach (var field in city.Fields)
|
||||
{
|
||||
foreach (var (a, b) in field.Boundary.RotateRight().Zip(field.Boundary, (a, b) => (a, b)))
|
||||
{
|
||||
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>
|
||||
{
|
||||
new LandmassRenderer()
|
||||
new LandmassRenderer(),
|
||||
new CityRenderer(),
|
||||
};
|
||||
|
||||
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