848 lines
26 KiB
C#
848 lines
26 KiB
C#
|
using UnityEngine;
|
||
|
using System.Collections;
|
||
|
#if UNITY_EDITOR
|
||
|
using UnityEditor;
|
||
|
#endif
|
||
|
|
||
|
namespace Dreamteck.Splines
|
||
|
{
|
||
|
[AddComponentMenu("Dreamteck/Splines/Users/Object Controller")]
|
||
|
public class ObjectController : SplineUser
|
||
|
{
|
||
|
[System.Serializable]
|
||
|
internal class ObjectControl
|
||
|
{
|
||
|
public bool isNull
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return gameObject == null;
|
||
|
}
|
||
|
}
|
||
|
public Transform transform
|
||
|
{
|
||
|
get {
|
||
|
if (gameObject == null) return null;
|
||
|
return gameObject.transform;
|
||
|
}
|
||
|
}
|
||
|
public GameObject gameObject;
|
||
|
public Vector3 position = Vector3.zero;
|
||
|
public Quaternion rotation = Quaternion.identity;
|
||
|
public Vector3 scale = Vector3.one;
|
||
|
public bool active = true;
|
||
|
|
||
|
public Vector3 baseScale = Vector3.one;
|
||
|
|
||
|
public ObjectControl(GameObject input)
|
||
|
{
|
||
|
gameObject = input;
|
||
|
baseScale = gameObject.transform.localScale;
|
||
|
}
|
||
|
|
||
|
public void Destroy()
|
||
|
{
|
||
|
if (gameObject == null) return;
|
||
|
GameObject.Destroy(gameObject);
|
||
|
}
|
||
|
|
||
|
public void DestroyImmediate()
|
||
|
{
|
||
|
if (gameObject == null) return;
|
||
|
GameObject.DestroyImmediate(gameObject);
|
||
|
}
|
||
|
|
||
|
public void Apply()
|
||
|
{
|
||
|
if (gameObject == null) return;
|
||
|
transform.position = position;
|
||
|
transform.rotation = rotation;
|
||
|
transform.localScale = scale;
|
||
|
gameObject.SetActive(active);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
public enum ObjectMethod { Instantiate, GetChildren }
|
||
|
public enum Positioning { Stretch, Clip }
|
||
|
public enum Iteration { Ordered, Random }
|
||
|
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
public GameObject[] objects = new GameObject[0];
|
||
|
|
||
|
public ObjectMethod objectMethod
|
||
|
{
|
||
|
get { return _objectMethod; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _objectMethod)
|
||
|
{
|
||
|
if (value == ObjectMethod.GetChildren)
|
||
|
{
|
||
|
_objectMethod = value;
|
||
|
Spawn();
|
||
|
}
|
||
|
else _objectMethod = value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public int spawnCount
|
||
|
{
|
||
|
get { return _spawnCount; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _spawnCount)
|
||
|
{
|
||
|
if (value < 0) value = 0;
|
||
|
if (_objectMethod == ObjectMethod.Instantiate)
|
||
|
{
|
||
|
if (value < _spawnCount)
|
||
|
{
|
||
|
_spawnCount = value;
|
||
|
Remove();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_spawnCount = value;
|
||
|
Spawn();
|
||
|
}
|
||
|
}
|
||
|
else _spawnCount = value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Positioning objectPositioning
|
||
|
{
|
||
|
get { return _objectPositioning; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _objectPositioning)
|
||
|
{
|
||
|
_objectPositioning = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Iteration iteration
|
||
|
{
|
||
|
get { return _iteration; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _iteration)
|
||
|
{
|
||
|
_iteration = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if UNITY_EDITOR
|
||
|
public bool retainPrefabInstancesInEditor
|
||
|
{
|
||
|
get { return _retainPrefabInstancesInEditor; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _retainPrefabInstancesInEditor)
|
||
|
{
|
||
|
_retainPrefabInstancesInEditor = value;
|
||
|
Clear();
|
||
|
Spawn();
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
public int randomSeed
|
||
|
{
|
||
|
get { return _randomSeed; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _randomSeed)
|
||
|
{
|
||
|
_randomSeed = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Vector3 minOffset
|
||
|
{
|
||
|
get { return _minOffset; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _minOffset)
|
||
|
{
|
||
|
_minOffset = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Vector3 maxOffset
|
||
|
{
|
||
|
get { return _maxOffset; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _maxOffset)
|
||
|
{
|
||
|
_maxOffset = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool offsetUseWorldCoords
|
||
|
{
|
||
|
get { return _offsetUseWorldCoords; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _offsetUseWorldCoords)
|
||
|
{
|
||
|
_offsetUseWorldCoords = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Vector3 minRotation
|
||
|
{
|
||
|
get { return _minRotation; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _minRotation)
|
||
|
{
|
||
|
_minRotation = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Vector3 maxRotation
|
||
|
{
|
||
|
get { return _maxRotation; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _maxRotation)
|
||
|
{
|
||
|
_maxRotation = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Vector3 rotationOffset
|
||
|
{
|
||
|
get { return (_maxRotation+_minRotation)/2f; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _minRotation || value != _maxRotation)
|
||
|
{
|
||
|
_minRotation = _maxRotation = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Vector3 minScaleMultiplier
|
||
|
{
|
||
|
get { return _minScaleMultiplier; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _minScaleMultiplier)
|
||
|
{
|
||
|
_minScaleMultiplier = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Vector3 maxScaleMultiplier
|
||
|
{
|
||
|
get { return _maxScaleMultiplier; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _maxScaleMultiplier)
|
||
|
{
|
||
|
_maxScaleMultiplier = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool uniformScaleLerp
|
||
|
{
|
||
|
get { return _uniformScaleLerp; }
|
||
|
set
|
||
|
{
|
||
|
if(value != _uniformScaleLerp)
|
||
|
{
|
||
|
_uniformScaleLerp = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool shellOffset
|
||
|
{
|
||
|
get { return _shellOffset; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _shellOffset)
|
||
|
{
|
||
|
_shellOffset = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool applyRotation
|
||
|
{
|
||
|
get { return _applyRotation; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _applyRotation)
|
||
|
{
|
||
|
_applyRotation = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool rotateByOffset
|
||
|
{
|
||
|
get { return _rotateByOffset; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _rotateByOffset)
|
||
|
{
|
||
|
_rotateByOffset = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool applyScale
|
||
|
{
|
||
|
get { return _applyScale; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _applyScale)
|
||
|
{
|
||
|
_applyScale = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public float evaluateOffset
|
||
|
{
|
||
|
get { return _evaluateOffset; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _evaluateOffset)
|
||
|
{
|
||
|
_evaluateOffset = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public float minObjectDistance
|
||
|
{
|
||
|
get { return _minObjectDistance; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _minObjectDistance)
|
||
|
{
|
||
|
_minObjectDistance = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public float maxObjectDistance
|
||
|
{
|
||
|
get { return _maxObjectDistance; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _maxObjectDistance)
|
||
|
{
|
||
|
_maxObjectDistance = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public ObjectControllerCustomRuleBase customOffsetRule
|
||
|
{
|
||
|
get { return _customOffsetRule; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _customOffsetRule)
|
||
|
{
|
||
|
_customOffsetRule = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public ObjectControllerCustomRuleBase customRotationRule
|
||
|
{
|
||
|
get { return _customRotationRule; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _customRotationRule)
|
||
|
{
|
||
|
_customRotationRule = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public ObjectControllerCustomRuleBase customScaleRule
|
||
|
{
|
||
|
get { return _customScaleRule; }
|
||
|
set
|
||
|
{
|
||
|
if (value != _customScaleRule)
|
||
|
{
|
||
|
_customScaleRule = value;
|
||
|
Rebuild();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private float _evaluateOffset = 0f;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private int _spawnCount = 0;
|
||
|
#if UNITY_EDITOR
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private bool _retainPrefabInstancesInEditor = true;
|
||
|
#endif
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private Positioning _objectPositioning = Positioning.Stretch;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private Iteration _iteration = Iteration.Ordered;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private int _randomSeed = 1;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private Vector3 _minOffset = Vector3.zero;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private Vector3 _maxOffset = Vector3.zero;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private bool _offsetUseWorldCoords = false;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private Vector3 _minRotation = Vector3.zero;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private Vector3 _maxRotation = Vector3.zero;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private bool _uniformScaleLerp = true;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private Vector3 _minScaleMultiplier = Vector3.one;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private Vector3 _maxScaleMultiplier = Vector3.one;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private bool _shellOffset = false;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private bool _applyRotation = true;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private bool _rotateByOffset = false;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private bool _applyScale = false;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private ObjectMethod _objectMethod = ObjectMethod.Instantiate;
|
||
|
[HideInInspector]
|
||
|
public bool delayedSpawn = false;
|
||
|
[HideInInspector]
|
||
|
public float spawnDelay = 0.1f;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private int lastChildCount = 0;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private ObjectControl[] spawned = new ObjectControl[0];
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private bool _useCustomObjectDistance = false;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private float _minObjectDistance = 0f;
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private float _maxObjectDistance = 0f;
|
||
|
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private ObjectControllerCustomRuleBase _customOffsetRule;
|
||
|
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private ObjectControllerCustomRuleBase _customRotationRule;
|
||
|
|
||
|
[SerializeField]
|
||
|
[HideInInspector]
|
||
|
private ObjectControllerCustomRuleBase _customScaleRule;
|
||
|
|
||
|
System.Random offsetRandomizer, shellRandomizer, rotationRandomizer, scaleRandomizer, distanceRandomizer;
|
||
|
|
||
|
public void Clear()
|
||
|
{
|
||
|
for (int i = 0; i < spawned.Length; i++)
|
||
|
{
|
||
|
if (spawned[i] == null || spawned[i].transform == null) continue;
|
||
|
spawned[i].transform.localScale = spawned[i].baseScale;
|
||
|
if (_objectMethod == ObjectMethod.GetChildren) spawned[i].gameObject.SetActive(false);
|
||
|
else
|
||
|
{
|
||
|
#if UNITY_EDITOR
|
||
|
if (!Application.isPlaying) spawned[i].DestroyImmediate();
|
||
|
else spawned[i].Destroy();
|
||
|
#else
|
||
|
spawned[i].Destroy();
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
}
|
||
|
spawned = new ObjectControl[0];
|
||
|
}
|
||
|
|
||
|
private void OnValidate()
|
||
|
{
|
||
|
if (_spawnCount < 0) _spawnCount = 0;
|
||
|
}
|
||
|
|
||
|
private void Remove()
|
||
|
{
|
||
|
if (_spawnCount >= spawned.Length) return;
|
||
|
for (int i = spawned.Length - 1; i >= _spawnCount; i--)
|
||
|
{
|
||
|
if (i >= spawned.Length) break;
|
||
|
if (spawned[i] == null) continue;
|
||
|
spawned[i].transform.localScale = spawned[i].baseScale;
|
||
|
if (_objectMethod == ObjectMethod.GetChildren) spawned[i].gameObject.SetActive(false);
|
||
|
else
|
||
|
{
|
||
|
if (Application.isEditor) spawned[i].DestroyImmediate();
|
||
|
else spawned[i].Destroy();
|
||
|
|
||
|
}
|
||
|
}
|
||
|
ObjectControl[] newSpawned = new ObjectControl[_spawnCount];
|
||
|
for (int i = 0; i < newSpawned.Length; i++)
|
||
|
{
|
||
|
newSpawned[i] = spawned[i];
|
||
|
}
|
||
|
spawned = newSpawned;
|
||
|
Rebuild();
|
||
|
}
|
||
|
|
||
|
public void GetAll()
|
||
|
{
|
||
|
ObjectControl[] newSpawned = new ObjectControl[transform.childCount];
|
||
|
int index = 0;
|
||
|
foreach (Transform child in transform)
|
||
|
{
|
||
|
if (newSpawned[index] == null)
|
||
|
{
|
||
|
newSpawned[index++] = new ObjectControl(child.gameObject);
|
||
|
continue;
|
||
|
}
|
||
|
bool found = false;
|
||
|
for (int i = 0; i < spawned.Length; i++)
|
||
|
{
|
||
|
if (spawned[i].gameObject == child.gameObject)
|
||
|
{
|
||
|
newSpawned[index++] = spawned[i];
|
||
|
found = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!found) newSpawned[index++] = new ObjectControl(child.gameObject);
|
||
|
}
|
||
|
spawned = newSpawned;
|
||
|
}
|
||
|
|
||
|
public void Spawn()
|
||
|
{
|
||
|
if (_objectMethod == ObjectMethod.Instantiate)
|
||
|
{
|
||
|
if (delayedSpawn && Application.isPlaying)
|
||
|
{
|
||
|
StopCoroutine("InstantiateAllWithDelay");
|
||
|
StartCoroutine(InstantiateAllWithDelay());
|
||
|
}
|
||
|
else InstantiateAll();
|
||
|
}
|
||
|
else GetAll();
|
||
|
Rebuild();
|
||
|
}
|
||
|
|
||
|
protected override void LateRun()
|
||
|
{
|
||
|
base.LateRun();
|
||
|
if (_objectMethod == ObjectMethod.GetChildren && lastChildCount != transform.childCount)
|
||
|
{
|
||
|
Spawn();
|
||
|
lastChildCount = transform.childCount;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
IEnumerator InstantiateAllWithDelay()
|
||
|
{
|
||
|
if (spline == null) yield break;
|
||
|
if (objects.Length == 0) yield break;
|
||
|
for (int i = spawned.Length; i <= spawnCount; i++)
|
||
|
{
|
||
|
InstantiateSingle();
|
||
|
yield return new WaitForSeconds(spawnDelay);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void InstantiateAll()
|
||
|
{
|
||
|
if (spline == null) return;
|
||
|
if (objects.Length == 0) return;
|
||
|
for (int i = spawned.Length; i < spawnCount; i++) InstantiateSingle();
|
||
|
}
|
||
|
|
||
|
private void InstantiateSingle()
|
||
|
{
|
||
|
if (objects.Length == 0) return;
|
||
|
int index = 0;
|
||
|
if (_iteration == Iteration.Ordered)
|
||
|
{
|
||
|
index = spawned.Length - Mathf.FloorToInt(spawned.Length / objects.Length) * objects.Length;
|
||
|
}
|
||
|
else index = Random.Range(0, objects.Length);
|
||
|
if (objects[index] == null) return;
|
||
|
|
||
|
ObjectControl[] newSpawned = new ObjectControl[spawned.Length + 1];
|
||
|
spawned.CopyTo(newSpawned, 0);
|
||
|
#if UNITY_EDITOR
|
||
|
if (!Application.isPlaying && retainPrefabInstancesInEditor)
|
||
|
{
|
||
|
GameObject go = (GameObject)UnityEditor.PrefabUtility.InstantiatePrefab(objects[index]);
|
||
|
go.transform.position = transform.position;
|
||
|
go.transform.rotation = transform.rotation;
|
||
|
newSpawned[newSpawned.Length - 1] = new ObjectControl(go);
|
||
|
} else
|
||
|
{
|
||
|
newSpawned[newSpawned.Length - 1] = new ObjectControl((GameObject)Instantiate(objects[index], transform.position, transform.rotation));
|
||
|
}
|
||
|
#else
|
||
|
newSpawned[newSpawned.Length - 1] = new ObjectControl((GameObject)Instantiate(objects[index], transform.position, transform.rotation));
|
||
|
#endif
|
||
|
newSpawned[newSpawned.Length - 1].transform.parent = transform;
|
||
|
spawned = newSpawned;
|
||
|
}
|
||
|
|
||
|
protected override void Build()
|
||
|
{
|
||
|
base.Build();
|
||
|
offsetRandomizer = new System.Random(_randomSeed);
|
||
|
if(_shellOffset) shellRandomizer = new System.Random(_randomSeed + 1);
|
||
|
rotationRandomizer = new System.Random(_randomSeed + 2);
|
||
|
scaleRandomizer = new System.Random(_randomSeed + 3);
|
||
|
distanceRandomizer = new System.Random(_randomSeed + 4);
|
||
|
|
||
|
bool hasCustomOffset = _customOffsetRule != null;
|
||
|
bool hasCustomRotation = _customRotationRule != null;
|
||
|
bool hasCustomScale = _customScaleRule != null;
|
||
|
|
||
|
bool randomScaleMultiplier = _minScaleMultiplier != _maxScaleMultiplier;
|
||
|
double distancePercentAccum = 0.0;
|
||
|
for (int i = 0; i < spawned.Length; i++)
|
||
|
{
|
||
|
if (spawned[i] == null)
|
||
|
{
|
||
|
Clear();
|
||
|
Spawn();
|
||
|
break;
|
||
|
}
|
||
|
float percent = 0f;
|
||
|
if (spawned.Length > 1)
|
||
|
{
|
||
|
if(!_useCustomObjectDistance)
|
||
|
{
|
||
|
if (spline.isClosed)
|
||
|
{
|
||
|
percent = (float)i / spawned.Length;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
percent = (float)i / (spawned.Length - 1);
|
||
|
}
|
||
|
} else
|
||
|
{
|
||
|
percent = (float)distancePercentAccum;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
percent += _evaluateOffset;
|
||
|
if (percent > 1f)
|
||
|
{
|
||
|
percent -= 1f;
|
||
|
}
|
||
|
else if (percent < 0f)
|
||
|
{
|
||
|
percent += 1f;
|
||
|
}
|
||
|
|
||
|
if (objectPositioning == Positioning.Clip)
|
||
|
{
|
||
|
spline.Evaluate(percent, ref evalResult);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Evaluate(percent, ref evalResult);
|
||
|
}
|
||
|
|
||
|
ModifySample(ref evalResult);
|
||
|
spawned[i].position = evalResult.position;
|
||
|
|
||
|
if (_applyScale)
|
||
|
{
|
||
|
if (hasCustomScale)
|
||
|
{
|
||
|
_customScaleRule.SetContext(this, evalResult, i, spawned.Length);
|
||
|
spawned[i].scale = _customOffsetRule.GetScale();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Vector3 scale = spawned[i].baseScale * evalResult.size;
|
||
|
Vector3 multiplier = _minScaleMultiplier;
|
||
|
|
||
|
if (randomScaleMultiplier)
|
||
|
{
|
||
|
|
||
|
if (_uniformScaleLerp)
|
||
|
{
|
||
|
multiplier = Vector3.Lerp(new Vector3(_minScaleMultiplier.x, _minScaleMultiplier.y, _minScaleMultiplier.z), new Vector3(_maxScaleMultiplier.x, _maxScaleMultiplier.y, _maxScaleMultiplier.z), (float)scaleRandomizer.NextDouble());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
multiplier.x = Mathf.Lerp(_minScaleMultiplier.x, _maxScaleMultiplier.x, (float)scaleRandomizer.NextDouble());
|
||
|
multiplier.y = Mathf.Lerp(_minScaleMultiplier.y, _maxScaleMultiplier.y, (float)scaleRandomizer.NextDouble());
|
||
|
multiplier.z = Mathf.Lerp(_minScaleMultiplier.z, _maxScaleMultiplier.z, (float)scaleRandomizer.NextDouble());
|
||
|
}
|
||
|
}
|
||
|
scale.x *= multiplier.x;
|
||
|
scale.y *= multiplier.y;
|
||
|
scale.z *= multiplier.z;
|
||
|
spawned[i].scale = scale;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
spawned[i].scale = spawned[i].baseScale;
|
||
|
}
|
||
|
|
||
|
Vector3 right = Vector3.Cross(evalResult.forward, evalResult.up).normalized;
|
||
|
|
||
|
Vector3 posOffset = _minOffset;
|
||
|
if (hasCustomOffset)
|
||
|
{
|
||
|
_customOffsetRule.SetContext(this, evalResult, i, spawned.Length);
|
||
|
posOffset = _customOffsetRule.GetOffset();
|
||
|
}
|
||
|
else if (_minOffset != _maxOffset)
|
||
|
{
|
||
|
if(_shellOffset)
|
||
|
{
|
||
|
float x = _maxOffset.x - _minOffset.x;
|
||
|
float y = _maxOffset.y - _minOffset.y;
|
||
|
float angleInRadians = (float)shellRandomizer.NextDouble() * 360f * Mathf.Deg2Rad;
|
||
|
posOffset = new Vector2(0.5f * Mathf.Cos(angleInRadians), 0.5f * Mathf.Sin(angleInRadians));
|
||
|
posOffset.x *= x;
|
||
|
posOffset.y *= y;
|
||
|
} else
|
||
|
{
|
||
|
float rnd = (float)offsetRandomizer.NextDouble();
|
||
|
posOffset.x = Mathf.Lerp(_minOffset.x, _maxOffset.x, rnd);
|
||
|
rnd = (float)offsetRandomizer.NextDouble();
|
||
|
posOffset.y = Mathf.Lerp(_minOffset.y, _maxOffset.y, rnd);
|
||
|
rnd = (float)offsetRandomizer.NextDouble();
|
||
|
posOffset.z = Mathf.Lerp(_minOffset.z, _maxOffset.z, rnd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_offsetUseWorldCoords)
|
||
|
{
|
||
|
spawned[i].position += posOffset;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
spawned[i].position += right * posOffset.x * evalResult.size + evalResult.up * posOffset.y * evalResult.size;
|
||
|
}
|
||
|
|
||
|
if (_applyRotation)
|
||
|
{
|
||
|
if (hasCustomRotation)
|
||
|
{
|
||
|
_customRotationRule.SetContext(this, evalResult, i, spawned.Length);
|
||
|
spawned[i].rotation = _customRotationRule.GetRotation();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Quaternion offsetRot = Quaternion.Euler(Mathf.Lerp(_minRotation.x, _maxRotation.x, (float)rotationRandomizer.NextDouble()), Mathf.Lerp(_minRotation.y, _maxRotation.y, (float)rotationRandomizer.NextDouble()), Mathf.Lerp(_minRotation.z, _maxRotation.z, (float)rotationRandomizer.NextDouble()));
|
||
|
if (_rotateByOffset) spawned[i].rotation = Quaternion.LookRotation(evalResult.forward, spawned[i].position - evalResult.position) * offsetRot;
|
||
|
else spawned[i].rotation = evalResult.rotation * offsetRot;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_objectPositioning == Positioning.Clip)
|
||
|
{
|
||
|
if (percent < clipFrom || percent > clipTo) spawned[i].active = false;
|
||
|
else spawned[i].active = true;
|
||
|
}
|
||
|
if (_useCustomObjectDistance)
|
||
|
{
|
||
|
if (objectPositioning == Positioning.Clip)
|
||
|
{
|
||
|
distancePercentAccum = spline.Travel(distancePercentAccum, Mathf.Lerp(_minObjectDistance, _maxObjectDistance, (float)distanceRandomizer.NextDouble()));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
distancePercentAccum = Travel(distancePercentAccum, Mathf.Lerp(_minObjectDistance, _maxObjectDistance, (float)distanceRandomizer.NextDouble()));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected override void PostBuild()
|
||
|
{
|
||
|
base.PostBuild();
|
||
|
for (int i = 0; i < spawned.Length; i++)
|
||
|
{
|
||
|
spawned[i].Apply();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|