generating city fields
This commit is contained in:
parent
0e0c591cf3
commit
ceb20fcba1
@ -6,7 +6,7 @@ using System.Linq;
|
|||||||
namespace Assets.Map
|
namespace Assets.Map
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Graph<T>
|
public class Graph<T> : ICloneable
|
||||||
{
|
{
|
||||||
public List<T> Vertices { get; internal set; } = new List<T>();
|
public List<T> Vertices { get; internal set; } = new List<T>();
|
||||||
private Dictionary<int, List<int>> _edges = new Dictionary<int, List<int>>();
|
private Dictionary<int, List<int>> _edges = new Dictionary<int, List<int>>();
|
||||||
@ -114,6 +114,11 @@ namespace Assets.Map
|
|||||||
|
|
||||||
return _edges[vertex];
|
return _edges[vertex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual public object Clone()
|
||||||
|
{
|
||||||
|
return Morph(l => l);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Graph<T, E> : Graph<T>
|
public class Graph<T, E> : Graph<T>
|
||||||
@ -153,5 +158,10 @@ namespace Assets.Map
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override object Clone()
|
||||||
|
{
|
||||||
|
return Morph(l => l, l => l);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
8
Assets/SampleScenes.meta
Normal file
8
Assets/SampleScenes.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3d8829ac873af27488b1412b8db301ab
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
8
Assets/SampleScenes/Materials.meta
Normal file
8
Assets/SampleScenes/Materials.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 35e5b60069b1d4945af0cbaefb902d02
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
8
Assets/SampleScenes/Models.meta
Normal file
8
Assets/SampleScenes/Models.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 92a62c583a2e8734d9a6018eec4d27fb
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
8
Assets/SampleScenes/Models/Materials.meta
Normal file
8
Assets/SampleScenes/Models/Materials.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7ff1b560cd403d249b3359b432be2796
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
8
Assets/SampleScenes/Navmesh.meta
Normal file
8
Assets/SampleScenes/Navmesh.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4014c75d332963b40a9724fb931da32e
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
8
Assets/SampleScenes/Scenes.meta
Normal file
8
Assets/SampleScenes/Scenes.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 26c0bbb8e6792b546bf28bbe08d7c96d
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
8
Assets/SampleScenes/Scenes/CharacterThirdPersonAI.meta
Normal file
8
Assets/SampleScenes/Scenes/CharacterThirdPersonAI.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c3ed31e3b158a9e4994bd4c23c947afb
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -26,50 +26,65 @@ namespace Assets.Scripts
|
|||||||
|
|
||||||
public int GetHashCode(Point obj)
|
public int GetHashCode(Point obj)
|
||||||
{
|
{
|
||||||
return 0;
|
return obj.GetHashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class CityField
|
||||||
|
{
|
||||||
|
public List<Point> boundary;
|
||||||
|
}
|
||||||
|
|
||||||
public class City
|
public class City
|
||||||
{
|
{
|
||||||
public Graph<Voronoi.Site> startGraph { get; set; }
|
public Graph<Voronoi.Site> startGraph;
|
||||||
public List<Voronoi.Site> sitesList { get; set; }
|
public List<Voronoi.Site> sites;
|
||||||
public Graph<Point, double> roads { get; set; } = new Graph<Point, double>();
|
|
||||||
public List<(int, int)> boundariesEdges { get; set; }
|
|
||||||
public Graph<Point> mainRoad { get; set; } = new Graph<Point>();
|
|
||||||
|
|
||||||
|
public Graph<Point> roads = new Graph<Point>();
|
||||||
|
public Graph<Point> fieldBoundaries = new Graph<Point>();
|
||||||
|
|
||||||
|
public List<CityField> fields = new List<CityField>();
|
||||||
|
|
||||||
|
public List<(int, int)> edges;
|
||||||
|
|
||||||
public City(Graph<Site> startGraph)
|
public City(Graph<Site> startGraph)
|
||||||
{
|
{
|
||||||
this.startGraph = startGraph;
|
this.startGraph = startGraph;
|
||||||
this.sitesList = new List<Voronoi.Site>();
|
|
||||||
this.boundariesEdges = new List<(int, int)>();
|
this.sites = new List<Voronoi.Site>();
|
||||||
|
this.edges = new List<(int, int)>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public City(Graph<Site> startGraph, List<Site> sitesList) : this(startGraph)
|
public City(Graph<Site> startGraph, List<Site> sitesList) : this(startGraph)
|
||||||
{
|
{
|
||||||
this.sitesList = sitesList;
|
this.sites = sitesList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddSite(Site site)
|
public void AddSite(Site site)
|
||||||
{
|
{
|
||||||
sitesList.Add(site);
|
sites.Add(site);
|
||||||
FixBoundaryEdges(site);
|
FixBoundaryEdges(site);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FixBoundaryEdges(Site site)
|
private void FixBoundaryEdges(Site site)
|
||||||
{
|
{
|
||||||
var a = boundariesEdges;
|
var a = edges;
|
||||||
var b = site.Edges.Select(x => x.Item1 < x.Item2 ? x : (x.Item2, x.Item1));
|
var b = site.Edges.Select(x => x.Item1 < x.Item2 ? x : (x.Item2, x.Item1));
|
||||||
|
|
||||||
boundariesEdges = a.Union(b).Except(a.Intersect(b)).ToList();
|
edges = a.Union(b).Except(a.Intersect(b)).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateRoadGraph(IList<Point> points)
|
public void CreateRoadGraph(IList<Point> points)
|
||||||
{
|
{
|
||||||
VoronoiGenerator generator = new VoronoiGenerator(sitesList.SelectMany(site => site.Vertices.Select(i => points[i]).Append(site.Point)).Distinct(new PointProximityComparer(2)).ToList());
|
var pointsForRoads = sites.SelectMany(site => site.Vertices.Select(i => (i, points[i])).Append((-1, site.Point))).Distinct().ToList();
|
||||||
|
var mapping = pointsForRoads.Select((x, i) => x.Item1 == -1 ? (-1, -1) : (i, x.Item1)).Where(x => x.Item1 != -1).ToDictionary(x => x.Item2, x => x.Item1);
|
||||||
|
|
||||||
|
VoronoiGenerator generator = new VoronoiGenerator(pointsForRoads.Select(x => x.Item2));
|
||||||
generator.Generate();
|
generator.Generate();
|
||||||
|
|
||||||
roads = generator.Delaunay.Morph(s => s.Point, e => Point.Dist(generator.Delaunay.Vertices[e.Item1].Point, generator.Delaunay.Vertices[e.Item2].Point));
|
roads = generator.Delaunay.Morph(s => s.Point);
|
||||||
|
|
||||||
|
fieldBoundaries = new Graph<Point> { Vertices = roads.Vertices, Edges = edges.Select(e => (mapping[e.Item1], mapping[e.Item2])) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +96,7 @@ namespace Assets.Scripts
|
|||||||
public bool displayEdges = false;
|
public bool displayEdges = false;
|
||||||
public bool displayCities = true;
|
public bool displayCities = true;
|
||||||
public bool displayCityRoads = true;
|
public bool displayCityRoads = true;
|
||||||
public bool displayCityMainRoads = true;
|
public bool displayFieldBoundaries = true;
|
||||||
public bool displayWorldRoads = false;
|
public bool displayWorldRoads = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,9 +110,9 @@ namespace Assets.Scripts
|
|||||||
private List<int> verticesForRoads;
|
private List<int> verticesForRoads;
|
||||||
private List<int> verticesForCitites;
|
private List<int> verticesForCitites;
|
||||||
public GraphGeneratorDebug debug;
|
public GraphGeneratorDebug debug;
|
||||||
public City city;
|
|
||||||
public List<City> cities = new List<City>();
|
public List<City> cities = new List<City>();
|
||||||
Graph<Site, double> roads = new Graph<Site, double>();
|
Graph<Site> roads = new Graph<Site>();
|
||||||
|
|
||||||
Graph<Point> mainRoads = new Graph<Point>();
|
Graph<Point> mainRoads = new Graph<Point>();
|
||||||
|
|
||||||
List<int> CountProbablitityOfCity(List<int> vertices)
|
List<int> CountProbablitityOfCity(List<int> vertices)
|
||||||
@ -115,6 +130,11 @@ namespace Assets.Scripts
|
|||||||
return ChoosePoints(20);
|
return ChoosePoints(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsPointInsideCity(City city, Point point)
|
||||||
|
{
|
||||||
|
return city.sites.Any(s => PointUtils.IsPointInside(point, s.Vertices.Select(i => _voronoiGraph[i]).ToArray()));
|
||||||
|
}
|
||||||
|
|
||||||
City CreateCity(int vertex, int size)
|
City CreateCity(int vertex, int size)
|
||||||
{
|
{
|
||||||
City newCity = new City(_basicGraph);
|
City newCity = new City(_basicGraph);
|
||||||
@ -136,7 +156,20 @@ namespace Assets.Scripts
|
|||||||
}
|
}
|
||||||
|
|
||||||
newCity.CreateRoadGraph(_voronoiGraph.Vertices);
|
newCity.CreateRoadGraph(_voronoiGraph.Vertices);
|
||||||
newCity.mainRoad = ConnectPointsIntoRoads(newCity.roads);
|
|
||||||
|
var edges = newCity.roads.Edges.ToList();
|
||||||
|
foreach (var (a, b) in edges)
|
||||||
|
{
|
||||||
|
var (va, vb) = (newCity.roads[a], newCity.roads[b]);
|
||||||
|
var center = (va + vb) / 2;
|
||||||
|
|
||||||
|
if (!IsPointInsideCity(newCity, center))
|
||||||
|
newCity.roads.DeleteEdge(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectPointsIntoRoads(newCity);
|
||||||
|
CreateFieldBoundaries(newCity);
|
||||||
|
|
||||||
return newCity;
|
return newCity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,28 +187,35 @@ namespace Assets.Scripts
|
|||||||
return vertices;
|
return vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
Graph<Point> ConnectPointsIntoRoads(Graph<Point, double> graph)
|
void ConnectPointsIntoRoads(City city)
|
||||||
{
|
{
|
||||||
|
var original = city.roads.Morph(s => s, e => Point.Dist(city.roads[e.Item1], city.roads[e.Item2]));
|
||||||
|
|
||||||
//1.Sort all the edges in non - decreasing order of their weight.
|
//1.Sort all the edges in non - decreasing order of their weight.
|
||||||
//2.Pick the smallest edge.Check if it forms a cycle with the spanning tree formed so far. If cycle is not formed, include this edge.Else, discard it.
|
//2.Pick the smallest edge.Check if it forms a cycle with the spanning tree formed so far. If cycle is not formed, include this edge.Else, discard it.
|
||||||
//3.Repeat step#2 until there are (V-1) edges in the spanning tree.
|
//3.Repeat step#2 until there are (V-1) edges in the spanning tree.
|
||||||
|
|
||||||
graph.Edges = graph.Edges.OrderBy(e => graph.GetEdgeData(e));
|
var edges = original.Edges.OrderByDescending(e => original.GetEdgeData(e));
|
||||||
graph._edgeData = graph._edgeData.OrderByDescending(e => e.Value).ToDictionary(e => e.Key, k => k.Value);
|
|
||||||
|
|
||||||
Graph<Point> spanningTree = new Graph<Point>();
|
Graph<Point> roads = new Graph<Point>() { Vertices = city.roads.Vertices };
|
||||||
spanningTree.Vertices = graph.Vertices;
|
|
||||||
|
|
||||||
foreach (var edge in graph.Edges)
|
foreach (var edge in original.Edges)
|
||||||
{
|
{
|
||||||
spanningTree.AddEdge(edge.Item1, edge.Item2);
|
roads.AddEdge(edge.Item1, edge.Item2);
|
||||||
if (Graph<Point>.HasCycle(spanningTree))
|
|
||||||
spanningTree.DeleteEdge(edge.Item1, edge.Item2);
|
if (Graph<Point>.HasCycle(roads))
|
||||||
if (spanningTree.Edges.Count() == spanningTree.Vertices.Count() - 1)
|
roads.DeleteEdge(edge.Item1, edge.Item2);
|
||||||
|
if (roads.Edges.Count() == roads.Vertices.Count() - 1)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return spanningTree;
|
|
||||||
|
city.roads = roads;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateFieldBoundaries(City city)
|
||||||
|
{
|
||||||
|
foreach (var (a, b) in city.roads.Edges)
|
||||||
|
city.fieldBoundaries.AddEdge(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateWorldRoadGraph()
|
void CreateWorldRoadGraph()
|
||||||
@ -250,10 +290,10 @@ namespace Assets.Scripts
|
|||||||
|
|
||||||
private void DisplayGraphCrossroads(Graph<Point> graph, List<int> vertices)
|
private void DisplayGraphCrossroads(Graph<Point> graph, List<int> vertices)
|
||||||
{
|
{
|
||||||
foreach (var v in vertices.Select(i => graph.Vertices[i].ToVector3()))
|
//foreach (var v in vertices.Select(i => graph.Vertices[i].ToVector3()))
|
||||||
{
|
//{
|
||||||
Gizmos.DrawSphere(v, 1);
|
// Gizmos.DrawSphere(v, 1);
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -262,12 +302,12 @@ namespace Assets.Scripts
|
|||||||
foreach (City city in cities)
|
foreach (City city in cities)
|
||||||
{
|
{
|
||||||
Gizmos.color = Color.magenta;
|
Gizmos.color = Color.magenta;
|
||||||
foreach (var (a, b) in city.boundariesEdges)
|
foreach (var (a, b) in city.edges)
|
||||||
{
|
{
|
||||||
Gizmos.DrawLine(_voronoiGraph.Vertices[a].ToVector3(), _voronoiGraph.Vertices[b].ToVector3());
|
Gizmos.DrawLine(_voronoiGraph.Vertices[a].ToVector3(), _voronoiGraph.Vertices[b].ToVector3());
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var a in city.sitesList)
|
foreach (var a in city.sites)
|
||||||
Gizmos.DrawSphere(a.Point.ToVector3(), 1);
|
Gizmos.DrawSphere(a.Point.ToVector3(), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,6 +321,7 @@ namespace Assets.Scripts
|
|||||||
|
|
||||||
foreach (var (s, e) in edges) Gizmos.DrawLine(s, e);
|
foreach (var (s, e) in edges) Gizmos.DrawLine(s, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDrawGizmos()
|
private void OnDrawGizmos()
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -308,9 +349,18 @@ namespace Assets.Scripts
|
|||||||
DisplayGraphCities(cities);
|
DisplayGraphCities(cities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (debug.displayFieldBoundaries)
|
||||||
|
{
|
||||||
|
Gizmos.color = Color.white;
|
||||||
|
|
||||||
|
foreach (var city in cities)
|
||||||
|
DisplayGraphEdges(city.fieldBoundaries);
|
||||||
|
}
|
||||||
|
|
||||||
if (debug.displayCityRoads)
|
if (debug.displayCityRoads)
|
||||||
{
|
{
|
||||||
Gizmos.color = Color.blue;
|
Gizmos.color = Color.green;
|
||||||
|
|
||||||
foreach (var city in cities)
|
foreach (var city in cities)
|
||||||
{
|
{
|
||||||
DisplayGraphEdges(city.roads);
|
DisplayGraphEdges(city.roads);
|
||||||
@ -318,15 +368,7 @@ namespace Assets.Scripts
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug.displayCityMainRoads)
|
|
||||||
{
|
|
||||||
//Gizmos.color = new Color(2.54f, 0.127f, 1.56f);
|
|
||||||
Gizmos.color = Color.green;
|
|
||||||
foreach (var city in cities)
|
|
||||||
{
|
|
||||||
DisplayGraphEdges(city.mainRoad);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (debug.displayWorldRoads)
|
if (debug.displayWorldRoads)
|
||||||
{
|
{
|
||||||
// Gizmos.color = new Color(0.254f, 0.127f, 0.156f);
|
// Gizmos.color = new Color(0.254f, 0.127f, 0.156f);
|
||||||
|
@ -21,7 +21,7 @@ namespace Assets
|
|||||||
public GameObject forest;
|
public GameObject forest;
|
||||||
|
|
||||||
private Random _random = new Random();
|
private Random _random = new Random();
|
||||||
private List<LocationSite> _sites;
|
private List<Site> _sites;
|
||||||
|
|
||||||
private GraphGenerator Generator => GetComponent<GraphGenerator>();
|
private GraphGenerator Generator => GetComponent<GraphGenerator>();
|
||||||
|
|
||||||
@ -39,17 +39,17 @@ namespace Assets
|
|||||||
|
|
||||||
private void PlaceTrees()
|
private void PlaceTrees()
|
||||||
{
|
{
|
||||||
foreach (LocationSite site in _sites)
|
foreach (Site site in _sites)
|
||||||
{
|
{
|
||||||
var sampler = new PoissonDiskSampler(radius) { Generator = _random };
|
var sampler = new PoissonDiskSampler(radius) { Generator = _random };
|
||||||
|
|
||||||
Bounding bounding =
|
Bounding bounding =
|
||||||
BoundingTools.GetBounding(site.Site.Vertices.Select(i => Generator.BoundariesGraph.Vertices[i]));
|
BoundingTools.GetBounding(site.Vertices.Select(i => Generator.BoundariesGraph.Vertices[i]));
|
||||||
|
|
||||||
var offset = Vector3.up * site.Location.Type.height;
|
var offset = Vector3.up * site.Location.Type.height;
|
||||||
var points = sampler.Generate((float)bounding.Width, (float)bounding.Height);
|
var points = sampler.Generate((float)bounding.Width, (float)bounding.Height);
|
||||||
|
|
||||||
foreach (var point in points.Select(point => point + bounding.Min).Where(point => IsPointInSite(site.Site, point)))
|
foreach (var point in points.Select(point => point + bounding.Min).Where(point => IsPointInSite(site, point)))
|
||||||
{
|
{
|
||||||
PlaceRandomTree(point.ToVector3() + offset);
|
PlaceRandomTree(point.ToVector3() + offset);
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ namespace Assets
|
|||||||
|
|
||||||
private void FindForestSites()
|
private void FindForestSites()
|
||||||
{
|
{
|
||||||
_sites = new List<LocationSite>();
|
_sites = new List<Site>();
|
||||||
|
|
||||||
foreach (var location in Generator.LocationGraph.Vertices.Skip(1))
|
foreach (var location in Generator.LocationGraph.Vertices.Skip(1))
|
||||||
{
|
{
|
||||||
|
@ -104,7 +104,7 @@ namespace Assets
|
|||||||
|
|
||||||
private void GenerateLocationMesh(Location location, IList<Point> points)
|
private void GenerateLocationMesh(Location location, IList<Point> points)
|
||||||
{
|
{
|
||||||
foreach (var vertices in location.Sites.Select(site => site.Edges.Select(x => points[x.Item1]).Reverse()))
|
foreach (var vertices in location.Sites.Select(site => site.Edges.Select(x => x.Item1).Reverse()))
|
||||||
{
|
{
|
||||||
int start = _vertices.Count;
|
int start = _vertices.Count;
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ namespace Assets.Voronoi
|
|||||||
|
|
||||||
public bool Done => Queue.Count == 0;
|
public bool Done => Queue.Count == 0;
|
||||||
|
|
||||||
public VoronoiGenerator(IList<Point> sites)
|
public VoronoiGenerator(IEnumerable<Point> sites)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
Sites = sites.Select(x => new Site(x, i++)).ToList();
|
Sites = sites.Select(x => new Site(x, i++)).ToList();
|
||||||
|
Loading…
Reference in New Issue
Block a user