126 lines
4.5 KiB
C#
126 lines
4.5 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
[ExecuteAlways]
|
|
public class Lorax : MonoBehaviour {
|
|
|
|
public Terrain Terrain;
|
|
|
|
[Header("Generic Gen")]
|
|
public int Seed;
|
|
public bool Regen = false;
|
|
public bool ShowInEditor = true;
|
|
public List<GameObject> SpawnableTrees;
|
|
public List<int> Chances;
|
|
public bool DisableOnStart = true;
|
|
|
|
[Header("Generation Details")]
|
|
public float HeightMin = 7.5f;
|
|
public float HeightMax = 9;
|
|
public float TreeChance = 0.9f;
|
|
public float CampSize = 10f;
|
|
public Vector3 CampMiddle;
|
|
public float RandomNudge = 2f;
|
|
public float Denseness = 4;
|
|
public float MinimumAdjacency = 1.5f;
|
|
|
|
private int LastSeed = -1;
|
|
private Vector3[][] TreePositions;
|
|
private bool Generated = false;
|
|
|
|
private int ChunkSize = 20;
|
|
private GameObject[] Chunks;
|
|
|
|
void Start() {
|
|
Generate();
|
|
}
|
|
|
|
void Update() {
|
|
if (!Application.isPlaying) {
|
|
if (!ShowInEditor) {
|
|
if (Generated) {
|
|
DestroyGenerated();
|
|
}
|
|
return;
|
|
}
|
|
if (Generated && LastSeed == Seed && !Regen) {
|
|
return;
|
|
}
|
|
Regen = false;
|
|
LastSeed = Seed;
|
|
DestroyGenerated();
|
|
Generate();
|
|
}
|
|
}
|
|
|
|
public GameObject GetChunkAt(float x, float y) {
|
|
int CurrentChunk = (int)((Mathf.Floor((y + 250f) / ChunkSize) * 25f) + Mathf.Floor((x + 250f) / ChunkSize));
|
|
return Chunks[CurrentChunk];
|
|
}
|
|
|
|
public void DestroyGenerated() {
|
|
for (int x = transform.childCount - 1; x >= 0; x--) {
|
|
DestroyImmediate(transform.GetChild(0).gameObject);
|
|
}
|
|
Chunks = new GameObject[(500 / ChunkSize) * (500 / ChunkSize)];
|
|
Generated = false;
|
|
}
|
|
|
|
public void Generate() {
|
|
Random.InitState(Seed);
|
|
Generated = true;
|
|
Chunks = new GameObject[(500 / ChunkSize) * (500 / ChunkSize)];
|
|
int[] TotalChances = new int[SpawnableTrees.Count + 1];
|
|
int Counter = 0;
|
|
for (int x = 0; x < TotalChances.Length - 1; x++) {
|
|
TotalChances[x + 1] = Counter + Chances[x];
|
|
Counter = TotalChances[x + 1];
|
|
}
|
|
int cap = (int)Mathf.Floor(500 / Denseness);
|
|
TreePositions = new Vector3[cap][];
|
|
for (int y = 0; y < cap; y++) {
|
|
TreePositions[y] = new Vector3[cap];
|
|
for (int x = 0; x < cap; x++) {
|
|
int CurrentChunk = (int)((Mathf.Floor(y * Denseness / ChunkSize) * 25) + Mathf.Floor(x * Denseness / ChunkSize));
|
|
if (Chunks[CurrentChunk] == null) {
|
|
Chunks[CurrentChunk] = new GameObject("Chunk " + CurrentChunk);
|
|
Chunks[CurrentChunk].transform.parent = transform;
|
|
if (Application.isPlaying) {
|
|
Chunks[CurrentChunk].SetActive(!DisableOnStart);
|
|
}
|
|
}
|
|
if (Random.value > TreeChance) {
|
|
continue;
|
|
}
|
|
var pos = new Vector3(x * Denseness - 250 + Random.value * RandomNudge - RandomNudge / 2, 0, y * Denseness - 250 + Random.value * RandomNudge - RandomNudge / 2);
|
|
TreePositions[y][x] = pos;
|
|
if (x > 0 && (TreePositions[y][x - 1] - pos).magnitude < MinimumAdjacency) {
|
|
continue;
|
|
}
|
|
if (y > 0 && (TreePositions[y - 1][x] - pos).magnitude < MinimumAdjacency) {
|
|
continue;
|
|
}
|
|
if ((pos - CampMiddle).magnitude < CampSize) {
|
|
continue;
|
|
}
|
|
|
|
var height = Terrain.SampleHeight(pos);
|
|
if (height >= HeightMin && height <= HeightMax) {
|
|
pos.y = Terrain.transform.position.y + height;
|
|
var rand = Random.Range(0, TotalChances[TotalChances.Length - 1]);
|
|
var Chosen = SpawnableTrees[0];
|
|
for (int curr = TotalChances.Length - 2; curr > 0; curr--) {
|
|
if (rand > TotalChances[curr]) {
|
|
Chosen = SpawnableTrees[curr];
|
|
break;
|
|
}
|
|
}
|
|
var rot = Quaternion.Euler(0, 360 * Random.value, 0);
|
|
var obj = GameObject.Instantiate(Chosen, pos, rot, Chunks[CurrentChunk].transform);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|