inz-00/Assets/Scripts/ForestGenerator.cs
2019-09-10 20:55:37 +02:00

98 lines
2.9 KiB
C#

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