using System.Collections.Generic;
using UnityEngine;
namespace Flexalon
{
///
/// Sometimes, it's useful to generate child objects instead of defining them statically.
/// The Flexalon Cloner can generate objects from a set of prefabs iteratively or randomly,
/// and can optionally bind to a data source.
///
[AddComponentMenu("Flexalon/Flexalon Cloner"), HelpURL("https://www.flexalon.com/docs/cloner")]
public class FlexalonCloner : MonoBehaviour
{
[SerializeField]
private List _objects;
/// Prefabs which should be cloned as children.
public List Objects
{
get => _objects;
set { _objects = value; MarkDirty(); }
}
/// In which order should prefabs be cloned.
public enum CloneTypes
{
/// Clone prefabs in the order they are assigned.
Iterative,
/// Clone prefabs in a random order.
Random
}
[SerializeField]
private CloneTypes _cloneType = CloneTypes.Iterative;
/// In which order should prefabs be cloned.
public CloneTypes CloneType
{
get => _cloneType;
set { _cloneType = value; MarkDirty(); }
}
[SerializeField]
private uint _count;
/// How many clones should be generated.
public uint Count
{
get => _count;
set { _count = value; MarkDirty(); }
}
[SerializeField]
private int _randomSeed;
/// Seed used for the Random clone type, to ensure results remain consistent.
public int RandomSeed
{
get => _randomSeed;
set { _randomSeed = value; MarkDirty(); }
}
[SerializeField]
private GameObject _dataSource = null;
/// Can be an gameObject with a component that implements FlexalonDataSource.
/// The number of objects cloned is set to the number of items in the Data property.
public GameObject DataSource
{
get => _dataSource;
set
{
UnhookDataSource();
_dataSource = value;
HookDataSource();
MarkDirty();
}
}
[SerializeField, HideInInspector]
private List _clones = new List();
void OnEnable()
{
HookDataSource();
MarkDirty();
}
private void HookDataSource()
{
if (isActiveAndEnabled && _dataSource != null && _dataSource)
{
if (_dataSource.TryGetComponent(out var component))
{
component.DataChanged += MarkDirty;
}
}
}
private void UnhookDataSource()
{
if (_dataSource != null && _dataSource)
{
if (_dataSource.TryGetComponent(out var component))
{
component.DataChanged -= MarkDirty;
}
}
}
void OnDisable()
{
UnhookDataSource();
MarkDirty();
}
/// Forces the cloner to regenerate its clones.
public void MarkDirty()
{
foreach(var clone in _clones)
{
if (Application.isPlaying)
{
Destroy(clone);
}
else
{
DestroyImmediate(clone);
}
}
_clones.Clear();
if (isActiveAndEnabled && _objects != null && _objects.Count > 0)
{
switch (_cloneType)
{
case CloneTypes.Iterative:
GenerateIterativeClones();
break;
case CloneTypes.Random:
GenerateRandomClones();
break;
}
}
}
private IReadOnlyList