94 lines
2.9 KiB
C#
94 lines
2.9 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Assets.Common;
|
|
using Assets.PointDistribution;
|
|
using Assets.Voronoi;
|
|
using UnityEngine;
|
|
using Random = System.Random;
|
|
|
|
namespace Assets
|
|
{
|
|
[RequireComponent(typeof(MeshFilter))]
|
|
[RequireComponent(typeof(MeshRenderer))]
|
|
[RequireComponent(typeof(LandmassGenerator))]
|
|
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 LandmassGenerator Generator => GetComponent<LandmassGenerator>();
|
|
|
|
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);
|
|
}
|
|
}
|
|
} |