dodano strefy wpływów miast
This commit is contained in:
parent
4facf6c3ba
commit
476411f6e7
@ -22,7 +22,6 @@ namespace Assets.AnnotationPass
|
|||||||
|
|
||||||
public double MinimumRoadLength { get; set; } = 2;
|
public double MinimumRoadLength { get; set; } = 2;
|
||||||
public double BusinessCityFields { get; set; } = 0.3;
|
public double BusinessCityFields { get; set; } = 0.3;
|
||||||
public double LivingCityFields { get; set; } = 0.7;
|
|
||||||
|
|
||||||
public CityFieldsPass(Random random)
|
public CityFieldsPass(Random random)
|
||||||
{
|
{
|
||||||
@ -144,20 +143,20 @@ namespace Assets.AnnotationPass
|
|||||||
// add field types
|
// add field types
|
||||||
var orderedFields = city.Fields.OrderBy(cf => Point.Dist(cf.Center, city.Center)).ToList();
|
var orderedFields = city.Fields.OrderBy(cf => Point.Dist(cf.Center, city.Center)).ToList();
|
||||||
|
|
||||||
orderedFields.First().cityFieldType = CityFieldTypes.MainSquare;
|
orderedFields.First().Type = FieldType.MainSquare;
|
||||||
|
|
||||||
|
|
||||||
int businessCityFields = (int)Math.Ceiling((BusinessCityFields*orderedFields.Count()));
|
int businessCityFields = (int)Math.Ceiling((BusinessCityFields*orderedFields.Count()));
|
||||||
|
|
||||||
foreach (var cityField in orderedFields.Skip(1).Take(businessCityFields))
|
foreach (var cityField in orderedFields.Skip(1).Take(businessCityFields))
|
||||||
{
|
{
|
||||||
cityField.cityFieldType = CityFieldTypes.Business;
|
cityField.Type = FieldType.Business;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
foreach (var cityField in orderedFields.Skip(1+businessCityFields))
|
foreach (var cityField in orderedFields.Skip(1+businessCityFields))
|
||||||
{
|
{
|
||||||
cityField.cityFieldType = CityFieldTypes.Living;
|
cityField.Type = FieldType.Living;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,12 @@ namespace Assets.AnnotationPass
|
|||||||
{
|
{
|
||||||
public const string CitiesProperty = "Cities";
|
public const string CitiesProperty = "Cities";
|
||||||
public const string CityProperty = "City";
|
public const string CityProperty = "City";
|
||||||
|
public int MaxCitiesCount { get; set; } = 20;
|
||||||
|
public int MaxPlacementTries { get; set; } = 30;
|
||||||
|
public float RangeOfInfluence { get; set; } = .5f;
|
||||||
|
public float CitiesSize { get; set; } = .5f;
|
||||||
|
|
||||||
|
|
||||||
private Graph<Location> _locationGraph;
|
private Graph<Location> _locationGraph;
|
||||||
private Graph<MapSite> _basicGraph;
|
private Graph<MapSite> _basicGraph;
|
||||||
private Random _random;
|
private Random _random;
|
||||||
@ -20,15 +25,10 @@ namespace Assets.AnnotationPass
|
|||||||
_random = random ?? new Random();
|
_random = random ?? new Random();
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<int> LocateCities()
|
|
||||||
{
|
|
||||||
return ChoosePoints(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
City CreateCity(int vertex, int size)
|
City CreateCity(int vertex, int size)
|
||||||
{
|
{
|
||||||
City newCity = new City();
|
City newCity = new City();
|
||||||
|
|
||||||
var site = _basicGraph.Vertices[vertex];
|
var site = _basicGraph.Vertices[vertex];
|
||||||
newCity.Center = site.Center.Clone() as Point;
|
newCity.Center = site.Center.Clone() as Point;
|
||||||
site.Tags.Add("City.Center");
|
site.Tags.Add("City.Center");
|
||||||
@ -49,35 +49,47 @@ namespace Assets.AnnotationPass
|
|||||||
s.Metadata.SetProperty(CityProperty, newCity);
|
s.Metadata.SetProperty(CityProperty, newCity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newCity.RangeOfInfluence = GetCityRangeOfInfluence(newCity);
|
||||||
return newCity;
|
return newCity;
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<int> ChoosePoints(int number)
|
List<City> CreateCities()
|
||||||
{
|
{
|
||||||
|
List<City> cities = new List<City>();
|
||||||
var vertices = new List<int>();
|
var vertices = new List<int>();
|
||||||
|
|
||||||
for (int i = 0; i < number; i++)
|
int guard = MaxPlacementTries;
|
||||||
|
int createdCitiesCount = 0;
|
||||||
|
|
||||||
|
while (createdCitiesCount < MaxCitiesCount && guard-- > 0)
|
||||||
{
|
{
|
||||||
var randomLocation = _locationGraph.Vertices[_random.Next(1, _locationGraph.Vertices.Count())];
|
var randomLocation = _locationGraph.Vertices.Skip(1).RandomElement(_random);
|
||||||
var count = randomLocation.Sites.Count();
|
var randomSite = randomLocation.Sites.RandomElement(_random);
|
||||||
var randomPoint = randomLocation.Sites[_random.Next(0, count)];
|
|
||||||
vertices.Add(randomPoint.Index);
|
if (cities.Any(c => Point.Dist(PointUtils.Mean(c.Sites.Select(s => s.Center)), randomSite.Center) < c.RangeOfInfluence))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cities.Add(CreateCity(randomSite.Index, (int)Math.Ceiling(CitiesSize * _random.Next(0, 30))));
|
||||||
|
guard = MaxPlacementTries;
|
||||||
|
createdCitiesCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return vertices;
|
return cities;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetCityRangeOfInfluence(City city)
|
||||||
|
{
|
||||||
|
return RangeOfInfluence*city.Sites.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Annotate(Map map)
|
public void Annotate(Map map)
|
||||||
{
|
{
|
||||||
_basicGraph = map.Sites.Clone() as Graph<MapSite>;
|
_basicGraph = map.Sites.Clone() as Graph<MapSite>;
|
||||||
_locationGraph = map.Metadata.GetProperty<Graph<Location>>(LandmassPass.MapLocationsProperty);
|
_locationGraph = map.Metadata.GetProperty<Graph<Location>>(LandmassPass.MapLocationsProperty);
|
||||||
|
|
||||||
var cities = new List<City>();
|
var cities = CreateCities();
|
||||||
var locations = LocateCities();
|
|
||||||
|
|
||||||
foreach (var index in locations)
|
|
||||||
cities.Add(CreateCity(index, _random.Next(0, 10)));
|
|
||||||
|
|
||||||
map.Metadata.SetProperty(CitiesProperty, cities);
|
map.Metadata.SetProperty(CitiesProperty, cities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ namespace Assets.Cities
|
|||||||
|
|
||||||
public List<(int, int)> Edges = new List<(int, int)>();
|
public List<(int, int)> Edges = new List<(int, int)>();
|
||||||
public Point Center { get; set; }
|
public Point Center { get; set; }
|
||||||
|
public float RangeOfInfluence { get; set; } = 0;
|
||||||
|
|
||||||
public City()
|
public City()
|
||||||
{
|
{
|
||||||
@ -25,6 +26,7 @@ namespace Assets.Cities
|
|||||||
{
|
{
|
||||||
Sites = sites;
|
Sites = sites;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void AddSite(MapSite site)
|
public void AddSite(MapSite site)
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@ using Assets.Common;
|
|||||||
|
|
||||||
namespace Assets.Cities
|
namespace Assets.Cities
|
||||||
{
|
{
|
||||||
public enum CityFieldTypes
|
public enum FieldType
|
||||||
{
|
{
|
||||||
MainSquare,
|
MainSquare,
|
||||||
Business,
|
Business,
|
||||||
@ -13,7 +13,7 @@ namespace Assets.Cities
|
|||||||
public class CityField
|
public class CityField
|
||||||
{
|
{
|
||||||
public IList<Point> Boundary { get; set; } = new List<Point>();
|
public IList<Point> Boundary { get; set; } = new List<Point>();
|
||||||
public CityFieldTypes cityFieldType { get; set; }
|
public FieldType Type { get; set; }
|
||||||
public Point Center { get; set; }
|
public Point Center { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -20,7 +20,7 @@ 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 displayVertices = true;
|
public bool displayVertices = true;
|
||||||
@ -37,6 +37,7 @@ namespace Assets
|
|||||||
public bool displayCityFields = true;
|
public bool displayCityFields = true;
|
||||||
|
|
||||||
[NonSerialized] public float generationTime = 0.0f;
|
[NonSerialized] public float generationTime = 0.0f;
|
||||||
|
public bool displayRangeOfInfluence = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@ -52,22 +53,30 @@ namespace Assets
|
|||||||
{
|
{
|
||||||
[NonSerialized] public Map Map;
|
[NonSerialized] public Map Map;
|
||||||
[NonSerialized] public Thread GenerationThread;
|
[NonSerialized] public Thread GenerationThread;
|
||||||
|
|
||||||
public GraphGeneratorDebug debug;
|
public GraphGeneratorDebug debug;
|
||||||
|
|
||||||
public Vector2 size = new Vector2();
|
public Vector2 size = new Vector2();
|
||||||
public List<LocationType> types = new List<LocationType>();
|
public List<LocationType> types = new List<LocationType>();
|
||||||
|
|
||||||
[Range(0f, 360f)]
|
[Range(0f, 360f)]
|
||||||
public float minimumRoadAngle = 30f;
|
public float minimumRoadAngle = 30f;
|
||||||
|
[Range(0f, 1f)]
|
||||||
|
public float businessCityFields = 0.3f;
|
||||||
[Range(0f, 4f)]
|
[Range(0f, 4f)]
|
||||||
public float minimumNudgeDistance = 0.5f;
|
public float minimumNudgeDistance = 0.5f;
|
||||||
[Range(0f, 4f)]
|
[Range(0f, 4f)]
|
||||||
public float maximumNudgeDistance = 1f;
|
public float maximumNudgeDistance = 1f;
|
||||||
[Range(0f, 4f)]
|
[Range(0f, 4f)]
|
||||||
public float minimumRoadLength = 1f;
|
public float minimumRoadLength = 1f;
|
||||||
|
public float rangeOfInfluence = .5f;
|
||||||
|
[Range(0f, 1f)]
|
||||||
|
public float citiesSize = .5f;
|
||||||
|
|
||||||
|
|
||||||
|
[Range(0, 50)]
|
||||||
|
public int citiesCount = 20;
|
||||||
|
|
||||||
[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;
|
||||||
@ -80,17 +89,17 @@ namespace Assets
|
|||||||
{
|
{
|
||||||
GenerationThread?.Abort();
|
GenerationThread?.Abort();
|
||||||
GenerationThread = new Thread(() =>
|
GenerationThread = new Thread(() =>
|
||||||
{
|
{
|
||||||
var generator = CreateMapGenerator();
|
var generator = CreateMapGenerator();
|
||||||
var result = generator.Generate(size.x, size.y);
|
var result = generator.Generate(size.x, size.y);
|
||||||
|
|
||||||
lock (GetType())
|
lock (GetType())
|
||||||
{
|
{
|
||||||
Map = result;
|
Map = result;
|
||||||
onDone(result);
|
onDone(result);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
GenerationThread.Start();
|
GenerationThread.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,13 +118,19 @@ namespace Assets
|
|||||||
var generator = new MapGenerator(new VoronoiGridGenerator(seed, new PoissonDiskSampler(radius) { Generator = new Random(seed) }));
|
var generator = new MapGenerator(new VoronoiGridGenerator(seed, new PoissonDiskSampler(radius) { Generator = new Random(seed) }));
|
||||||
|
|
||||||
generator.AddAnnotationPass(new LandmassPass(types.Prepend(new LocationType { name = "Ocean", height = -1 }).Select(t => new Location { Type = t }), new Random(seed)));
|
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 LocateCitiesPass(new Random(seed))
|
||||||
|
{
|
||||||
|
MaxCitiesCount = citiesCount,
|
||||||
|
RangeOfInfluence = rangeOfInfluence,
|
||||||
|
CitiesSize = citiesSize
|
||||||
|
});
|
||||||
generator.AddAnnotationPass(new CityFieldsPass(new Random(seed))
|
generator.AddAnnotationPass(new CityFieldsPass(new Random(seed))
|
||||||
{
|
{
|
||||||
MinimumAngle = Mathf.Deg2Rad * minimumRoadAngle,
|
MinimumAngle = Mathf.Deg2Rad * minimumRoadAngle,
|
||||||
MaxNudgeDistance = maximumNudgeDistance,
|
MaxNudgeDistance = maximumNudgeDistance,
|
||||||
MinNudgeDistance = minimumNudgeDistance,
|
MinNudgeDistance = minimumNudgeDistance,
|
||||||
MinimumRoadLength = minimumRoadLength
|
MinimumRoadLength = minimumRoadLength,
|
||||||
|
BusinessCityFields = businessCityFields
|
||||||
});
|
});
|
||||||
|
|
||||||
return generator;
|
return generator;
|
||||||
@ -125,7 +140,7 @@ namespace Assets
|
|||||||
{
|
{
|
||||||
GenerationThread?.Abort();
|
GenerationThread?.Abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisplayGraphCities(IEnumerable<City> cities)
|
private void DisplayGraphCities(IEnumerable<City> cities)
|
||||||
{
|
{
|
||||||
foreach (City city in cities)
|
foreach (City city in cities)
|
||||||
@ -143,7 +158,7 @@ namespace Assets
|
|||||||
void OnDrawGizmos()
|
void OnDrawGizmos()
|
||||||
{
|
{
|
||||||
if (!debug.enabled || Map == null) return;
|
if (!debug.enabled || Map == null) return;
|
||||||
|
|
||||||
if (debug.displayBoundary)
|
if (debug.displayBoundary)
|
||||||
{
|
{
|
||||||
Gizmos.color = Color.gray;
|
Gizmos.color = Color.gray;
|
||||||
@ -153,7 +168,7 @@ namespace Assets
|
|||||||
Gizmos.DrawLine(new Vector3(size.x, 0, size.y), new Vector3(size.x, 0, 0));
|
Gizmos.DrawLine(new Vector3(size.x, 0, size.y), new Vector3(size.x, 0, 0));
|
||||||
Gizmos.DrawLine(new Vector3(size.x, 0, size.y), new Vector3(0, 0, size.y));
|
Gizmos.DrawLine(new Vector3(size.x, 0, size.y), new Vector3(0, 0, size.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug.displayPoints)
|
if (debug.displayPoints)
|
||||||
{
|
{
|
||||||
Gizmos.color = Color.white;
|
Gizmos.color = Color.white;
|
||||||
@ -177,47 +192,47 @@ namespace Assets
|
|||||||
Gizmos.color = Color.white;
|
Gizmos.color = Color.white;
|
||||||
DebugUtils.DisplayGraphEdges(Map.Boundaries);
|
DebugUtils.DisplayGraphEdges(Map.Boundaries);
|
||||||
}
|
}
|
||||||
|
|
||||||
Gizmos.color = Color.blue;
|
Gizmos.color = Color.blue;
|
||||||
|
|
||||||
if (!Map.Metadata.HasProperty(LandmassPass.MapLocationsProperty)) return;
|
if (!Map.Metadata.HasProperty(LandmassPass.MapLocationsProperty)) return;
|
||||||
|
|
||||||
var locations = Map.Metadata.GetProperty<Graph<Location>>(LandmassPass.MapLocationsProperty);
|
var locations = Map.Metadata.GetProperty<Graph<Location>>(LandmassPass.MapLocationsProperty);
|
||||||
|
|
||||||
if (debug.displayLocationCells)
|
if (debug.displayLocationCells)
|
||||||
{
|
{
|
||||||
var cells = Map.Sites.Vertices
|
var cells = Map.Sites.Vertices
|
||||||
.Where(s => s.Metadata.HasProperty(LandmassPass.SiteLocationProperty))
|
.Where(s => s.Metadata.HasProperty(LandmassPass.SiteLocationProperty))
|
||||||
.Where(s => s.Metadata.GetProperty<Location>(LandmassPass.SiteLocationProperty).Type.name != "Ocean");
|
.Where(s => s.Metadata.GetProperty<Location>(LandmassPass.SiteLocationProperty).Type.name != "Ocean");
|
||||||
|
|
||||||
foreach (var site in cells)
|
foreach (var site in cells)
|
||||||
{
|
{
|
||||||
var location = site.Metadata.GetProperty<Location>(LandmassPass.SiteLocationProperty);
|
var location = site.Metadata.GetProperty<Location>(LandmassPass.SiteLocationProperty);
|
||||||
|
|
||||||
Gizmos.color = location.Type.color;
|
Gizmos.color = location.Type.color;
|
||||||
Gizmos.DrawSphere(site.Center.ToVector3(), 2);
|
Gizmos.DrawSphere(site.Center.ToVector3(), 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// if (debug.displayLocations && _locationGraph != null)
|
// if (debug.displayLocations && _locationGraph != null)
|
||||||
// {
|
// {
|
||||||
// DisplayGraphEdges(_locationGraph.Morph(a => a.Item1));
|
// DisplayGraphEdges(_locationGraph.Morph(a => a.Item1));
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// if (debug.displayLocationPoints)
|
// if (debug.displayLocationPoints)
|
||||||
// {
|
// {
|
||||||
// foreach (var location in _locations.Skip(1))
|
// foreach (var location in _locations.Skip(1))
|
||||||
// {
|
// {
|
||||||
// Gizmos.color = location.Type.color;
|
// Gizmos.color = location.Type.color;
|
||||||
// foreach (var point in location.BoundaryPoints)
|
// foreach (var point in location.BoundaryPoints)
|
||||||
// {
|
// {
|
||||||
// var v = VoronoiGenerator.Voronoi.Vertices[point].ToVector3();
|
// var v = VoronoiGenerator.Voronoi.Vertices[point].ToVector3();
|
||||||
// Gizmos.DrawSphere(v, 1);
|
// Gizmos.DrawSphere(v, 1);
|
||||||
// if (debug.displayLabels) Handles.Label(v + Vector3.right, $"{point} at {v.x:F2}, {v.y:f2}");
|
// if (debug.displayLabels) Handles.Label(v + Vector3.right, $"{point} at {v.x:F2}, {v.y:f2}");
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (debug.displayLocationEdges)
|
if (debug.displayLocationEdges)
|
||||||
{
|
{
|
||||||
@ -230,15 +245,15 @@ namespace Assets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug.displayCities && Map.Metadata.HasProperty(LocateCitiesPass.CitiesProperty))
|
if (debug.displayCities && Map.Metadata.HasProperty(LocateCitiesPass.CitiesProperty))
|
||||||
{
|
{
|
||||||
Gizmos.color = Color.magenta;
|
Gizmos.color = Color.magenta;
|
||||||
DisplayGraphCities(Map.Metadata.GetProperty<IEnumerable<City>>(LocateCitiesPass.CitiesProperty));
|
DisplayGraphCities(Map.Metadata.GetProperty<IEnumerable<City>>(LocateCitiesPass.CitiesProperty));
|
||||||
}
|
}
|
||||||
|
|
||||||
var cities = Map.Metadata.GetProperty<List<City>>(LocateCitiesPass.CitiesProperty);
|
var cities = Map.Metadata.GetProperty<List<City>>(LocateCitiesPass.CitiesProperty);
|
||||||
|
|
||||||
if (debug.displayFieldBoundaries)
|
if (debug.displayFieldBoundaries)
|
||||||
{
|
{
|
||||||
Gizmos.color = Color.white;
|
Gizmos.color = Color.white;
|
||||||
@ -261,19 +276,44 @@ namespace Assets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (debug.displayRangeOfInfluence)
|
||||||
|
{
|
||||||
|
foreach (var city in cities)
|
||||||
|
{
|
||||||
|
Gizmos.color = Color.yellow;
|
||||||
|
Gizmos.DrawWireSphere(PointUtils.Mean(city.Sites.Select(s => s.Center)).ToVector3(), city.RangeOfInfluence);
|
||||||
|
Gizmos.DrawSphere(PointUtils.Mean(city.Sites.Select(s => s.Center)).ToVector3(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (debug.displayCityFields)
|
if (debug.displayCityFields)
|
||||||
{
|
{
|
||||||
Gizmos.color = Color.green;
|
Gizmos.color = Color.blue;
|
||||||
|
|
||||||
foreach (var city in cities)
|
foreach (var city in cities)
|
||||||
{
|
{
|
||||||
foreach (var field in city.Fields)
|
foreach (var field in city.Fields)
|
||||||
{
|
{
|
||||||
|
switch (field.Type)
|
||||||
|
{
|
||||||
|
case FieldType.Business:
|
||||||
|
Gizmos.color = Color.green;
|
||||||
|
break;
|
||||||
|
case FieldType.Living:
|
||||||
|
Gizmos.color = Color.yellow;
|
||||||
|
break;
|
||||||
|
case FieldType.MainSquare:
|
||||||
|
Gizmos.color = Color.red;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Gizmos.color = Color.blue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
foreach (var (a, b) in field.Boundary.RotateRight().Zip(field.Boundary, (a, b) => (a, b)))
|
foreach (var (a, b) in field.Boundary.RotateRight().Zip(field.Boundary, (a, b) => (a, b)))
|
||||||
Gizmos.DrawLine(a.ToVector3(), b.ToVector3());
|
Gizmos.DrawLine(a.ToVector3(), b.ToVector3());
|
||||||
|
|
||||||
foreach (var tuple in field.Boundary.Zip(PointUtils.CalculateNormals(field.Boundary), (a, b) => (Point: a, Normal: a + b)))
|
foreach (var tuple in field.Boundary.Zip(PointUtils.CalculateNormals(field.Boundary), (a, b) => (Point: a, Normal: a + b)))
|
||||||
Gizmos.DrawLine(tuple.Point.ToVector3(), tuple.Normal.ToVector3());
|
Gizmos.DrawLine(tuple.Point.ToVector3(), tuple.Normal.ToVector3());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user