[otwarty teren] wydzielenie generowania ze skryptow unity part 4

This commit is contained in:
Kacper Donat 2019-11-10 19:05:41 +01:00
parent 085ab2d62d
commit b06f9f1887
62 changed files with 1060 additions and 1097 deletions

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 1a667fae02f346199ad742a83f9d8610
timeCreated: 1573304795

View File

@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
namespace Assets.Common
{
[Serializable]
public class MapSite
{
public readonly Metadata Metadata = new Metadata();
public MapSite(Point center, IEnumerable<Point> boundary)
{
Center = center;
Boundary = boundary;
}
public Point Center { get; set; }
public IEnumerable<Point> Boundary { get; set; }
[field: NonSerialized]
public Map Map { get; internal set; }
}
}

View File

@ -1,6 +1,5 @@
using System; using System;
using Assets; using Assets;
using Assets.Scripts;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using Random = UnityEngine.Random; using Random = UnityEngine.Random;
@ -10,31 +9,27 @@ namespace Assets.Editor
[CustomEditor(typeof(CityGenerator))] [CustomEditor(typeof(CityGenerator))]
public class CityGeneratorUI : UnityEditor.Editor public class CityGeneratorUI : UnityEditor.Editor
{ {
public override void OnInspectorGUI() public override void OnInspectorGUI()
{ {
CityGenerator generator = (CityGenerator)target; CityGenerator generator = (CityGenerator)target;
DrawDefaultInspector(); DrawDefaultInspector();
if (GUILayout.Button("Reset")) // if (GUILayout.Button("Reset"))
{ // {
generator.Reset(); // generator.Reset();
} // }
//
if (GUILayout.Button("Generate")) // if (GUILayout.Button("Generate"))
{ // {
generator.Reset(); // generator.Reset();
generator.Generate(); // generator.Generate();
} // }
//
if (GUILayout.Button("New City")) // if (GUILayout.Button("New City"))
{ // {
generator.NewCity(); // generator.NewCity();
} // }
} }
} }
} }

View File

@ -15,7 +15,7 @@ namespace Editor
if (GUILayout.Button("Generate")) if (GUILayout.Button("Generate"))
{ {
target.Generate(); // target.Generate();
} }
} }
} }

View File

@ -1,77 +0,0 @@
using System;
using Assets;
using UnityEditor;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Editor
{
[CustomEditor(typeof (LandmassGenerator))]
public class GraphGeneratorUI : UnityEditor.Editor
{
private string _threshold;
private bool _showInfo = false;
public override void OnInspectorGUI()
{
LandmassGenerator generator = (LandmassGenerator)target;
_showInfo = EditorGUILayout.Foldout(_showInfo, "Debug info");
if (_showInfo)
{
EditorGUILayout.LabelField($"Stage: ", generator.Stage.ToString());
EditorGUILayout.LabelField($"Took: ", $"{generator.debug.generationTime:F3}s");
}
DrawDefaultInspector();
if (GUILayout.Button("Reset")) {
generator.Reset();
}
if (GUILayout.Button("Generate Random"))
{
generator.seed = (int)(Random.value * int.MaxValue);
generator.Reset();
generator.Generate();
}
if (GUILayout.Button("Generate")) {
generator.Generate();
}
if (GUILayout.Button("Step")) {
generator.Step();
}
GUILayout.BeginHorizontal();
{
_threshold = GUILayout.TextField(_threshold);
if (GUILayout.Button("Go")) {
try
{
generator.Rewind(float.Parse(_threshold));
}
catch
{
GUILayout.Label("You should pass valid number.");
}
}
}
GUILayout.EndHorizontal();
}
private void OnSceneGUI()
{
LandmassGenerator generator = (LandmassGenerator)target;
if (generator.VoronoiGenerator != null)
{
var moved = Handles.PositionHandle(generator.transform.position + Vector3.up * (float)generator.VoronoiGenerator.Line.Directrix, Quaternion.identity);
generator.VoronoiGenerator.Line.Directrix = moved.y;
}
}
}
}

View File

@ -0,0 +1,34 @@
using System;
using Assets;
using UnityEditor;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Editor
{
[CustomEditor(typeof (LandmassGenerator))]
public class LandmassGeneratorUI : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
LandmassGenerator generator = (LandmassGenerator)target;
DrawDefaultInspector();
if (GUILayout.Button("Reset")) {
generator.Reset();
}
if (GUILayout.Button("Generate Random"))
{
generator.seed = (int)(Random.value * int.MaxValue);
generator.Reset();
generator.Generate();
}
if (GUILayout.Button("Generate")) {
generator.Generate();
}
}
}
}

View File

@ -15,7 +15,7 @@ namespace Editor
if (GUILayout.Button("Generate")) if (GUILayout.Button("Generate"))
{ {
target.Generate(); // target.Generate();
} }
} }
} }

View File

@ -120,6 +120,65 @@ NavMeshSettings:
debug: debug:
m_Flags: 0 m_Flags: 0
m_NavMeshData: {fileID: 0} m_NavMeshData: {fileID: 0}
--- !u!1 &319467306
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 319467308}
- component: {fileID: 319467307}
m_Layer: 0
m_Name: Map
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &319467307
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 319467306}
m_Enabled: 0
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 06dfaa94f8713f12fbe207b61b694c90, type: 3}
m_Name:
m_EditorClassIdentifier:
debug:
enabled: 1
displayPoints: 1
displayBoundary: 1
displayVertices: 1
displayNeighbours: 0
displayLabels: 0
displayEdges: 1
displayLocations: 1
displayLocationCells: 1
displayLocationEdges: 1
displayLocationPoints: 1
size: {x: 100, y: 100}
types: []
radius: 4
seed: 2040725760
--- !u!4 &319467308
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 319467306}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &519420028 --- !u!1 &519420028
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -1,6 +1,6 @@
using Assets.Common; using Assets.Common;
namespace Assets namespace Assets.AnnotationPass
{ {
public interface IAnnotationPass public interface IAnnotationPass
{ {

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2f8409bbb3b843a7b41dd4ee8f6ea4d2
timeCreated: 1573389323

View File

@ -1,47 +1,48 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Assets.Voronoi; using Assets.Common;
using Random = System.Random;
namespace Assets.Common namespace Assets.AnnotationPass
{ {
public class LocationGenerator public class LocationPass : IAnnotationPass
{ {
private readonly IList<Point> _points; public const string MapLocationsProperty = "Locations";
private readonly Graph<Site> _sites; public const string SiteLocationProperty = "Location";
private IList<Point> _points;
private Graph<MapSite> _sites;
private readonly Graph<Location> _locations; private readonly Graph<Location> _locations;
private readonly List<(int, Location)> _queue = new List<(int, Location)>(); private readonly List<(int, Location)> _queue = new List<(int, Location)>();
private readonly Random _random; private Random _random;
public Graph<Site> Sites => _sites;
public Graph<Location> Result => _locations;
public bool Done => _queue.Count == 0;
public LocationGenerator(List<Location> locations, Graph<Site> sites, IList<Point> points, Random random = null) public LocationPass(IEnumerable<Location> locations, Random random = null)
{ {
_points = points;
_sites = sites.Morph(s => s);
_locations = new Graph<Location> { Vertices = new List<Location>(locations) }; _locations = new Graph<Location> { Vertices = new List<Location>(locations) };
_random = random ?? new Random(); _random = random ?? new Random();
} }
public void SetLocation(int vertex, Location location) private void Process(int vertex, Location location)
{ {
location.AddSite(_sites.Vertices[vertex]); location.AddSite(_sites.Vertices[vertex]);
_sites.Vertices[vertex].Metadata.SetProperty(SiteLocationProperty, location);
foreach (var neighbour in _sites.Neighbours(vertex)) foreach (var neighbour in _sites.Neighbours(vertex))
if (_sites.Vertices[neighbour].Location == null) {
var site = _sites[neighbour];
if (!site.Metadata.HasProperty(SiteLocationProperty))
_queue.Add((neighbour, location)); _queue.Add((neighbour, location));
else if (location != _sites.Vertices[neighbour].Location) else if (location != site.Metadata.GetProperty<Location>(SiteLocationProperty))
_locations.AddEdge( _locations.AddEdge(
_locations.Vertices.IndexOf(location), _locations.Vertices.IndexOf(location),
_locations.Vertices.IndexOf(_sites.Vertices[neighbour].Location) _locations.Vertices.IndexOf(site.Metadata.GetProperty<Location>(SiteLocationProperty))
); );
}
} }
private (int, Location) Dequeue() private (int, Location) Dequeue()
@ -53,19 +54,19 @@ namespace Assets.Common
_queue.RemoveAt(index); _queue.RemoveAt(index);
if (_sites.Vertices[pair.Item1].Location == null) return pair; if (!_sites[pair.Item1].Metadata.HasProperty(SiteLocationProperty)) return pair;
} }
throw new Exception("No more elements."); throw new Exception("No more elements.");
} }
public void Step() private void Step()
{ {
try try
{ {
var (vertex, location) = Dequeue(); var (vertex, location) = Dequeue();
SetLocation(vertex, location); Process(vertex, location);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -79,7 +80,7 @@ namespace Assets.Common
var center = location.Center; var center = location.Center;
var left = location.BoundaryEdges; var left = location.BoundaryEdges;
location.BoundaryEdges = new List<(int, int)>() { EnsureClockwise(center, left[0]) }; location.BoundaryEdges = new List<(int, int)> { EnsureClockwise(center, left[0]) };
(int, int) last = location.BoundaryEdges[0]; (int, int) last = location.BoundaryEdges[0];
left.RemoveAt(0); left.RemoveAt(0);
@ -104,5 +105,31 @@ namespace Assets.Common
{ {
return PointUtils.IsClockwise(center, _points[edge.Item1], _points[edge.Item2]) ? (edge.Item2, edge.Item1) : edge; return PointUtils.IsClockwise(center, _points[edge.Item1], _points[edge.Item2]) ? (edge.Item2, edge.Item1) : edge;
} }
public void Annotate(Map map)
{
_random = new Random(map.Seed);
_sites = map.Sites;
_points = map.Boundaries.Vertices;
map.Metadata.SetProperty(MapLocationsProperty, _locations);
var initial =
from location in _locations.Vertices.Skip(1)
select (_random.Next(map.Sites.Vertices.Count), location);
initial = initial.Concat(
map.Sites.Vertices
.Select((s, i) => (Site: s, Vertex: i))
.Where(t => t.Site.IsOuter)
.Select(t => (t.Vertex, _locations[0]))
);
foreach (var (vertex, location) in initial)
Process(vertex, location);
while (_queue.Count != 0)
Step();
}
} }
} }

View File

@ -1,12 +0,0 @@
using Assets.Common;
namespace Assets.AnnotationPass
{
public class LocationsPass : IAnnotationPass
{
public void Annotate(Map map)
{
throw new System.NotImplementedException();
}
}
}

View File

@ -5,433 +5,433 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
namespace Assets.Scripts //namespace Assets.Scripts
{ //{
public class PointProximityComparer : IEqualityComparer<Point> // public class PointProximityComparer : IEqualityComparer<Point>
{ // {
double _threshold; // double _threshold;
//
public PointProximityComparer(double threshold = 0.2) // public PointProximityComparer(double threshold = 0.2)
{ // {
_threshold = threshold; // _threshold = threshold;
} // }
//
public bool Equals(Point x, Point y) // public bool Equals(Point x, Point y)
{ // {
return Point.Dist(x, y) < _threshold; // return Point.Dist(x, y) < _threshold;
} // }
//
public int GetHashCode(Point obj) // public int GetHashCode(Point obj)
{ // {
return obj.GetHashCode(); // return obj.GetHashCode();
} // }
} // }
//
public class CityField // public class CityField
{ // {
public List<Point> boundary; // public List<Point> boundary;
} // }
//
public class City // public class City
{ // {
public Graph<Voronoi.Site> startGraph; // public Graph<Voronoi.Site> startGraph;
public List<Voronoi.Site> sites; // public List<Voronoi.Site> sites;
//
public Graph<Point> roads = new Graph<Point>(); // public Graph<Point> roads = new Graph<Point>();
public Graph<Point> fieldBoundaries = new Graph<Point>(); // public Graph<Point> fieldBoundaries = new Graph<Point>();
//
public List<CityField> fields = new List<CityField>(); // public List<CityField> fields = new List<CityField>();
//
public List<(int, int)> edges; // public List<(int, int)> edges;
//
public City(Graph<Site> startGraph) // public City(Graph<Site> startGraph)
{ // {
this.startGraph = startGraph; // this.startGraph = startGraph;
//
this.sites = new List<Voronoi.Site>(); // this.sites = new List<Voronoi.Site>();
this.edges = new List<(int, int)>(); // 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.sites = sitesList; // this.sites = sitesList;
} // }
//
public void AddSite(Site site) // public void AddSite(Site site)
{ // {
sites.Add(site); // sites.Add(site);
FixBoundaryEdges(site); // FixBoundaryEdges(site);
} // }
//
private void FixBoundaryEdges(Site site) // private void FixBoundaryEdges(Site site)
{ // {
var a = edges; // 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));
//
edges = 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)
{ // {
var pointsForRoads = sites.SelectMany(site => site.Vertices.Select(i => (i, points[i])).Append((-1, site.Point))).Distinct().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); // 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)); // VoronoiGenerator generator = new VoronoiGenerator(pointsForRoads.Select(x => x.Item2));
generator.Generate(); // generator.Generate();
//
roads = generator.Delaunay.Morph(s => s.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])) }; // fieldBoundaries = new Graph<Point> { Vertices = roads.Vertices, Edges = edges.Select(e => (mapping[e.Item1], mapping[e.Item2])) };
} // }
} // }
//
[Serializable] // [Serializable]
public class GraphGeneratorDebug // public class GraphGeneratorDebug
{ // {
public bool displayVertices = false; // public bool displayVertices = false;
public bool displayCrossroads = true; // public bool displayCrossroads = true;
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 displayFieldBoundaries = true; // public bool displayFieldBoundaries = true;
public bool displayWorldRoads = false; // public bool displayWorldRoads = false;
} // }
//
[RequireComponent(typeof(LandmassGenerator))] // [RequireComponent(typeof(LandmassGenerator))]
public class CityGenerator : MonoBehaviour public class CityGenerator : MonoBehaviour
{ {
private System.Random _random; // private System.Random _random;
private Graph<Point> _voronoiGraph; // private Graph<Point> _voronoiGraph;
private Graph<Location> _locationGraph; // private Graph<Location> _locationGraph;
private Graph<Site> _basicGraph; // private Graph<Site> _basicGraph;
private List<int> verticesForRoads; // private List<int> verticesForRoads;
private List<int> verticesForCitites; // private List<int> verticesForCitites;
//
public GraphGeneratorDebug debug; // public GraphGeneratorDebug debug;
public double minimumAngle = 0.25; // public double minimumAngle = 0.25;
//
public List<City> cities = new List<City>(); // public List<City> cities = new List<City>();
//
Graph<Site> roads = new Graph<Site>(); // 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)
{ // {
List<int> probabilities = new List<int>(); // List<int> probabilities = new List<int>();
vertices.ForEach(v => probabilities.Add((v % 2 == 0 ? _random.Next(0, 50) : _random.Next(50, 100)))); // vertices.ForEach(v => probabilities.Add((v % 2 == 0 ? _random.Next(0, 50) : _random.Next(50, 100))));
return probabilities; // return probabilities;
} // }
//
List<int> LocateCities() // List<int> LocateCities()
{ // {
// var verticesForCitites = CountProbablitityOfCity(ChoosePoints(20)); // // var verticesForCitites = CountProbablitityOfCity(ChoosePoints(20));
// verticesForCitites.Sort(); // // verticesForCitites.Sort();
// return verticesForCitites.GetRange(0, 10); // // return verticesForCitites.GetRange(0, 10);
return ChoosePoints(20); // return ChoosePoints(20);
} // }
//
public bool IsPointInsideCity(City city, Point point) // public bool IsPointInsideCity(City city, Point point)
{ // {
return city.sites.Any(s => PointUtils.IsPointInside(point, s.Vertices.Select(i => _voronoiGraph[i]).ToArray())); // 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);
var site = _basicGraph.Vertices[vertex]; // var site = _basicGraph.Vertices[vertex];
var sites = new List<Site>() { site }; // var sites = new List<Site>() { site };
var location = site.Location; // var location = site.Location;
//
for (int i = 0; i < size - 1; i++) // for (int i = 0; i < size - 1; i++)
{ // {
location = site.Location; // location = site.Location;
var neighbours = _basicGraph.Neighbours(site.Index).Select(j => _basicGraph.Vertices[j]).Where(s => s.Location == location).ToList(); // var neighbours = _basicGraph.Neighbours(site.Index).Select(j => _basicGraph.Vertices[j]).Where(s => s.Location == location).ToList();
site = neighbours[_random.Next(neighbours.Count)]; // site = neighbours[_random.Next(neighbours.Count)];
sites.Add(site); // sites.Add(site);
} // }
//
foreach (var s in sites.Distinct()) // foreach (var s in sites.Distinct())
{ // {
newCity.AddSite(s); // newCity.AddSite(s);
} // }
//
newCity.CreateRoadGraph(_voronoiGraph.Vertices); // newCity.CreateRoadGraph(_voronoiGraph.Vertices);
//
var edges = newCity.roads.Edges.ToList(); // var edges = newCity.roads.Edges.ToList();
foreach (var (a, b) in edges) // foreach (var (a, b) in edges)
{ // {
var (va, vb) = (newCity.roads[a], newCity.roads[b]); // var (va, vb) = (newCity.roads[a], newCity.roads[b]);
var center = (va + vb) / 2; // var center = (va + vb) / 2;
//
if (!IsPointInsideCity(newCity, center)) // if (!IsPointInsideCity(newCity, center))
newCity.roads.DeleteEdge(a, b); // newCity.roads.DeleteEdge(a, b);
} // }
//
ConnectPointsIntoRoads(newCity); // ConnectPointsIntoRoads(newCity);
FixRoadsDensity(newCity, minimumAngle); // FixRoadsDensity(newCity, minimumAngle);
CreateFieldBoundaries(newCity); // CreateFieldBoundaries(newCity);
//
return newCity; // return newCity;
} // }
//
List<int> ChoosePoints(int number) // List<int> ChoosePoints(int number)
{ // {
var vertices = new List<int>(); // var vertices = new List<int>();
for (int i = 0; i < number; i++) // for (int i = 0; i < number; i++)
{ // {
var randomLocation = _locationGraph.Vertices[_random.Next(1, _locationGraph.Vertices.Count())]; // var randomLocation = _locationGraph.Vertices[_random.Next(1, _locationGraph.Vertices.Count())];
var count = randomLocation.Sites.Count(); // var count = randomLocation.Sites.Count();
var randomPoint = randomLocation.Sites[_random.Next(0, count)]; // var randomPoint = randomLocation.Sites[_random.Next(0, count)];
vertices.Add(randomPoint.Index); // vertices.Add(randomPoint.Index);
} // }
return vertices; // return vertices;
} // }
//
void ConnectPointsIntoRoads(City city) // void ConnectPointsIntoRoads(City city)
{ // {
var original = city.roads.Morph(s => s, e => Point.Dist(city.roads[e.Item1], city.roads[e.Item2])); // 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.
//
var edges = original.Edges.OrderByDescending(e => original.GetEdgeData(e)); // var edges = original.Edges.OrderByDescending(e => original.GetEdgeData(e));
//
Graph<Point> roads = new Graph<Point>() { Vertices = city.roads.Vertices }; // Graph<Point> roads = new Graph<Point>() { Vertices = city.roads.Vertices };
//
foreach (var edge in original.Edges) // foreach (var edge in original.Edges)
{ // {
roads.AddEdge(edge.Item1, edge.Item2); // roads.AddEdge(edge.Item1, edge.Item2);
//
if (Graph<Point>.HasCycle(roads)) // if (Graph<Point>.HasCycle(roads))
roads.DeleteEdge(edge.Item1, edge.Item2); // roads.DeleteEdge(edge.Item1, edge.Item2);
if (roads.Edges.Count() == roads.Vertices.Count() - 1) // if (roads.Edges.Count() == roads.Vertices.Count() - 1)
break; // break;
} // }
//
city.roads = roads; // city.roads = roads;
} // }
//
private void CreateFieldBoundaries(City city) // private void CreateFieldBoundaries(City city)
{ // {
foreach (var (a, b) in city.roads.Edges) // foreach (var (a, b) in city.roads.Edges)
city.fieldBoundaries.AddEdge(a, b); // city.fieldBoundaries.AddEdge(a, b);
//
var deadEnds = city.fieldBoundaries.Vertices.Select((_, i) => i).Where(i => city.fieldBoundaries.Neighbours(i).Count() == 1); // var deadEnds = city.fieldBoundaries.Vertices.Select((_, i) => i).Where(i => city.fieldBoundaries.Neighbours(i).Count() == 1);
//
foreach (var deadEnd in deadEnds) // foreach (var deadEnd in deadEnds)
{ // {
var neighbour = city.fieldBoundaries.Neighbours(deadEnd).First(); // var neighbour = city.fieldBoundaries.Neighbours(deadEnd).First();
var closest = city.fieldBoundaries.Vertices // var closest = city.fieldBoundaries.Vertices
.Select((_, i) => i) // .Select((_, i) => i)
.OrderBy(i => Point.Dist(city.fieldBoundaries[i], city.fieldBoundaries[deadEnd])) // .OrderBy(i => Point.Dist(city.fieldBoundaries[i], city.fieldBoundaries[deadEnd]))
.Skip(1) // .Skip(1)
.First(c => c != neighbour); // .First(c => c != neighbour);
//
city.fieldBoundaries.AddEdge(deadEnd, closest); // city.fieldBoundaries.AddEdge(deadEnd, closest);
city.roads.AddEdge(deadEnd, closest); // city.roads.AddEdge(deadEnd, closest);
} // }
} // }
//
//
private void FixRoadsDensity(City city, double angle = 0.25f) // private void FixRoadsDensity(City city, double angle = 0.25f)
{ // {
// dla każdego punktu w grafie dróg // // dla każdego punktu w grafie dróg
// chyba że ma 2 to pomiń? // // chyba że ma 2 to pomiń?
// wyznacz punkt 0 // // wyznacz punkt 0
// oblicz odległości kątowe do wszystkich punktów // // oblicz odległości kątowe do wszystkich punktów
// posortuj je // // posortuj je
// między wszystkimiu parami oblicz kąt // // między wszystkimiu parami oblicz kąt
// potem według jakiegoś parametru usuń te, które są za bliskie // // potem według jakiegoś parametru usuń te, które są za bliskie
//
//
for (int i = 0; i < city.roads.Vertices.Count(); i++) // for (int i = 0; i < city.roads.Vertices.Count(); i++)
{ // {
var p = city.roads[i]; // var p = city.roads[i];
if (city.roads.Neighbours(i).Count() <= 2) // if (city.roads.Neighbours(i).Count() <= 2)
continue; // continue;
//
var reference = new Point(p.x, p.y + 30); // var reference = new Point(p.x, p.y + 30);
//
var orderedNeighours = city.roads.Neighbours(i) // var orderedNeighours = city.roads.Neighbours(i)
.Select(n => (Vertex: n, Point: city.roads[n])) // .Select(n => (Vertex: n, Point: city.roads[n]))
.Select(x => (Vertex: x.Vertex, Angle: PointUtils.AngleBetween(p, reference, x.Point))) // .Select(x => (Vertex: x.Vertex, Angle: PointUtils.AngleBetween(p, reference, x.Point)))
.OrderBy(x => x.Angle) // .OrderBy(x => x.Angle)
.Select(x => x.Vertex); // .Select(x => x.Vertex);
//
foreach (var (a, b) in orderedNeighours.RotateRight(1).Zip(orderedNeighours, (a, b) => (a, b))) // foreach (var (a, b) in orderedNeighours.RotateRight(1).Zip(orderedNeighours, (a, b) => (a, b)))
{ // {
if( PointUtils.AngleBetween(p, city.roads[a], city.roads[b]) < angle) // if( PointUtils.AngleBetween(p, city.roads[a], city.roads[b]) < angle)
{ // {
city.roads.DeleteEdge(i, a); // city.roads.DeleteEdge(i, a);
} // }
} // }
} // }
} // }
//
//
//
//
//
//
void CreateWorldRoadGraph() // void CreateWorldRoadGraph()
{ // {
roads.Vertices = verticesForCitites.Select(i => _basicGraph.Vertices[i]).ToList(); // roads.Vertices = verticesForCitites.Select(i => _basicGraph.Vertices[i]).ToList();
//
VoronoiGenerator generator = new VoronoiGenerator(roads.Vertices.Select(s => s.Point).ToList()); // VoronoiGenerator generator = new VoronoiGenerator(roads.Vertices.Select(s => s.Point).ToList());
generator.Generate(); // generator.Generate();
//
roads.Edges = generator.Delaunay.Edges; // roads.Edges = generator.Delaunay.Edges;
} // }
//
//
void AddLanesToRoads() // void AddLanesToRoads()
{ // {
// ergo dodaj randomowe połączenia xd // // ergo dodaj randomowe połączenia xd
} // }
//
//
//
//
// UI Methods // // UI Methods
//
//
public void Start() // public void Start()
{ // {
Reset(); // Reset();
} // }
//
public void Reset() // public void Reset()
{ // {
//
var graphGenerator = GetComponent<LandmassGenerator>(); // var graphGenerator = GetComponent<LandmassGenerator>();
_random = new System.Random(graphGenerator.seed); // _random = new System.Random(graphGenerator.seed);
cities = new List<City>(); // cities = new List<City>();
} // }
//
public void NewCity() // public void NewCity()
{ // {
cities.Add(CreateCity(LocateCities()[_random.Next(0, 10)], _random.Next(0, 10))); // cities.Add(CreateCity(LocateCities()[_random.Next(0, 10)], _random.Next(0, 10)));
} // }
//
public void Generate() // public void Generate()
{ // {
var graphGenerator = GetComponent<LandmassGenerator>(); // var graphGenerator = GetComponent<LandmassGenerator>();
graphGenerator.Generate(); // graphGenerator.Generate();
_basicGraph = graphGenerator.VoronoiGenerator.Delaunay.Morph(l => l); // _basicGraph = graphGenerator.VoronoiGenerator.Delaunay.Morph(l => l);
_voronoiGraph = graphGenerator.VoronoiGenerator.Voronoi; // _voronoiGraph = graphGenerator.VoronoiGenerator.Voronoi;
_locationGraph = graphGenerator.LocationGenerator.Result; // _locationGraph = graphGenerator.LocationGenerator.Result;
//
verticesForCitites = LocateCities(); // verticesForCitites = LocateCities();
foreach (var index in verticesForCitites) // foreach (var index in verticesForCitites)
{ // {
cities.Add(CreateCity(index, _random.Next(0, 10))); // cities.Add(CreateCity(index, _random.Next(0, 10)));
} // }
//
CreateWorldRoadGraph(); // CreateWorldRoadGraph();
mainRoads = roads.Morph(s => s.Point); // mainRoads = roads.Morph(s => s.Point);
//
} // }
//
private void DisplayGraphVertices(Graph<Point> graph) // private void DisplayGraphVertices(Graph<Point> graph)
{ // {
var vertices = graph.Vertices.Select(p => p.ToVector3()); // var vertices = graph.Vertices.Select(p => p.ToVector3());
var offset = Vector3.right; // var offset = Vector3.right;
//
foreach (var (v, i) in vertices.Select((x, i) => (x, i))) // foreach (var (v, i) in vertices.Select((x, i) => (x, i)))
{ // {
Gizmos.DrawSphere(v, 1); // Gizmos.DrawSphere(v, 1);
} // }
} // }
//
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);
//} // //}
} // }
//
//
private void DisplayGraphCities(List<City> cities) // private void DisplayGraphCities(List<City> cities)
{ // {
foreach (City city in cities) // foreach (City city in cities)
{ // {
Gizmos.color = Color.magenta; // Gizmos.color = Color.magenta;
foreach (var (a, b) in city.edges) // 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.sites) // foreach (var a in city.sites)
Gizmos.DrawSphere(a.Point.ToVector3(), 1); // Gizmos.DrawSphere(a.Point.ToVector3(), 1);
} // }
} // }
//
//
private void DisplayGraphEdges(Graph<Point> graph) // private void DisplayGraphEdges(Graph<Point> graph)
{ // {
var edges = graph.Edges // var edges = graph.Edges
.Select(edge => (graph.Vertices[edge.Item1], graph.Vertices[edge.Item2])) // .Select(edge => (graph.Vertices[edge.Item1], graph.Vertices[edge.Item2]))
.Select(edge => (edge.Item1.ToVector3(), edge.Item2.ToVector3())); // .Select(edge => (edge.Item1.ToVector3(), edge.Item2.ToVector3()));
//
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()
{ // {
//
if (debug.displayVertices) // if (debug.displayVertices)
{ // {
Gizmos.color = Color.white; // Gizmos.color = Color.white;
DisplayGraphVertices(_basicGraph.Morph(l => l.Point)); // DisplayGraphVertices(_basicGraph.Morph(l => l.Point));
} // }
//
if (debug.displayEdges) // if (debug.displayEdges)
{ // {
Gizmos.color = Color.white; // Gizmos.color = Color.white;
DisplayGraphEdges(_basicGraph.Morph(l => l.Point)); // DisplayGraphEdges(_basicGraph.Morph(l => l.Point));
} // }
//
if (debug.displayCrossroads) // if (debug.displayCrossroads)
{ // {
Gizmos.color = Color.magenta; // Gizmos.color = Color.magenta;
DisplayGraphCrossroads(_basicGraph.Morph(l => l.Point), verticesForRoads); // DisplayGraphCrossroads(_basicGraph.Morph(l => l.Point), verticesForRoads);
} // }
//
if (debug.displayCities) // if (debug.displayCities)
{ // {
Gizmos.color = Color.magenta; // Gizmos.color = Color.magenta;
DisplayGraphCities(cities); // DisplayGraphCities(cities);
} // }
//
if (debug.displayFieldBoundaries) // if (debug.displayFieldBoundaries)
{ // {
Gizmos.color = Color.white; // Gizmos.color = Color.white;
//
foreach (var city in cities) // foreach (var city in cities)
DisplayGraphEdges(city.fieldBoundaries); // DisplayGraphEdges(city.fieldBoundaries);
} // }
//
if (debug.displayCityRoads) // if (debug.displayCityRoads)
{ // {
Gizmos.color = Color.green; // Gizmos.color = Color.green;
//
foreach (var city in cities) // foreach (var city in cities)
{ // {
DisplayGraphEdges(city.roads); // DisplayGraphEdges(city.roads);
DisplayGraphVertices(city.roads); // DisplayGraphVertices(city.roads);
} // }
} // }
//
//
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);
Gizmos.color = Color.blue; // Gizmos.color = Color.blue;
DisplayGraphEdges(mainRoads); // DisplayGraphEdges(mainRoads);
} // }
} // }
} }
} //}

View File

@ -6,29 +6,28 @@ namespace Assets.Common
{ {
public class Location public class Location
{ {
public List<Site> Sites = new List<Site>(); public List<MapSite> Sites = new List<MapSite>();
public IEnumerable<int> Points => Sites.SelectMany(site => site.Vertices); public IEnumerable<int> Points => Sites.SelectMany(site => site.Boundary);
public IEnumerable<int> BoundaryPoints => BoundaryEdges.SelectMany(edge => new [] { edge.Item1, edge.Item2 }).Distinct(); public IEnumerable<int> BoundaryPoints => BoundaryEdges.SelectMany(edge => new [] { edge.Item1, edge.Item2 }).Distinct();
public IEnumerable<int> InsidePoints => Points.Except(BoundaryPoints); public IEnumerable<int> InsidePoints => Points.Except(BoundaryPoints);
public List<(int, int)> BoundaryEdges = new List<(int, int)>(); public List<(int, int)> BoundaryEdges = new List<(int, int)>();
public Point Center => PointUtils.Mean(Sites.Select(s => s.Point)); public Point Center => PointUtils.Mean(Sites.Select(s => s.Center));
public LocationType Type; public LocationType Type;
public List<Point> DetailedEdge = new List<Point>(); public List<Point> DetailedEdge = new List<Point>();
public void AddSite(Site site) public void AddSite(MapSite site)
{ {
site.Location = this;
Sites.Add(site); Sites.Add(site);
FixBoundaryEdges(site); FixBoundaryEdges(site);
} }
private void FixBoundaryEdges(Site site) private void FixBoundaryEdges(MapSite site)
{ {
var a = BoundaryEdges; var a = BoundaryEdges;
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));

View File

@ -6,6 +6,7 @@ namespace Assets.Common
[Serializable] [Serializable]
public class Map public class Map
{ {
[SerializeField]
private Graph<MapSite> _sites = new Graph<MapSite>(); private Graph<MapSite> _sites = new Graph<MapSite>();
public int Seed { get; set; } public int Seed { get; set; }

View File

@ -0,0 +1,28 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Assets.Common
{
[Serializable]
public class MapSite
{
public readonly Metadata Metadata = new Metadata();
public MapSite(Point center, IEnumerable<int> boundary)
{
Center = center;
Boundary = boundary;
}
public Point Center { get; set; }
public bool IsOuter { get; set; } = false;
public IEnumerable<int> Boundary { get; set; }
// public IEnumerable<(int, int)> Edges => Boundary.Append(Boundary.First()).Zip(Boundary.RotateRight(), (a, b) => (a, b));
public IEnumerable<(int, int)> Edges { get; set; }
[field: NonSerialized]
public Map Map { get; internal set; }
}
}

View File

@ -6,89 +6,89 @@ using Assets.Voronoi;
using UnityEngine; using UnityEngine;
using Random = System.Random; using Random = System.Random;
namespace Assets //namespace Assets
{ //{
[RequireComponent(typeof(MeshFilter))] // [RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))] // [RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(LandmassGenerator))] // [RequireComponent(typeof(LandmassGenerator))]
public class ForestGenerator : MonoBehaviour public class ForestGenerator : MonoBehaviour
{ {
public GameObject[] trees; // public GameObject[] trees;
[Range(1, 15)] // [Range(1, 15)]
public float radius = 3.0f; // public float radius = 3.0f;
public GameObject forest; // public GameObject forest;
//
private Random _random = new Random(); // private Random _random = new Random();
private List<Site> _sites; // private List<Site> _sites;
//
private LandmassGenerator Generator => GetComponent<LandmassGenerator>(); // private LandmassGenerator Generator => GetComponent<LandmassGenerator>();
//
public void Generate() // public void Generate()
{ // {
Cleanup(); // Cleanup();
//
Generator.EnsureGenerated(); // Generator.EnsureGenerated();
//
FindForestSites(); // FindForestSites();
PlaceTrees(); // PlaceTrees();
//
_random = new Random(Generator.seed); // _random = new Random(Generator.seed);
} // }
//
private void PlaceTrees() // private void PlaceTrees()
{ // {
foreach (Site 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.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, point))) // foreach (var point in points.Select(point => point + bounding.Min).Where(point => IsPointInSite(site, point)))
PlaceRandomTree(point.ToVector3() + offset); // PlaceRandomTree(point.ToVector3() + offset);
} // }
} // }
//
public void Cleanup() // public void Cleanup()
{ // {
var destroy = new List<GameObject>(); // var destroy = new List<GameObject>();
//
foreach (var child in forest.transform) // foreach (var child in forest.transform)
if (child is Transform t) // if (child is Transform t)
destroy.Add(t.gameObject); // destroy.Add(t.gameObject);
//
foreach (var @object in destroy) // foreach (var @object in destroy)
DestroyImmediate(@object); // DestroyImmediate(@object);
} // }
//
private void FindForestSites() // private void FindForestSites()
{ // {
_sites = new List<Site>(); // _sites = new List<Site>();
//
foreach (var location in Generator.LocationGraph.Vertices.Skip(1)) // foreach (var location in Generator.LocationGraph.Vertices.Skip(1))
{ // {
var count = _random.Next(10); // var count = _random.Next(10);
//
for (int i = 0; i < count; i++) // for (int i = 0; i < count; i++)
_sites.Add(location.Sites[_random.Next(location.Sites.Count)]); // _sites.Add(location.Sites[_random.Next(location.Sites.Count)]);
} // }
} // }
//
private void PlaceRandomTree(Vector3 pos) // private void PlaceRandomTree(Vector3 pos)
{ // {
GameObject tree = Instantiate(trees[_random.Next(trees.Length)], forest.transform); // GameObject tree = Instantiate(trees[_random.Next(trees.Length)], forest.transform);
//
tree.transform.position = pos - Vector3.down * 0.2f; // tree.transform.position = pos - Vector3.down * 0.2f;
} // }
//
private bool IsPointInSite(Site site, Point point) // private bool IsPointInSite(Site site, Point point)
{ // {
var polygon = site.Vertices.Select(i => Generator.BoundariesGraph[i]).ToArray(); // var polygon = site.Vertices.Select(i => Generator.BoundariesGraph[i]).ToArray();
//
return PointUtils.IsPointInside(point, polygon); // return PointUtils.IsPointInside(point, polygon);
} // }
} }
} //}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 71568e6595e041ef95f62998c310450e
timeCreated: 1573389260

View File

@ -1,6 +1,6 @@
using Assets.Common; using Assets.Common;
namespace Assets namespace Assets.GridGenerator
{ {
public interface IGridGenerator public interface IGridGenerator
{ {

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7d6304beabfe4be58588b56d52f262fe
timeCreated: 1573389342

View File

@ -1,10 +1,10 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Assets.Common; using Assets.Common;
using Assets.PointDistribution; using Assets.PointDistribution;
using Assets.Voronoi; using Assets.Voronoi;
namespace Assets namespace Assets.GridGenerator
{ {
public class VoronoiGridGenerator : IGridGenerator public class VoronoiGridGenerator : IGridGenerator
{ {
@ -31,13 +31,16 @@ namespace Assets
result.Boundaries = (Graph<Point>)generator.Voronoi.Clone(); result.Boundaries = (Graph<Point>)generator.Voronoi.Clone();
result.Sites = generator.Delaunay.Morph(s => result.Sites = generator.Delaunay.Morph(s =>
{ {
var site = new MapSite(s.Point, new List<Point>()); var site = new MapSite(s.Point, ClockwiseVertices(generator.Voronoi, s.Vertices)) { Edges = s.Edges };
site.Metadata.SetProperty(VoronoiSiteProperty, s); site.Metadata.SetProperty(VoronoiSiteProperty, s);
return site; return site;
}); });
foreach (var site in result.Sites.Vertices.Take(4))
site.IsOuter = true;
return result; return result;
} }
@ -55,5 +58,19 @@ namespace Assets
return points; return points;
} }
private IEnumerable<int> ClockwiseVertices(Graph<Point> graph, IEnumerable<int> vertices)
{
var enumerated = vertices as int[] ?? vertices.ToArray();
var center = PointUtils.Mean(enumerated.Select(n => graph[n]));
var reference = center + new Point(0, 1);
return enumerated
.Select(n => (Vertex: n, Point: graph[n]))
.Select(x => (Vertex: x.Vertex, Angle: PointUtils.AngleBetween(center, reference, x.Point)))
.OrderBy(x => x.Angle)
.Select(x => x.Vertex);
}
} }
} }

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: f29f3a8ef63c47e4acb0f0fe114e7cda
timeCreated: 1573323034

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: bbbede9954254e208a6e9701f51a6d9b
timeCreated: 1573323655

View File

@ -1,12 +1,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Assets.AnnotationPass;
using Assets.Common; using Assets.Common;
using Assets.GridGenerator;
using Assets.PointDistribution; using Assets.PointDistribution;
using Assets.Voronoi; using Assets.Utils;
using UnityEditor;
using UnityEngine; using UnityEngine;
using UnityEngine.Serialization;
using Random = System.Random; using Random = System.Random;
namespace Assets namespace Assets
@ -15,14 +18,12 @@ namespace Assets
public class GraphGeneratorDebug public class GraphGeneratorDebug
{ {
public bool enabled = true; public bool enabled = true;
public bool displayPoints = true; public bool displayPoints = true;
public bool displayBoundary = true; public bool displayBoundary = true;
public bool displayBeachLine = true;
public bool displayParabolas = false;
public bool displayVertices = true; public bool displayVertices = true;
public bool displayNeighbours = false; public bool displayNeighbours = false;
public bool displayLabels = false; public bool displayLabels = false;
public bool displayHalfEdges = false;
public bool displayEdges = true; public bool displayEdges = true;
public bool displayLocations = true; public bool displayLocations = true;
public bool displayLocationCells = true; public bool displayLocationCells = true;
@ -40,291 +41,151 @@ namespace Assets
public float height = 0.0f; public float height = 0.0f;
} }
public enum GenerationStage
{
Start,
Voronoi,
Location,
Done
};
[ExecuteInEditMode] [ExecuteInEditMode]
public class LandmassGenerator : MonoBehaviour public class LandmassGenerator : MonoBehaviour
{ {
private IPointDistribution _sampler; [NonSerialized] public Map Map;
private Random _random; [NonSerialized] public Thread GenerationThread;
private VoronoiGenerator _voronoiGenerator; public GraphGeneratorDebug debug;
private LocationGenerator _locationGenerator;
private List<Vector3> _points = new List<Vector3>(); public Vector2 size = new Vector2();
private List<Location> _locations = new List<Location>();
private Graph<(Point, Location)> _locationGraph;
public List<LocationType> types = new List<LocationType>(); public List<LocationType> types = new List<LocationType>();
public Graph<Site> SitesGraph => _voronoiGenerator.Delaunay;
public Graph<Point> BoundariesGraph => _voronoiGenerator.Voronoi;
public Graph<Location> LocationGraph => _locationGenerator.Result;
[Range(2.0f, 64.0f)] [Range(2.0f, 64.0f)]
public float radius = 8; public float radius = 8;
public int seed = Environment.TickCount; public int seed = Environment.TickCount;
public Vector2 size = new Vector2();
public GraphGeneratorDebug debug;
public GenerationStage Stage { get; private set; } = GenerationStage.Start;
public VoronoiGenerator VoronoiGenerator => _voronoiGenerator; public Graph<MapSite> SitesGraph => Map?.Sites;
public LocationGenerator LocationGenerator => _locationGenerator; public Graph<Point> BoundariesGraph => Map?.Boundaries;
public Graph<Location> LocationGraph => Map?.Metadata.GetProperty<Graph<Location>>(LocationPass.MapLocationsProperty);
void Start()
{
Reset();
}
public void Reset()
{
_random = new Random(seed);
_sampler = new PoissonDiskSampler(radius) { Generator = _random };
_points = new List<Vector3>();
Stage = GenerationStage.Voronoi;
_voronoiGenerator = null;
_locationGenerator = null;
_locationGraph = null;
_locations = new List<Location>() { new Location() { Type = new LocationType() { color = Color.clear, name = "Ocean", height = -1 } } };
_locations.AddRange(types.Select(type => new Location { Type = type }));
}
public void Generate() public void Generate()
{ {
var stopwatch = new Stopwatch(); GenerationThread?.Abort();
stopwatch.Start(); GenerationThread = new Thread(() =>
{
var generator = CreateMapGenerator();
var result = generator.Generate(size.x, size.y);
lock (GetType())
{
Map = result;
}
});
debug.generationTime = 0; GenerationThread.Start();
_points = new List<Vector3>();
_points.Add(new Vector3(-size.x/8, size.y / 2 + 0.1f));
_points.Add(new Vector3(size.x * 1.125f, size.y / 2 - 0.1f));
_points.Add(new Vector3(size.x / 2 - 0.1f, -size.y/8));
_points.Add(new Vector3(size.x / 2 + 0.1f, size.y * 1.125f));
_points.AddRange(_sampler.Generate(size.x, size.y).Select(x => new Vector3((float)x.x, (float)x.y)));
while (Stage != GenerationStage.Done)
{
Step();
debug.generationTime = stopwatch.ElapsedMilliseconds / 1000.0f;
}
stopwatch.Stop();
debug.generationTime = stopwatch.ElapsedMilliseconds / 1000.0f;
} }
public void EnsureGenerated() public void OnDisable()
{ {
if (this.Stage != GenerationStage.Done) GenerationThread?.Abort();
Generate();
} }
public void Step() private MapGenerator CreateMapGenerator()
{ {
if (Stage == GenerationStage.Voronoi) var generator = new MapGenerator(new VoronoiGridGenerator(seed, new PoissonDiskSampler(radius) { Generator = new Random(seed) }));
{
_voronoiGenerator.Step();
if (_voronoiGenerator.Done) generator.AddAnnotationPass(new LocationPass(types.Prepend(new LocationType { name = "Ocean", height = -1 }).Select(t => new Location { Type = t }), new Random(seed)));
{
Stage = GenerationStage.Location; return generator;
}
_locationGenerator = new LocationGenerator(_locations, _voronoiGenerator.Delaunay, _voronoiGenerator.Voronoi.Vertices, _random);
var initial = public void Reset()
from location in _locations {
select (_random.Next(_voronoiGenerator.Delaunay.Vertices.Count), location); GenerationThread?.Abort();
initial = initial.Concat(new List<int> { 0, 1, 2, 3 }.Select(i => (i, _locations[0])));
foreach (var (vertex, location) in initial)
_locationGenerator.SetLocation(vertex, location);
}
}
else if (Stage == GenerationStage.Location)
{
_locationGenerator.Step();
if (_locationGenerator.Done)
{
Stage = GenerationStage.Done;
RecalculateLocationGraph();
}
}
} }
void OnDrawGizmos() void OnDrawGizmos()
{ {
if (!debug.enabled || Map == null) return;
if (debug.displayBoundary) if (debug.displayBoundary)
{ {
Gizmos.color = Color.gray; Gizmos.color = Color.gray;
Gizmos.DrawLine(new Vector3(0, 0), new Vector3(size.x, 0)); Gizmos.DrawLine(new Vector3(0, 0, 0), new Vector3(size.x, 0, 0));
Gizmos.DrawLine(new Vector3(0, 0), new Vector3(0, size.y)); Gizmos.DrawLine(new Vector3(0, 0, 0), new Vector3(0, 0, size.y));
Gizmos.DrawLine(new Vector3(size.x, size.y), new Vector3(size.x, 0)); Gizmos.DrawLine(new Vector3(size.x, 0, size.y), new Vector3(size.x, 0, 0));
Gizmos.DrawLine(new Vector3(size.x, size.y), new Vector3(0, size.y)); Gizmos.DrawLine(new Vector3(size.x, 0, size.y), new Vector3(0, 0, size.y));
} }
if (!debug.enabled || _voronoiGenerator == null) return;
if (debug.displayPoints) if (debug.displayPoints)
{ {
Gizmos.color = Color.white; Gizmos.color = Color.white;
DisplayGraphVertices(_voronoiGenerator.Delaunay.Morph(x => x.Point)); DebugUtils.DisplayGraphVertices(Map.Sites, s => s.Center, displayLabels: debug.displayLabels);
} }
if (debug.displayNeighbours) if (debug.displayNeighbours)
{ {
Gizmos.color = Color.yellow; Gizmos.color = Color.yellow;
DisplayGraphEdges(_voronoiGenerator.Delaunay.Morph(x => x.Point)); DebugUtils.DisplayGraphEdges(Map.Sites, s => s.Center);
} }
if (debug.displayVertices) if (debug.displayVertices)
{ {
Gizmos.color = Color.blue; Gizmos.color = Color.blue;
DisplayGraphVertices(_voronoiGenerator.Voronoi); DebugUtils.DisplayGraphVertices(Map.Boundaries, displayLabels: debug.displayLabels);
}
if (debug.displayHalfEdges)
{
Gizmos.color = Color.green;
foreach (var edge in _voronoiGenerator.HalfEdges)
{
Gizmos.DrawLine(edge.Start.ToVector3(), edge.End.ToVector3());
}
} }
if (debug.displayEdges) if (debug.displayEdges)
{ {
Gizmos.color = Color.white; Gizmos.color = Color.white;
DisplayGraphEdges(_voronoiGenerator.Voronoi); DebugUtils.DisplayGraphEdges(Map.Boundaries);
} }
Gizmos.color = Color.red;
Gizmos.DrawLine(new Vector3(0, (float)_voronoiGenerator.Line.Directrix), new Vector3(size.x, (float)_voronoiGenerator.Line.Directrix));
Gizmos.color = Color.blue; Gizmos.color = Color.blue;
Vector3 start; if (!Map.Metadata.HasProperty(LocationPass.MapLocationsProperty)) return;
var locations = Map.Metadata.GetProperty<Graph<Location>>(LocationPass.MapLocationsProperty);
if (debug.displayParabolas)
{
foreach (var parabola in _voronoiGenerator.Line.Parabolas)
{
start = new Vector3(-size.x, (float)_voronoiGenerator.Line.EvalParabola(parabola.Site.Point, -size.x));
for (var x = -size.x + 0.1f; x < size.x * 2; x += 0.1f)
{
var point = new Vector3(x, (float)_voronoiGenerator.Line.EvalParabola(parabola.Site.Point, x));
Gizmos.DrawLine(start, point);
start = point;
}
}
}
if (debug.displayBeachLine)
{
Gizmos.color = Color.white;
start = new Vector3(-size.x, (float)_voronoiGenerator.Line.Eval(-size.x));
for (var x = -size.x + 0.1f; x < size.x * 2; x += 0.1f)
{
var point = new Vector3(x, (float)_voronoiGenerator.Line.Eval(x));
Gizmos.DrawLine(start, point);
start = point;
}
}
if (LocationGenerator == null) return;
if (debug.displayLocationCells) if (debug.displayLocationCells)
{ {
foreach (var location in LocationGenerator.Sites.Vertices.Where(l => l.Location != null && l.Location != _locations[0])) var cells = Map.Sites.Vertices
{ .Where(s => s.Metadata.HasProperty(LocationPass.SiteLocationProperty))
Gizmos.color = location.Location.Type.color; .Where(s => s.Metadata.GetProperty<Location>(LocationPass.SiteLocationProperty).Type.name != "Ocean");
Gizmos.DrawSphere(location.Point.ToVector3(), 2);
} foreach (var site in cells)
}
if (debug.displayLocations && _locationGraph != null)
{
DisplayGraphEdges(_locationGraph.Morph(a => a.Item1));
}
if (debug.displayLocationPoints)
{
foreach (var location in _locations.Skip(1))
{ {
var location = site.Metadata.GetProperty<Location>(LocationPass.SiteLocationProperty);
Gizmos.color = location.Type.color; Gizmos.color = location.Type.color;
foreach (var point in location.BoundaryPoints) Gizmos.DrawSphere(site.Center.ToVector3(), 2);
{
var v = VoronoiGenerator.Voronoi.Vertices[point].ToVector3();
Gizmos.DrawSphere(v, 1);
if (debug.displayLabels) Handles.Label(v + Vector3.right, $"{point} at {v.x:F2}, {v.y:f2}");
}
} }
} }
//
// if (debug.displayLocations && _locationGraph != null)
// {
// DisplayGraphEdges(_locationGraph.Morph(a => a.Item1));
// }
//
// if (debug.displayLocationPoints)
// {
// foreach (var location in _locations.Skip(1))
// {
// Gizmos.color = location.Type.color;
// foreach (var point in location.BoundaryPoints)
// {
// var v = VoronoiGenerator.Voronoi.Vertices[point].ToVector3();
// Gizmos.DrawSphere(v, 1);
// if (debug.displayLabels) Handles.Label(v + Vector3.right, $"{point} at {v.x:F2}, {v.y:f2}");
// }
// }
// }
//
if (debug.displayLocationEdges) if (debug.displayLocationEdges)
{ {
foreach (var location in _locations.Skip(1)) foreach (var location in Map.Metadata.GetProperty<Graph<Location>>(LocationPass.MapLocationsProperty).Vertices)
{ {
Gizmos.color = location.Type.color; Gizmos.color = location.Type.color;
foreach (var (a, b) in location.BoundaryEdges) foreach (var (a, b) in location.BoundaryEdges)
{ {
Gizmos.DrawLine(VoronoiGenerator.Voronoi.Vertices[a].ToVector3(), VoronoiGenerator.Voronoi.Vertices[b].ToVector3()); Gizmos.DrawLine(BoundariesGraph[a].ToVector3(), BoundariesGraph[b].ToVector3());
} }
} }
} }
} }
public void Rewind(float y)
{
while (_voronoiGenerator.Line.Directrix < y && !_voronoiGenerator.Done)
{
_voronoiGenerator.Step();
}
}
private void DisplayGraphVertices(Graph<Point> graph)
{
var vertices = graph.Vertices.Select(p => p.ToVector3());
var offset = Vector3.right;
foreach (var (v, i) in vertices.Select((x, i) => (x, i)))
{
Gizmos.DrawSphere(v, 1);
if (debug.displayLabels) Handles.Label(v + offset, $"{i} at {v.x:F2}, {v.y:f2}");
}
}
private void DisplayGraphEdges(Graph<Point> graph)
{
var edges = graph.Edges
.Select(edge => (graph.Vertices[edge.Item1], graph.Vertices[edge.Item2]))
.Select(edge => (edge.Item1.ToVector3(), edge.Item2.ToVector3()));
foreach (var (s, e) in edges) Gizmos.DrawLine(s, e);
}
private void RecalculateLocationGraph()
{
_locationGraph = LocationGenerator.Result.Morph(location => (location.Center, location));
}
} }
} }

View File

@ -1,11 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Assets.AnnotationPass;
using Assets.Common; using Assets.Common;
using Assets.GridGenerator;
namespace Assets namespace Assets
{ {
public class MapGenerator class MapGenerator
{ {
private IGridGenerator _gridGenerator; private IGridGenerator _gridGenerator;
private ICollection<IAnnotationPass> _annotationPasses = new List<IAnnotationPass>(); private ICollection<IAnnotationPass> _annotationPasses = new List<IAnnotationPass>();

View File

@ -6,192 +6,192 @@ using Random = UnityEngine.Random;
namespace Assets namespace Assets
{ {
[RequireComponent(typeof(MeshFilter))] // [RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))] // [RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(LandmassGenerator))] // [RequireComponent(typeof(LandmassGenerator))]
public class MapRenderer : MonoBehaviour public class MapRenderer : MonoBehaviour
{ {
public float UVScale = 1.0f; // public float UVScale = 1.0f;
//
private List<Vector3> _vertices; // private List<Vector3> _vertices;
private List<Vector2> _uv; // private List<Vector2> _uv;
private List<Vector3> _normals; // private List<Vector3> _normals;
private List<Color> _colors; // private List<Color> _colors;
private List<int> _triangles; // private List<int> _triangles;
//
private List<List<Point>> _edges; // private List<List<Point>> _edges;
//
public void Generate() // public void Generate()
{ // {
var graph = GetComponent<LandmassGenerator>(); // var graph = GetComponent<LandmassGenerator>();
//
graph.Reset(); // graph.Reset();
graph.Generate(); // graph.Generate();
//
var points = graph.VoronoiGenerator.Voronoi.Vertices; // var points = graph.VoronoiGenerator.Voronoi.Vertices;
//
_vertices = new List<Vector3>(); // _vertices = new List<Vector3>();
_normals = new List<Vector3>(); // _normals = new List<Vector3>();
_uv = new List<Vector2>(); // _uv = new List<Vector2>();
_colors = new List<Color>(); // _colors = new List<Color>();
_triangles = new List<int>(); // _triangles = new List<int>();
//
foreach (var location in graph.LocationGenerator.Result.Vertices.Skip(1)) // foreach (var location in graph.LocationGenerator.Result.Vertices.Skip(1))
{ // {
GenerateLocationEdges(location, points); // GenerateLocationEdges(location, points);
GenerateLocationMeshAlt(location, points); // GenerateLocationMeshAlt(location, points);
GenerateLocationWall(location, points); // GenerateLocationWall(location, points);
} // }
//
Mesh mesh = new Mesh(); // Mesh mesh = new Mesh();
mesh.vertices = _vertices.ToArray(); // mesh.vertices = _vertices.ToArray();
mesh.uv = _uv.ToArray(); // mesh.uv = _uv.ToArray();
mesh.normals = _normals.ToArray(); // mesh.normals = _normals.ToArray();
mesh.triangles = _triangles.ToArray(); // mesh.triangles = _triangles.ToArray();
mesh.colors = _colors.ToArray(); // mesh.colors = _colors.ToArray();
//
GetComponent<MeshFilter>().sharedMesh = mesh; // GetComponent<MeshFilter>().sharedMesh = mesh;
//
} // }
//
private void GenerateLocationEdges(Location location, List<Point> points) // private void GenerateLocationEdges(Location location, List<Point> points)
{ // {
foreach (var (a, b) in location.BoundaryEdges.Select(x => (points[x.Item1], points[x.Item2]))) // foreach (var (a, b) in location.BoundaryEdges.Select(x => (points[x.Item1], points[x.Item2])))
location.DetailedEdge.AddRange(this.SplitEdge(a, b, 3)); // location.DetailedEdge.AddRange(this.SplitEdge(a, b, 3));
} // }
//
private IEnumerable<Point> SplitEdge(Point a, Point b, int count) // private IEnumerable<Point> SplitEdge(Point a, Point b, int count)
{ // {
// var direction = ; //// var direction = ;
var magnitude = Point.Dist(a, b); // var magnitude = Point.Dist(a, b);
var d = new Point(-(b.y - a.y) / magnitude, (b.x - a.x) / magnitude); // var d = new Point(-(b.y - a.y) / magnitude, (b.x - a.x) / magnitude);
//
magnitude *= Random.value * 0.4 - 0.2; // magnitude *= Random.value * 0.4 - 0.2;
//
Point c = new Point((a.x + b.x) / 2.0 + d.x * magnitude, (a.y + b.y) / 2.0 + d.y * magnitude); // Point c = new Point((a.x + b.x) / 2.0 + d.x * magnitude, (a.y + b.y) / 2.0 + d.y * magnitude);
//
if (count > 0) // if (count > 0)
{ // {
foreach (var p in SplitEdge(a, c, count - 1)) // foreach (var p in SplitEdge(a, c, count - 1))
yield return p; // yield return p;
//
yield return c; // yield return c;
//
foreach (var p in SplitEdge(c, b, count - 1)) // foreach (var p in SplitEdge(c, b, count - 1))
yield return p; // yield return p;
} // }
else // else
{ // {
yield return c; // yield return c;
} // }
} // }
//
private void GenerateLocationMeshAlt(Location location, IList<Point> points) // private void GenerateLocationMeshAlt(Location location, IList<Point> points)
{ // {
var start = _vertices.Count; // var start = _vertices.Count;
var count = location.DetailedEdge.Count; // var count = location.DetailedEdge.Count;
//
_vertices.AddRange(location.DetailedEdge.Select(p => new Vector3((float)p.x, location.Type.height, (float)p.y))); // _vertices.AddRange(location.DetailedEdge.Select(p => new Vector3((float)p.x, location.Type.height, (float)p.y)));
_normals.AddRange(Enumerable.Repeat(Vector3.up, count)); // _normals.AddRange(Enumerable.Repeat(Vector3.up, count));
_colors.AddRange(Enumerable.Repeat(Color.blue, count)); // _colors.AddRange(Enumerable.Repeat(Color.blue, count));
_uv.AddRange(location.DetailedEdge.Select(p => new Vector2((float)p.x, (float)p.y) / UVScale)); // _uv.AddRange(location.DetailedEdge.Select(p => new Vector2((float)p.x, (float)p.y) / UVScale));
//
var triangulator = new Triangulator(location.DetailedEdge.Select(v => new Vector2((float)v.x, (float)v.y)).ToArray()); // var triangulator = new Triangulator(location.DetailedEdge.Select(v => new Vector2((float)v.x, (float)v.y)).ToArray());
_triangles.AddRange(triangulator.Triangulate().Select(x => x + start)); // _triangles.AddRange(triangulator.Triangulate().Select(x => x + start));
} // }
//
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 => 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;
//
foreach (var i in vertices) // foreach (var i in vertices)
{ // {
var isEdge = location.BoundaryPoints.Contains(i); // var isEdge = location.BoundaryPoints.Contains(i);
//
var vertex = points[i]; // var vertex = points[i];
var v = PointToVector(location, vertex); // var v = PointToVector(location, vertex);
//
_vertices.Add(v); // _vertices.Add(v);
_normals.Add(Vector3.up); // _normals.Add(Vector3.up);
_uv.Add(new Vector2(v.x, v.z) / UVScale); // _uv.Add(new Vector2(v.x, v.z) / UVScale);
_colors.Add(isEdge ? Color.red : Color.blue); // _colors.Add(isEdge ? Color.red : Color.blue);
} // }
//
int end = _vertices.Count; // int end = _vertices.Count;
//
var triangulator = new Triangulator(_vertices.Skip(start).Take(end - start).Select(v => new Vector2(v.x, v.z)).ToArray()); // var triangulator = new Triangulator(_vertices.Skip(start).Take(end - start).Select(v => new Vector2(v.x, v.z)).ToArray());
_triangles.AddRange(triangulator.Triangulate().Select(x => x + start)); // _triangles.AddRange(triangulator.Triangulate().Select(x => x + start));
//
} // }
} // }
//
private static Vector3 PointToVector(Location location, Point vertex) // private static Vector3 PointToVector(Location location, Point vertex)
{ // {
return new Vector3((float)vertex.x, location.Type.height + Mathf.PerlinNoise((float)vertex.x, (float)vertex.y) / 4, (float)vertex.y); // return new Vector3((float)vertex.x, location.Type.height + Mathf.PerlinNoise((float)vertex.x, (float)vertex.y) / 4, (float)vertex.y);
} // }
//
private void GenerateLocationWall(Location location, IList<Point> points) // private void GenerateLocationWall(Location location, IList<Point> points)
{ // {
var length = 0.0; // var length = 0.0;
//
var collection = location.DetailedEdge.Append(location.DetailedEdge.First()); // var collection = location.DetailedEdge.Append(location.DetailedEdge.First());
var edges = collection.Zip(collection.Skip(1), (a, b) => (a, b)).Zip(collection.Skip(2), (tuple, c) => (tuple.a, tuple.b, c)); // var edges = collection.Zip(collection.Skip(1), (a, b) => (a, b)).Zip(collection.Skip(2), (tuple, c) => (tuple.a, tuple.b, c));
//
foreach (var (p, c, n) in edges) // foreach (var (p, c, n) in edges)
{ // {
int start = _vertices.Count; // int start = _vertices.Count;
var dist = Point.Dist(p, c); // var dist = Point.Dist(p, c);
//
var veca = PointToVector(location, p); // var veca = PointToVector(location, p);
var vecb = PointToVector(location, c); // var vecb = PointToVector(location, c);
//
_vertices.Add(veca); // _vertices.Add(veca);
_vertices.Add(new Vector3((float)p.x, -10,(float)p.y)); // _vertices.Add(new Vector3((float)p.x, -10,(float)p.y));
_vertices.Add(vecb); // _vertices.Add(vecb);
_vertices.Add(new Vector3((float)c.x, -10,(float)c.y)); // _vertices.Add(new Vector3((float)c.x, -10,(float)c.y));
//
var normal = new Vector3((float)(p.x + n.x - c.x) / 2.0f, 0, (float)(p.y + n.y - c.y) / 2.0f).normalized; // var normal = new Vector3((float)(p.x + n.x - c.x) / 2.0f, 0, (float)(p.y + n.y - c.y) / 2.0f).normalized;
//
_normals.AddRange(Enumerable.Repeat(normal, 4)); // _normals.AddRange(Enumerable.Repeat(normal, 4));
_colors.AddRange(Enumerable.Repeat(Color.red, 4)); // _colors.AddRange(Enumerable.Repeat(Color.red, 4));
//
_triangles.AddRange(new [] // _triangles.AddRange(new []
{ // {
start, start + 2, start + 1, // start, start + 2, start + 1,
start + 1, start + 2, start + 3 // start + 1, start + 2, start + 3
}); // });
//
_uv.AddRange(new [] // _uv.AddRange(new []
{ // {
new Vector2((float)length, veca.y) / UVScale, // new Vector2((float)length, veca.y) / UVScale,
new Vector2((float)length, -10) / UVScale, // new Vector2((float)length, -10) / UVScale,
new Vector2((float)(length + dist), vecb.y) / UVScale, // new Vector2((float)(length + dist), vecb.y) / UVScale,
new Vector2((float)(length + dist), -10) / UVScale, // new Vector2((float)(length + dist), -10) / UVScale,
}); // });
//
length += dist; // length += dist;
} // }
} // }
//
private void OnDrawGizmos() // private void OnDrawGizmos()
{ // {
var graph = GetComponent<LandmassGenerator>(); // var graph = GetComponent<LandmassGenerator>();
//
if (graph?.LocationGenerator?.Result == null) return; // if (graph?.LocationGenerator?.Result == null) return;
//
foreach (var location in graph.LocationGenerator.Result.Vertices.Skip(1)) // foreach (var location in graph.LocationGenerator.Result.Vertices.Skip(1))
{ // {
var boundary = location.DetailedEdge; // var boundary = location.DetailedEdge;
foreach (var (a, b) in boundary.Zip(boundary.Skip(1).Append(boundary.First()), (a, b) => (a, b))) // foreach (var (a, b) in boundary.Zip(boundary.Skip(1).Append(boundary.First()), (a, b) => (a, b)))
{ // {
var va = new Vector3((float) a.x, location.Type.height, (float) a.y); // var va = new Vector3((float) a.x, location.Type.height, (float) a.y);
var vb = new Vector3((float) b.x, location.Type.height, (float) b.y); // var vb = new Vector3((float) b.x, location.Type.height, (float) b.y);
//
Gizmos.DrawLine(va, vb); // Gizmos.DrawLine(va, vb);
} // }
} // }
} // }
} }
} }

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 81821064023a48f4affdf44568a66557
timeCreated: 1573390973

View File

@ -1,7 +1,7 @@
using Assets.Common; using Assets.Common;
using UnityEngine; using UnityEngine;
namespace Assets namespace Assets.RenderPass
{ {
public interface IRenderPass public interface IRenderPass
{ {

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d1235a1f76af47e6b8686c3c359e24da
timeCreated: 1573399226

View File

@ -0,0 +1,43 @@
using System.Linq;
using Assets.Common;
using UnityEditor;
using UnityEngine;
namespace Assets.Utils
{
public static class DebugUtils
{
public delegate Point PointExtractor<T>(T thing);
public static void DisplayGraphVertices<T>(Graph<T> graph, PointExtractor<T> extractor, bool displayLabels = true)
{
var vertices = graph.Vertices.Select(p => extractor(p).ToVector3());
var offset = Vector3.right;
foreach (var (v, i) in vertices.Select((x, i) => (x, i)))
{
Gizmos.DrawSphere(v, 1);
if (displayLabels) Handles.Label(v + offset, $"{i} at {v.x:F2}, {v.y:f2}");
}
}
public static void DisplayGraphVertices(Graph<Point> graph, bool displayLabels = true)
{
DisplayGraphVertices(graph, l => l, displayLabels);
}
public static void DisplayGraphEdges<T>(Graph<T> graph, PointExtractor<T> extractor)
{
var edges = graph.Edges
.Select(edge => (graph.Vertices[edge.Item1], graph.Vertices[edge.Item2]))
.Select(edge => (extractor(edge.Item1).ToVector3(), extractor(edge.Item2).ToVector3()));
foreach (var (s, e) in edges) Gizmos.DrawLine(s, e);
}
public static void DisplayGraphEdges(Graph<Point> graph)
{
DisplayGraphEdges(graph, l => l);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2248a5e781874095a731dffefaca79c1
timeCreated: 1573399272