generacja działek w mieście oparta o przygotowaną architekturę
This commit is contained in:
parent
9b606119c4
commit
c0eda23d16
File diff suppressed because one or more lines are too long
@ -151,7 +151,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
debug:
|
||||
enabled: 1
|
||||
displayPoints: 1
|
||||
displayPoints: 0
|
||||
displayBoundary: 1
|
||||
displayVertices: 0
|
||||
displayNeighbours: 0
|
||||
@ -159,9 +159,12 @@ MonoBehaviour:
|
||||
displayEdges: 0
|
||||
displayLocations: 0
|
||||
displayLocationCells: 0
|
||||
displayLocationEdges: 1
|
||||
displayLocationEdges: 0
|
||||
displayCities: 1
|
||||
displayLocationPoints: 0
|
||||
size: {x: 100, y: 100}
|
||||
displayFieldBoundaries: 1
|
||||
displayCityRoads: 0
|
||||
size: {x: 250, y: 250}
|
||||
types:
|
||||
- name:
|
||||
color: {r: 1, g: 0, b: 0.74144936, a: 1}
|
||||
@ -175,8 +178,9 @@ MonoBehaviour:
|
||||
- name:
|
||||
color: {r: 0, g: 1, b: 0.042674065, a: 1}
|
||||
height: 0
|
||||
radius: 4
|
||||
seed: 1294302848
|
||||
minimumRoadAngle: 30
|
||||
radius: 5
|
||||
seed: 865432704
|
||||
--- !u!4 &319467308
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Assets.Cities;
|
||||
@ -8,91 +9,69 @@ namespace Assets.AnnotationPass
|
||||
{
|
||||
public class CityFieldsPass : IAnnotationPass
|
||||
{
|
||||
private System.Random _random;
|
||||
private Graph<Point> _voronoiGraph;
|
||||
private Graph<Location> _locationGraph;
|
||||
private Graph<MapSite> _basicGraph;
|
||||
private List<int> verticesForRoads;
|
||||
private List<int> verticesForCitites;
|
||||
private Random _random;
|
||||
|
||||
List<City> cities = new List<City>();
|
||||
Graph<MapSite> roads = new Graph<MapSite>();
|
||||
Graph<Point> mainRoads = new Graph<Point>();
|
||||
double minimumAngle;
|
||||
private Graph<Point> _voronoiGraph;
|
||||
|
||||
private double _minimumAngle;
|
||||
|
||||
List<int> CountProbablitityOfCity(List<int> vertices)
|
||||
public CityFieldsPass(Random random, double minimumAngle = 0.2)
|
||||
{
|
||||
List<int> probabilities = new List<int>();
|
||||
vertices.ForEach(v => probabilities.Add((v % 2 == 0 ? _random.Next(0, 50) : _random.Next(50, 100))));
|
||||
return probabilities;
|
||||
_random = random;
|
||||
_minimumAngle = minimumAngle;
|
||||
}
|
||||
|
||||
List<int> LocateCities()
|
||||
{
|
||||
// var verticesForCitites = CountProbablitityOfCity(ChoosePoints(20));
|
||||
// verticesForCitites.Sort();
|
||||
// return verticesForCitites.GetRange(0, 10);
|
||||
return ChoosePoints(20);
|
||||
}
|
||||
|
||||
public bool IsPointInsideCity(City city, Point point)
|
||||
private bool IsPointInsideCity(City city, Point point)
|
||||
{
|
||||
return city.sites.Any(s => PointUtils.IsPointInside(point, s.Boundary.Select(i => _voronoiGraph[i]).ToArray()));
|
||||
}
|
||||
|
||||
City CreateCity(int vertex, int size)
|
||||
private void AnnotateCity(City city)
|
||||
{
|
||||
City newCity = new City(_basicGraph);
|
||||
CreateRoadGraph(city, _voronoiGraph.Vertices);
|
||||
RemoveIncorrectEdges(city);
|
||||
ConnectPointsIntoRoads(city);
|
||||
FixRoadsDensity(city, _minimumAngle);
|
||||
CreateFieldBoundaries(city);
|
||||
}
|
||||
|
||||
public void Annotate(Map map)
|
||||
{
|
||||
_voronoiGraph = map.Boundaries;
|
||||
|
||||
var site = _basicGraph.Vertices[vertex];
|
||||
var sites = new List<MapSite> { site };
|
||||
var location = site.Metadata.GetProperty<Location>(LandmassPass.SiteLocationProperty);
|
||||
var cities = map.Metadata.GetProperty<List<City>>(LocateCitiesPass.CitiesProperty);
|
||||
|
||||
for (int i = 0; i < size - 1; i++)
|
||||
{
|
||||
var neighbours = _basicGraph.Neighbours(site.Index).Select(j => _basicGraph.Vertices[j]).Where(s => s.Metadata.GetProperty<Location>(LandmassPass.SiteLocationProperty) == location).ToList();
|
||||
site = neighbours[_random.Next(neighbours.Count)];
|
||||
sites.Add(site);
|
||||
}
|
||||
foreach (var city in cities)
|
||||
AnnotateCity(city);
|
||||
}
|
||||
|
||||
foreach (var s in sites.Distinct())
|
||||
{
|
||||
newCity.AddSite(s);
|
||||
}
|
||||
|
||||
newCity.CreateRoadGraph(_voronoiGraph.Vertices);
|
||||
|
||||
var edges = newCity.roads.Edges.ToList();
|
||||
private void RemoveIncorrectEdges(City city)
|
||||
{
|
||||
var edges = city.roads.Edges.ToList();
|
||||
foreach (var (a, b) in edges)
|
||||
{
|
||||
var (va, vb) = (newCity.roads[a], newCity.roads[b]);
|
||||
var (va, vb) = (city.roads[a], city.roads[b]);
|
||||
var center = (va + vb) / 2;
|
||||
|
||||
if (!IsPointInsideCity(newCity, center))
|
||||
newCity.roads.DeleteEdge(a, b);
|
||||
if (!IsPointInsideCity(city, center))
|
||||
city.roads.DeleteEdge(a, b);
|
||||
}
|
||||
|
||||
ConnectPointsIntoRoads(newCity);
|
||||
FixRoadsDensity(newCity, minimumAngle);
|
||||
CreateFieldBoundaries(newCity);
|
||||
|
||||
return newCity;
|
||||
}
|
||||
|
||||
List<int> ChoosePoints(int number)
|
||||
private void CreateRoadGraph(City city, IList<Point> points)
|
||||
{
|
||||
var vertices = new List<int>();
|
||||
for (int i = 0; i < number; i++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
return vertices;
|
||||
var pointsForRoads = city.sites.SelectMany(site => site.Boundary.Select(i => (i, points[i])).Append((-1, site.Center))).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();
|
||||
|
||||
city.roads = generator.Delaunay.Morph(s => s.Point);
|
||||
|
||||
city.fieldBoundaries = new Graph<Point> { Vertices = city.roads.Vertices, Edges = city.edges.Select(e => (mapping[e.Item1], mapping[e.Item2])) };
|
||||
}
|
||||
|
||||
void ConnectPointsIntoRoads(City city)
|
||||
private void ConnectPointsIntoRoads(City city)
|
||||
{
|
||||
var original = city.roads.Morph(s => s, e => Point.Dist(city.roads[e.Item1], city.roads[e.Item2]));
|
||||
|
||||
@ -126,15 +105,22 @@ namespace Assets.AnnotationPass
|
||||
|
||||
foreach (var deadEnd in deadEnds)
|
||||
{
|
||||
var neighbour = city.fieldBoundaries.Neighbours(deadEnd).First();
|
||||
var closest = city.fieldBoundaries.Vertices
|
||||
.Select((_, i) => i)
|
||||
.OrderBy(i => Point.Dist(city.fieldBoundaries[i], city.fieldBoundaries[deadEnd]))
|
||||
.Skip(1)
|
||||
.First(c => c != neighbour);
|
||||
try
|
||||
{
|
||||
var neighbour = city.fieldBoundaries.Neighbours(deadEnd).First();
|
||||
var closest = city.fieldBoundaries.Vertices
|
||||
.Select((_, i) => i)
|
||||
.OrderBy(i => Point.Dist(city.fieldBoundaries[i], city.fieldBoundaries[deadEnd]))
|
||||
.Skip(1)
|
||||
.First(c => c != neighbour && PointUtils.AngleBetween(city.fieldBoundaries[deadEnd],
|
||||
city.fieldBoundaries[c], city.fieldBoundaries[neighbour]) > _minimumAngle);
|
||||
|
||||
city.fieldBoundaries.AddEdge(deadEnd, closest);
|
||||
city.roads.AddEdge(deadEnd, closest);
|
||||
city.fieldBoundaries.AddEdge(deadEnd, closest);
|
||||
city.roads.AddEdge(deadEnd, closest);
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,36 +159,5 @@ namespace Assets.AnnotationPass
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreateWorldRoadGraph()
|
||||
{
|
||||
roads.Vertices = verticesForCitites.Select(i => _basicGraph.Vertices[i]).ToList();
|
||||
|
||||
VoronoiGenerator generator = new VoronoiGenerator(roads.Vertices.Select(s => s.Center).ToList());
|
||||
generator.Generate();
|
||||
|
||||
roads.Edges = generator.Delaunay.Edges;
|
||||
}
|
||||
|
||||
void AddLanesToRoads()
|
||||
{
|
||||
// ergo dodaj randomowe połączenia xd
|
||||
}
|
||||
|
||||
public void Annotate(Map map)
|
||||
{
|
||||
_basicGraph = map.Sites.Clone() as Graph<MapSite>;
|
||||
_voronoiGraph = map.Boundaries;
|
||||
_locationGraph = map.Metadata.GetProperty<Graph<Location>>(LandmassPass.MapLocationsProperty);
|
||||
|
||||
verticesForCitites = LocateCities();
|
||||
foreach (var index in verticesForCitites)
|
||||
{
|
||||
cities.Add(CreateCity(index, _random.Next(0, 10)));
|
||||
}
|
||||
|
||||
CreateWorldRoadGraph();
|
||||
mainRoads = roads.Morph(s => s.Center);
|
||||
}
|
||||
}
|
||||
}
|
@ -22,9 +22,6 @@ namespace Assets.AnnotationPass
|
||||
|
||||
IEnumerable<int> LocateCities()
|
||||
{
|
||||
// var verticesForCitites = CountProbablitityOfCity(ChoosePoints(20));
|
||||
// verticesForCitites.Sort();
|
||||
// return verticesForCitites.GetRange(0, 10);
|
||||
return ChoosePoints(20);
|
||||
}
|
||||
|
||||
@ -52,7 +49,7 @@ namespace Assets.AnnotationPass
|
||||
return newCity;
|
||||
}
|
||||
|
||||
List<int> ChoosePoints(int number)
|
||||
IEnumerable<int> ChoosePoints(int number)
|
||||
{
|
||||
var vertices = new List<int>();
|
||||
|
||||
|
@ -43,18 +43,5 @@ namespace Assets.Cities
|
||||
|
||||
edges = a.Union(b).Except(a.Intersect(b)).ToList();
|
||||
}
|
||||
|
||||
public void CreateRoadGraph(IList<Point> points)
|
||||
{
|
||||
var pointsForRoads = sites.SelectMany(site => site.Boundary.Select(i => (i, points[i])).Append((-1, site.Center))).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();
|
||||
|
||||
roads = generator.Delaunay.Morph(s => s.Point);
|
||||
|
||||
fieldBoundaries = new Graph<Point> { Vertices = roads.Vertices, Edges = edges.Select(e => (mapping[e.Item1], mapping[e.Item2])) };
|
||||
}
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ namespace Assets.Common
|
||||
[SerializeField]
|
||||
private Graph<MapSite> _sites = new Graph<MapSite>();
|
||||
|
||||
public int Seed { get; set; }
|
||||
public int Seed { get; }
|
||||
|
||||
public Graph<MapSite> Sites
|
||||
{
|
||||
|
@ -19,9 +19,9 @@ namespace Assets.Common
|
||||
public int Index { get; internal set; }
|
||||
public Point Center { get; set; }
|
||||
public bool IsOuter { get; set; } = false;
|
||||
public ISet<string> Tags { get; set; } = new HashSet<string> { "Empty" };
|
||||
public IEnumerable<int> Boundary { get; set; }
|
||||
public IEnumerable<(int, int)> Edges => Boundary.RotateRight().Zip(Boundary, (a, b) => (a, b));
|
||||
// public IEnumerable<(int, int)> Edges { get; set; }
|
||||
|
||||
[field: NonSerialized]
|
||||
public Map Map { get; internal set; }
|
||||
|
@ -32,6 +32,8 @@ namespace Assets
|
||||
public bool displayLocationEdges = true;
|
||||
public bool displayCities = true;
|
||||
public bool displayLocationPoints = true;
|
||||
public bool displayFieldBoundaries = true;
|
||||
public bool displayCityRoads = true;
|
||||
|
||||
[NonSerialized] public float generationTime = 0.0f;
|
||||
}
|
||||
@ -55,6 +57,9 @@ namespace Assets
|
||||
public Vector2 size = new Vector2();
|
||||
public List<LocationType> types = new List<LocationType>();
|
||||
|
||||
[Range(0f, 360f)]
|
||||
public double minimumRoadAngle = 30f;
|
||||
|
||||
[Range(2.0f, 64.0f)]
|
||||
public float radius = 8;
|
||||
public int seed = Environment.TickCount;
|
||||
@ -91,7 +96,8 @@ namespace Assets
|
||||
|
||||
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 CityFieldsPass(new Random(seed), Mathf.Deg2Rad * minimumRoadAngle));
|
||||
|
||||
return generator;
|
||||
}
|
||||
|
||||
@ -192,7 +198,7 @@ namespace Assets
|
||||
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
||||
if (debug.displayLocationEdges)
|
||||
{
|
||||
foreach (var location in Map.Metadata.GetProperty<Graph<Location>>(LandmassPass.MapLocationsProperty).Vertices)
|
||||
@ -210,6 +216,27 @@ namespace Assets
|
||||
Gizmos.color = Color.magenta;
|
||||
DisplayGraphCities(Map.Metadata.GetProperty<IEnumerable<City>>(LocateCitiesPass.CitiesProperty));
|
||||
}
|
||||
|
||||
var cities = Map.Metadata.GetProperty<List<City>>(LocateCitiesPass.CitiesProperty);
|
||||
|
||||
if (debug.displayFieldBoundaries)
|
||||
{
|
||||
Gizmos.color = Color.white;
|
||||
|
||||
foreach (var city in cities)
|
||||
DebugUtils.DisplayGraphEdges(city.fieldBoundaries);
|
||||
}
|
||||
|
||||
if (debug.displayCityRoads)
|
||||
{
|
||||
Gizmos.color = Color.green;
|
||||
|
||||
foreach (var city in cities)
|
||||
{
|
||||
DebugUtils.DisplayGraphEdges(city.roads);
|
||||
DebugUtils.DisplayGraphVertices(city.roads, displayLabels: debug.displayLabels);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user