From d2ab30e7a69bfe7efda63ae75812207377917bd3 Mon Sep 17 00:00:00 2001
From: miepzerino <o.skotnik@gmail.com>
Date: Sun, 30 Mar 2025 18:50:27 +0000
Subject: [PATCH] Merge branch 'Flexalon-UI-Layouts' into develop
---
Assets/Flexalon/Runtime/Cloner/FlexalonCloner.cs | 188 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 188 insertions(+), 0 deletions(-)
diff --git a/Assets/Flexalon/Runtime/Cloner/FlexalonCloner.cs b/Assets/Flexalon/Runtime/Cloner/FlexalonCloner.cs
new file mode 100644
index 0000000..a4cceb5
--- /dev/null
+++ b/Assets/Flexalon/Runtime/Cloner/FlexalonCloner.cs
@@ -0,0 +1,188 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Flexalon
+{
+ /// <summary>
+ /// 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.
+ /// </summary>
+ [AddComponentMenu("Flexalon/Flexalon Cloner"), HelpURL("https://www.flexalon.com/docs/cloner")]
+ public class FlexalonCloner : MonoBehaviour
+ {
+ [SerializeField]
+ private List<GameObject> _objects;
+ /// <summary> Prefabs which should be cloned as children. </summary>
+ public List<GameObject> Objects
+ {
+ get => _objects;
+ set { _objects = value; MarkDirty(); }
+ }
+
+ /// <summary> In which order should prefabs be cloned. </summary>
+ public enum CloneTypes
+ {
+ /// <summary> Clone prefabs in the order they are assigned. </summary>
+ Iterative,
+
+ /// <summary> Clone prefabs in a random order. </summary>
+ Random
+ }
+
+ [SerializeField]
+ private CloneTypes _cloneType = CloneTypes.Iterative;
+ /// <summary> In which order should prefabs be cloned. </summary>
+ public CloneTypes CloneType
+ {
+ get => _cloneType;
+ set { _cloneType = value; MarkDirty(); }
+ }
+
+ [SerializeField]
+ private uint _count;
+ /// <summary> How many clones should be generated. </summary>
+ public uint Count
+ {
+ get => _count;
+ set { _count = value; MarkDirty(); }
+ }
+
+ [SerializeField]
+ private int _randomSeed;
+ /// <summary> Seed used for the Random clone type, to ensure results remain consistent. </summary>
+ public int RandomSeed
+ {
+ get => _randomSeed;
+ set { _randomSeed = value; MarkDirty(); }
+ }
+
+ [SerializeField]
+ private GameObject _dataSource = null;
+ /// <summary> 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. </summary>
+ public GameObject DataSource
+ {
+ get => _dataSource;
+ set
+ {
+ UnhookDataSource();
+ _dataSource = value;
+ HookDataSource();
+ MarkDirty();
+ }
+ }
+
+ [SerializeField, HideInInspector]
+ private List<GameObject> _clones = new List<GameObject>();
+
+ void OnEnable()
+ {
+ HookDataSource();
+ MarkDirty();
+ }
+
+ private void HookDataSource()
+ {
+ if (isActiveAndEnabled && _dataSource != null && _dataSource)
+ {
+ if (_dataSource.TryGetComponent<DataSource>(out var component))
+ {
+ component.DataChanged += MarkDirty;
+ }
+ }
+ }
+
+ private void UnhookDataSource()
+ {
+ if (_dataSource != null && _dataSource)
+ {
+ if (_dataSource.TryGetComponent<DataSource>(out var component))
+ {
+ component.DataChanged -= MarkDirty;
+ }
+ }
+ }
+
+ void OnDisable()
+ {
+ UnhookDataSource();
+ MarkDirty();
+ }
+
+ /// <summary> Forces the cloner to regenerate its clones. </summary>
+ 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<object> GetData()
+ {
+ if (_dataSource != null && _dataSource)
+ {
+ return _dataSource.GetComponent<DataSource>()?.Data;
+ }
+
+ return null;
+ }
+
+ private void GenerateIterativeClones()
+ {
+ int i = 0;
+ var data = GetData();
+ var count = data?.Count ?? (int)_count;
+ while (_clones.Count < count)
+ {
+ GenerateClone(i, data);
+ i = (i + 1) % _objects.Count;
+ }
+ }
+
+ private void GenerateRandomClones()
+ {
+ var random = new System.Random(_randomSeed);
+ var data = GetData();
+ var count = data?.Count ?? (int)_count;
+ while (_clones.Count < count)
+ {
+ GenerateClone(random.Next(_objects.Count), data);
+ }
+ }
+
+ private void GenerateClone(int index, IReadOnlyList<object> data)
+ {
+ var clone = Instantiate(_objects[index], Vector3.zero, Quaternion.identity, transform);
+ _clones.Add(clone);
+
+ if (data != null && clone.TryGetComponent<DataBinding>(out var dataBinding))
+ {
+ dataBinding.SetData(data[_clones.Count - 1]);
+ }
+ }
+ }
+}
\ No newline at end of file
--
Gitblit v1.10.0