143 lines
4.3 KiB
C#
143 lines
4.3 KiB
C#
|
using System.Collections;
|
||
|
using UnityEngine;
|
||
|
using System.Collections.Generic;
|
||
|
using UnityEngine.AI;
|
||
|
|
||
|
namespace Unity.AI.Navigation.Samples
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Fill 5x5 tiles around the local position procedurally by instantiating prefabs at random positions/orientations
|
||
|
/// </summary>
|
||
|
[DefaultExecutionOrder(-200)]
|
||
|
public class RandomInstancing : MonoBehaviour
|
||
|
{
|
||
|
public GameObject m_Prefab;
|
||
|
public int m_PoolSize = 250;
|
||
|
public int m_InstancesPerTile = 10;
|
||
|
public bool m_RandomPosition = true;
|
||
|
public bool m_RandomOrientation = true;
|
||
|
public float m_Height;
|
||
|
|
||
|
public int m_BaseHash = 347652783;
|
||
|
public float m_Size = 100.0f;
|
||
|
|
||
|
[SerializeField]
|
||
|
Transform parent;
|
||
|
[SerializeField]
|
||
|
NavMeshAgent trackedAgent;
|
||
|
|
||
|
List<Transform> m_Instances = new List<Transform>();
|
||
|
int m_Used;
|
||
|
int m_LocX, m_LocZ;
|
||
|
|
||
|
void Awake()
|
||
|
{
|
||
|
for (int i = 0; i < m_PoolSize; ++i)
|
||
|
{
|
||
|
var go = Instantiate(m_Prefab, Vector3.zero, Quaternion.identity, parent) as GameObject;
|
||
|
go.SetActive(false);
|
||
|
m_Instances.Add(go.transform);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void OnEnable()
|
||
|
{
|
||
|
m_LocX = ~0;
|
||
|
m_LocZ = ~0;
|
||
|
UpdateInstances();
|
||
|
}
|
||
|
|
||
|
void OnDestroy()
|
||
|
{
|
||
|
for (int i = 0; i < m_Instances.Count; ++i)
|
||
|
{
|
||
|
if (m_Instances[i])
|
||
|
Destroy(m_Instances[i].gameObject);
|
||
|
}
|
||
|
m_Instances.Clear();
|
||
|
}
|
||
|
|
||
|
void Update()
|
||
|
{
|
||
|
if (trackedAgent.remainingDistance > 0.1f)
|
||
|
{
|
||
|
UpdateInstances();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void UpdateInstances()
|
||
|
{
|
||
|
var x = (int)Mathf.Floor(transform.position.x / m_Size);
|
||
|
var z = (int)Mathf.Floor(transform.position.z / m_Size);
|
||
|
if (x == m_LocX && z == m_LocZ)
|
||
|
return;
|
||
|
|
||
|
m_LocX = x;
|
||
|
m_LocZ = z;
|
||
|
|
||
|
m_Used = 0;
|
||
|
for (var i = x - 2; i <= x + 2; ++i)
|
||
|
{
|
||
|
for (var j = z - 2; j <= z + 2; ++j)
|
||
|
{
|
||
|
var count = UpdateTileInstances(i, j);
|
||
|
if (count != m_InstancesPerTile)
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Deactivate the remaining active elements in the pool.
|
||
|
// Here we assume all active elements are contiguous and first in the list.
|
||
|
for (int i = m_Used; i < m_PoolSize && m_Instances[i].gameObject.activeSelf; ++i)
|
||
|
m_Instances[i].gameObject.SetActive(false);
|
||
|
}
|
||
|
|
||
|
int UpdateTileInstances(int i, int j)
|
||
|
{
|
||
|
var seed = Hash2(i, j) ^ m_BaseHash;
|
||
|
var count = System.Math.Min(m_InstancesPerTile, m_PoolSize - m_Used);
|
||
|
for (var end = m_Used + count; m_Used < end; ++m_Used)
|
||
|
{
|
||
|
float x = 0;
|
||
|
float y = 0;
|
||
|
|
||
|
if (m_RandomPosition)
|
||
|
{
|
||
|
x = Random(ref seed);
|
||
|
y = Random(ref seed);
|
||
|
}
|
||
|
var pos = new Vector3((i + x) * m_Size, m_Height, (j + y) * m_Size);
|
||
|
|
||
|
if (m_RandomOrientation)
|
||
|
{
|
||
|
float r = 360.0f * Random(ref seed);
|
||
|
m_Instances[m_Used].rotation = Quaternion.AngleAxis(r, Vector3.up);
|
||
|
}
|
||
|
m_Instances[m_Used].position = pos;
|
||
|
m_Instances[m_Used].gameObject.SetActive(true);
|
||
|
}
|
||
|
|
||
|
if (count < m_InstancesPerTile)
|
||
|
Debug.LogWarning("Pool exhausted", this);
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
static int Hash2(int i, int j)
|
||
|
{
|
||
|
return (i * 73856093) ^ (j * 19349663);
|
||
|
}
|
||
|
|
||
|
static float Random(ref int seed)
|
||
|
{
|
||
|
seed = (seed ^ 123459876);
|
||
|
var k = seed / 127773;
|
||
|
seed = 16807 * (seed - k * 127773) - 2836 * k;
|
||
|
if (seed < 0)
|
||
|
seed = seed + 2147483647;
|
||
|
float ran0 = seed * 1.0f / 2147483647.0f;
|
||
|
seed = (seed ^ 123459876);
|
||
|
return ran0;
|
||
|
}
|
||
|
}
|
||
|
}
|