123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- namespace Pathfinding.Examples {
-
- [HelpURL("http://arongranberg.com/astar/documentation/stable/class_pathfinding_1_1_examples_1_1_procedural_world.php")]
- public class ProceduralWorld : MonoBehaviour {
- public Transform target;
- public ProceduralPrefab[] prefabs;
-
- public int range = 1;
- public int disableAsyncLoadWithinRange = 1;
-
- public float tileSize = 100;
- public int subTiles = 20;
-
-
-
-
-
- public bool staticBatching = false;
- Queue<IEnumerator> tileGenerationQueue = new Queue<IEnumerator>();
- public enum RotationRandomness {
- AllAxes,
- Y
- }
- [System.Serializable]
- public class ProceduralPrefab {
-
- public GameObject prefab;
-
- public float density = 0;
-
-
-
-
- public float perlin = 0;
-
-
-
-
- public float perlinPower = 1;
-
- public Vector2 perlinOffset = Vector2.zero;
-
-
-
-
- public float perlinScale = 1;
-
-
-
-
- public float random = 1;
- public RotationRandomness randomRotation = RotationRandomness.AllAxes;
-
- public bool singleFixed = false;
- }
-
- Dictionary<Int2, ProceduralTile> tiles = new Dictionary<Int2, ProceduralTile>();
-
- void Start () {
-
-
- Update();
- AstarPath.active.Scan();
- StartCoroutine(GenerateTiles());
- }
-
- void Update () {
-
- Int2 p = new Int2(Mathf.RoundToInt((target.position.x - tileSize*0.5f) / tileSize), Mathf.RoundToInt((target.position.z - tileSize*0.5f) / tileSize));
-
- range = range < 1 ? 1 : range;
-
- bool changed = true;
- while (changed) {
- changed = false;
- foreach (KeyValuePair<Int2, ProceduralTile> pair in tiles) {
- if (Mathf.Abs(pair.Key.x-p.x) > range || Mathf.Abs(pair.Key.y-p.y) > range) {
- pair.Value.Destroy();
- tiles.Remove(pair.Key);
- changed = true;
- break;
- }
- }
- }
-
-
- for (int x = p.x-range; x <= p.x+range; x++) {
- for (int z = p.y-range; z <= p.y+range; z++) {
- if (!tiles.ContainsKey(new Int2(x, z))) {
- ProceduralTile tile = new ProceduralTile(this, x, z);
- var generator = tile.Generate();
-
- generator.MoveNext();
-
- tileGenerationQueue.Enqueue(generator);
- tiles.Add(new Int2(x, z), tile);
- }
- }
- }
-
-
-
- for (int x = p.x-disableAsyncLoadWithinRange; x <= p.x+disableAsyncLoadWithinRange; x++) {
- for (int z = p.y-disableAsyncLoadWithinRange; z <= p.y+disableAsyncLoadWithinRange; z++) {
- tiles[new Int2(x, z)].ForceFinish();
- }
- }
- }
- IEnumerator GenerateTiles () {
- while (true) {
- if (tileGenerationQueue.Count > 0) {
- var generator = tileGenerationQueue.Dequeue();
- yield return StartCoroutine(generator);
- }
- yield return null;
- }
- }
- class ProceduralTile {
- int x, z;
- System.Random rnd;
- ProceduralWorld world;
- public bool destroyed { get; private set; }
- public ProceduralTile (ProceduralWorld world, int x, int z) {
- this.x = x;
- this.z = z;
- this.world = world;
- rnd = new System.Random((x * 10007) ^ (z*36007));
- }
- Transform root;
- IEnumerator ie;
- public IEnumerator Generate () {
- ie = InternalGenerate();
- GameObject rt = new GameObject("Tile " + x + " " + z);
- root = rt.transform;
- while (ie != null && root != null && ie.MoveNext()) yield return ie.Current;
- ie = null;
- }
- public void ForceFinish () {
- while (ie != null && root != null && ie.MoveNext()) {}
- ie = null;
- }
- Vector3 RandomInside () {
- Vector3 v = new Vector3();
- v.x = (x + (float)rnd.NextDouble())*world.tileSize;
- v.z = (z + (float)rnd.NextDouble())*world.tileSize;
- return v;
- }
- Vector3 RandomInside (float px, float pz) {
- Vector3 v = new Vector3();
- v.x = (px + (float)rnd.NextDouble()/world.subTiles)*world.tileSize;
- v.z = (pz + (float)rnd.NextDouble()/world.subTiles)*world.tileSize;
- return v;
- }
- Quaternion RandomYRot (ProceduralPrefab prefab) {
- return prefab.randomRotation == RotationRandomness.AllAxes ? Quaternion.Euler(360*(float)rnd.NextDouble(), 360*(float)rnd.NextDouble(), 360*(float)rnd.NextDouble()) : Quaternion.Euler(0, 360 * (float)rnd.NextDouble(), 0);
- }
- IEnumerator InternalGenerate () {
- Debug.Log("Generating tile " + x + ", " + z);
- int counter = 0;
- float[, ] ditherMap = new float[world.subTiles+2, world.subTiles+2];
-
- for (int i = 0; i < world.prefabs.Length; i++) {
- ProceduralPrefab pref = world.prefabs[i];
- if (pref.singleFixed) {
- Vector3 p = new Vector3((x+0.5f) * world.tileSize, 0, (z+0.5f) * world.tileSize);
- GameObject ob = GameObject.Instantiate(pref.prefab, p, Quaternion.identity) as GameObject;
- ob.transform.parent = root;
- } else {
- float subSize = world.tileSize/world.subTiles;
- for (int sx = 0; sx < world.subTiles; sx++) {
- for (int sz = 0; sz < world.subTiles; sz++) {
- ditherMap[sx+1, sz+1] = 0;
- }
- }
- for (int sx = 0; sx < world.subTiles; sx++) {
- for (int sz = 0; sz < world.subTiles; sz++) {
- float px = x + sx/(float)world.subTiles;
- float pz = z + sz/(float)world.subTiles;
- float perl = Mathf.Pow(Mathf.PerlinNoise((px + pref.perlinOffset.x)*pref.perlinScale, (pz + pref.perlinOffset.y)*pref.perlinScale), pref.perlinPower);
- float density = pref.density * Mathf.Lerp(1, perl, pref.perlin) * Mathf.Lerp(1, (float)rnd.NextDouble(), pref.random);
- float fcount = subSize*subSize*density + ditherMap[sx+1, sz+1];
- int count = Mathf.RoundToInt(fcount);
-
-
- ditherMap[sx+1+1, sz+1+0] += (7f/16f) * (fcount - count);
- ditherMap[sx+1-1, sz+1+1] += (3f/16f) * (fcount - count);
- ditherMap[sx+1+0, sz+1+1] += (5f/16f) * (fcount - count);
- ditherMap[sx+1+1, sz+1+1] += (1f/16f) * (fcount - count);
-
- for (int j = 0; j < count; j++) {
-
- Vector3 p = RandomInside(px, pz);
- GameObject ob = GameObject.Instantiate(pref.prefab, p, RandomYRot(pref)) as GameObject;
- ob.transform.parent = root;
-
-
- counter++;
- if (counter % 2 == 0)
- yield return null;
- }
- }
- }
- }
- }
- ditherMap = null;
- yield return null;
- yield return null;
-
- if (Application.HasProLicense() && world.staticBatching) {
- StaticBatchingUtility.Combine(root.gameObject);
- }
- }
- public void Destroy () {
- if (root != null) {
- Debug.Log("Destroying tile " + x + ", " + z);
- GameObject.Destroy(root.gameObject);
- root = null;
- }
-
- ie = null;
- }
- }
- }
- }
|