com.wallstop-studios.unity-helpers 1.0.0-rc8 → 1.0.1-rc01
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Editor/AnimationEventEditor.cs +21 -5
- package/Runtime/Core/Attributes/ChildComponentAttribute.cs +17 -12
- package/Runtime/Core/Attributes/ParentComponent.cs +15 -12
- package/Runtime/Core/Attributes/SiblingComponentAttribute.cs +10 -7
- package/Runtime/Core/Attributes/ValidateAssignmentAttribute.cs +43 -14
- package/Runtime/Core/Extension/StringExtensions.cs +65 -10
- package/Runtime/Core/Helper/Helpers.cs +107 -51
- package/Runtime/Utils/SpriteRendererMetadata.cs +273 -0
- package/Runtime/Utils/SpriteRendererMetadata.cs.meta +3 -0
- package/Runtime/Utils/SpriteRendererSyncer.cs +98 -0
- package/Runtime/Utils/SpriteRendererSyncer.cs.meta +3 -0
- package/Tests/Runtime/Extensions/StringExtensionTests.cs +31 -0
- package/Tests/Runtime/Extensions/StringExtensionTests.cs.meta +3 -0
- package/Tests/Runtime/Extensions.meta +3 -0
- package/Tests/Runtime/Random/RandomTestBase.cs +16 -8
- package/Tests/Runtime/Utils/SpriteRendererMetadataTests.cs +395 -0
- package/Tests/Runtime/Utils/SpriteRendererMetadataTests.cs.meta +3 -0
- package/Tests/Runtime/Utils.meta +3 -0
- package/package.json +2 -1
- package/Runtime/Core/Attributes/AutomaticallyFindAttribute.cs +0 -43
- package/Runtime/Core/Attributes/AutomaticallyFindAttribute.cs.meta +0 -11
|
@@ -55,7 +55,9 @@
|
|
|
55
55
|
|
|
56
56
|
if (log)
|
|
57
57
|
{
|
|
58
|
-
component.LogWarn(
|
|
58
|
+
component.LogWarn(
|
|
59
|
+
"Failed to find {0} on {1} (name: {2}), id [{3}].", typeof(T).Name, tag, gameObject.name,
|
|
60
|
+
gameObject.GetInstanceID());
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
return default;
|
|
@@ -111,9 +113,9 @@
|
|
|
111
113
|
}
|
|
112
114
|
}
|
|
113
115
|
|
|
114
|
-
public static bool HasComponent<T>(this Object unityObject)
|
|
116
|
+
public static bool HasComponent<T>(this Object unityObject) where T : Object
|
|
115
117
|
{
|
|
116
|
-
return
|
|
118
|
+
return unityObject switch
|
|
117
119
|
{
|
|
118
120
|
GameObject go => go.HasComponent<T>(),
|
|
119
121
|
Component component => component.HasComponent<T>(),
|
|
@@ -121,12 +123,12 @@
|
|
|
121
123
|
};
|
|
122
124
|
}
|
|
123
125
|
|
|
124
|
-
public static bool HasComponent<T>(this Component component)
|
|
126
|
+
public static bool HasComponent<T>(this Component component) where T : Object
|
|
125
127
|
{
|
|
126
128
|
return component.TryGetComponent<T>(out _);
|
|
127
129
|
}
|
|
128
130
|
|
|
129
|
-
public static bool HasComponent<T>(this GameObject gameObject)
|
|
131
|
+
public static bool HasComponent<T>(this GameObject gameObject) where T : Object
|
|
130
132
|
{
|
|
131
133
|
return gameObject.TryGetComponent<T>(out _);
|
|
132
134
|
}
|
|
@@ -162,7 +164,8 @@
|
|
|
162
164
|
}
|
|
163
165
|
}
|
|
164
166
|
|
|
165
|
-
public static IEnumerable<GameObject> IterateOverChildGameObjectsRecursivelyIncludingSelf(
|
|
167
|
+
public static IEnumerable<GameObject> IterateOverChildGameObjectsRecursivelyIncludingSelf(
|
|
168
|
+
this GameObject gameObject)
|
|
166
169
|
{
|
|
167
170
|
yield return gameObject;
|
|
168
171
|
|
|
@@ -186,7 +189,8 @@
|
|
|
186
189
|
}
|
|
187
190
|
}
|
|
188
191
|
|
|
189
|
-
public static IEnumerable<GameObject> IterateOverParentGameObjectsRecursivelyIncludingSelf(
|
|
192
|
+
public static IEnumerable<GameObject> IterateOverParentGameObjectsRecursivelyIncludingSelf(
|
|
193
|
+
this GameObject gameObject)
|
|
190
194
|
{
|
|
191
195
|
yield return gameObject;
|
|
192
196
|
|
|
@@ -225,7 +229,8 @@
|
|
|
225
229
|
}
|
|
226
230
|
}
|
|
227
231
|
|
|
228
|
-
public static void EnableRendererRecursively<T>(
|
|
232
|
+
public static void EnableRendererRecursively<T>(
|
|
233
|
+
this Component component, bool enabled,
|
|
229
234
|
Func<T, bool> exclude = null) where T : Renderer
|
|
230
235
|
{
|
|
231
236
|
if (component == null)
|
|
@@ -388,31 +393,36 @@
|
|
|
388
393
|
}
|
|
389
394
|
}
|
|
390
395
|
|
|
391
|
-
public static void DestroyAllChildrenGameObjectsImmediatelyConditionally(
|
|
396
|
+
public static void DestroyAllChildrenGameObjectsImmediatelyConditionally(
|
|
397
|
+
this GameObject gameObject,
|
|
392
398
|
Func<GameObject, bool> acceptancePredicate)
|
|
393
399
|
{
|
|
394
|
-
InternalDestroyAllChildrenGameObjects(
|
|
395
|
-
|
|
396
|
-
if (!acceptancePredicate(toDestroy))
|
|
400
|
+
InternalDestroyAllChildrenGameObjects(
|
|
401
|
+
gameObject, toDestroy =>
|
|
397
402
|
{
|
|
398
|
-
|
|
399
|
-
|
|
403
|
+
if (!acceptancePredicate(toDestroy))
|
|
404
|
+
{
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
400
407
|
|
|
401
|
-
|
|
402
|
-
|
|
408
|
+
Object.DestroyImmediate(toDestroy);
|
|
409
|
+
});
|
|
403
410
|
}
|
|
404
411
|
|
|
405
|
-
public static void DestroyAllChildGameObjectsConditionally(
|
|
412
|
+
public static void DestroyAllChildGameObjectsConditionally(
|
|
413
|
+
this GameObject gameObject,
|
|
406
414
|
Func<GameObject, bool> acceptancePredicate)
|
|
407
415
|
{
|
|
408
|
-
InternalDestroyAllChildrenGameObjects(
|
|
409
|
-
|
|
410
|
-
if (!acceptancePredicate(toDestroy))
|
|
416
|
+
InternalDestroyAllChildrenGameObjects(
|
|
417
|
+
gameObject, toDestroy =>
|
|
411
418
|
{
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
419
|
+
if (!acceptancePredicate(toDestroy))
|
|
420
|
+
{
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
toDestroy.Destroy();
|
|
425
|
+
});
|
|
416
426
|
}
|
|
417
427
|
|
|
418
428
|
public static void DestroyAllChildrenGameObjectsImmediately(this GameObject gameObject) =>
|
|
@@ -424,7 +434,8 @@
|
|
|
424
434
|
public static void EditorDestroyAllChildrenGameObjects(this GameObject gameObject) =>
|
|
425
435
|
InternalDestroyAllChildrenGameObjects(gameObject, go => go.Destroy());
|
|
426
436
|
|
|
427
|
-
private static void InternalDestroyAllChildrenGameObjects(
|
|
437
|
+
private static void InternalDestroyAllChildrenGameObjects(
|
|
438
|
+
this GameObject gameObject,
|
|
428
439
|
Action<GameObject> destroyFunction)
|
|
429
440
|
{
|
|
430
441
|
for (int i = gameObject.transform.childCount - 1; 0 <= i; --i)
|
|
@@ -441,8 +452,16 @@
|
|
|
441
452
|
{
|
|
442
453
|
return true;
|
|
443
454
|
}
|
|
444
|
-
|
|
455
|
+
|
|
456
|
+
return PrefabUtility.GetPrefabAssetType(gameObject) switch
|
|
457
|
+
{
|
|
458
|
+
PrefabAssetType.NotAPrefab => false,
|
|
459
|
+
PrefabAssetType.MissingAsset => scene.rootCount == 0,
|
|
460
|
+
_ => true,
|
|
461
|
+
};
|
|
462
|
+
#else
|
|
445
463
|
return scene.rootCount == 0;
|
|
464
|
+
#endif
|
|
446
465
|
}
|
|
447
466
|
|
|
448
467
|
public static bool IsPrefab(this Component component)
|
|
@@ -516,7 +535,9 @@
|
|
|
516
535
|
}
|
|
517
536
|
|
|
518
537
|
// https://gamedevelopment.tutsplus.com/tutorials/unity-solution-for-hitting-moving-targets--cms-29633
|
|
519
|
-
public static Vector2 PredictCurrentTarget(
|
|
538
|
+
public static Vector2 PredictCurrentTarget(
|
|
539
|
+
this GameObject currentTarget, Vector2 launchLocation, float projectileSpeed, bool predictiveFiring,
|
|
540
|
+
Vector2 targetVelocity)
|
|
520
541
|
{
|
|
521
542
|
Vector2 target = currentTarget.transform.position;
|
|
522
543
|
|
|
@@ -530,8 +551,9 @@
|
|
|
530
551
|
return target;
|
|
531
552
|
}
|
|
532
553
|
|
|
533
|
-
float a = (targetVelocity.x * targetVelocity.x) + (targetVelocity.y * targetVelocity.y) -
|
|
534
|
-
|
|
554
|
+
float a = (targetVelocity.x * targetVelocity.x) + (targetVelocity.y * targetVelocity.y) -
|
|
555
|
+
(projectileSpeed * projectileSpeed);
|
|
556
|
+
|
|
535
557
|
float b = 2 * (targetVelocity.x * (target.x - launchLocation.x) +
|
|
536
558
|
targetVelocity.y * (target.y - launchLocation.y));
|
|
537
559
|
|
|
@@ -593,7 +615,7 @@
|
|
|
593
615
|
{
|
|
594
616
|
GameObject go => go,
|
|
595
617
|
Component c => c.gameObject,
|
|
596
|
-
_ =>
|
|
618
|
+
_ => null
|
|
597
619
|
};
|
|
598
620
|
}
|
|
599
621
|
|
|
@@ -610,10 +632,12 @@
|
|
|
610
632
|
|
|
611
633
|
public static GameObject FindChildGameObjectWithTag(this GameObject gameObject, string tag)
|
|
612
634
|
{
|
|
613
|
-
return gameObject.IterateOverChildGameObjectsRecursivelyIncludingSelf()
|
|
635
|
+
return gameObject.IterateOverChildGameObjectsRecursivelyIncludingSelf()
|
|
636
|
+
.FirstOrDefault(child => child.CompareTag(tag));
|
|
614
637
|
}
|
|
615
638
|
|
|
616
|
-
public static bool HasLineOfSight(
|
|
639
|
+
public static bool HasLineOfSight(
|
|
640
|
+
Vector2 initialLocation, Vector2 direction, Transform transform, float totalDistance, float delta)
|
|
617
641
|
{
|
|
618
642
|
int hits = Physics2D.RaycastNonAlloc(initialLocation, direction, Buffers.RaycastHits);
|
|
619
643
|
for (int i = 0; i < hits; ++i)
|
|
@@ -634,7 +658,9 @@
|
|
|
634
658
|
return true;
|
|
635
659
|
}
|
|
636
660
|
|
|
637
|
-
public static Coroutine StartFunctionAsCoroutine(
|
|
661
|
+
public static Coroutine StartFunctionAsCoroutine(
|
|
662
|
+
this MonoBehaviour monoBehaviour, Action action, float updateRate, bool useJitter = false,
|
|
663
|
+
bool waitBefore = false)
|
|
638
664
|
{
|
|
639
665
|
return monoBehaviour.StartCoroutine(FunctionAsCoroutine(action, updateRate, useJitter, waitBefore));
|
|
640
666
|
}
|
|
@@ -642,30 +668,51 @@
|
|
|
642
668
|
private static IEnumerator FunctionAsCoroutine(Action action, float updateRate, bool useJitter, bool waitBefore)
|
|
643
669
|
{
|
|
644
670
|
bool usedJitter = false;
|
|
645
|
-
WaitForSeconds wait = new(updateRate);
|
|
646
|
-
|
|
647
671
|
while (true)
|
|
648
672
|
{
|
|
673
|
+
float startTime;
|
|
649
674
|
if (waitBefore)
|
|
650
675
|
{
|
|
651
|
-
// Copy-pasta the code, no way to unify in a performant way without generating garbage
|
|
652
|
-
yield return wait;
|
|
653
676
|
if (useJitter && !usedJitter)
|
|
654
677
|
{
|
|
655
|
-
|
|
678
|
+
float delay = PcgRandom.Instance.NextFloat(updateRate);
|
|
679
|
+
startTime = Time.time;
|
|
680
|
+
while (!HasEnoughTimePassed(startTime, delay))
|
|
681
|
+
{
|
|
682
|
+
yield return null;
|
|
683
|
+
}
|
|
684
|
+
|
|
656
685
|
usedJitter = true;
|
|
657
686
|
}
|
|
687
|
+
|
|
688
|
+
startTime = Time.time;
|
|
689
|
+
while (!HasEnoughTimePassed(startTime, updateRate))
|
|
690
|
+
{
|
|
691
|
+
yield return null;
|
|
692
|
+
}
|
|
658
693
|
}
|
|
659
694
|
|
|
660
695
|
action();
|
|
696
|
+
|
|
661
697
|
if (!waitBefore)
|
|
662
698
|
{
|
|
663
|
-
yield return wait;
|
|
664
699
|
if (useJitter && !usedJitter)
|
|
665
700
|
{
|
|
666
|
-
|
|
701
|
+
float delay = PcgRandom.Instance.NextFloat(updateRate);
|
|
702
|
+
startTime = Time.time;
|
|
703
|
+
while (!HasEnoughTimePassed(startTime, delay))
|
|
704
|
+
{
|
|
705
|
+
yield return null;
|
|
706
|
+
}
|
|
707
|
+
|
|
667
708
|
usedJitter = true;
|
|
668
709
|
}
|
|
710
|
+
|
|
711
|
+
startTime = Time.time;
|
|
712
|
+
while (!HasEnoughTimePassed(startTime, updateRate))
|
|
713
|
+
{
|
|
714
|
+
yield return null;
|
|
715
|
+
}
|
|
669
716
|
}
|
|
670
717
|
}
|
|
671
718
|
}
|
|
@@ -727,6 +774,7 @@
|
|
|
727
774
|
{
|
|
728
775
|
yield return null;
|
|
729
776
|
}
|
|
777
|
+
|
|
730
778
|
action();
|
|
731
779
|
}
|
|
732
780
|
|
|
@@ -736,7 +784,8 @@
|
|
|
736
784
|
action();
|
|
737
785
|
}
|
|
738
786
|
|
|
739
|
-
public static bool HasEnoughTimePassed(float timestamp, float desiredDuration) =>
|
|
787
|
+
public static bool HasEnoughTimePassed(float timestamp, float desiredDuration) =>
|
|
788
|
+
timestamp + desiredDuration < Time.time;
|
|
740
789
|
|
|
741
790
|
public static Vector2 Opposite(this Vector2 vector)
|
|
742
791
|
{
|
|
@@ -774,12 +823,12 @@
|
|
|
774
823
|
|
|
775
824
|
public static Vector3Int AsVector3Int(this (uint x, uint y, uint z) vector)
|
|
776
825
|
{
|
|
777
|
-
return new Vector3Int((int)
|
|
826
|
+
return new Vector3Int((int)vector.x, (int)vector.y, (int)vector.z);
|
|
778
827
|
}
|
|
779
828
|
|
|
780
829
|
public static Vector3Int AsVector3Int(this Vector3 vector)
|
|
781
830
|
{
|
|
782
|
-
return new Vector3Int((int)
|
|
831
|
+
return new Vector3Int((int)Math.Round(vector.x), (int)Math.Round(vector.y), (int)Math.Round(vector.z));
|
|
783
832
|
}
|
|
784
833
|
|
|
785
834
|
public static Vector3 AsVector3(this (uint x, uint y, uint z) vector)
|
|
@@ -829,7 +878,7 @@
|
|
|
829
878
|
}
|
|
830
879
|
|
|
831
880
|
foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
|
|
832
|
-
|
|
881
|
+
.Where(field => Attribute.IsDefined(field, typeof(SerializeField))))
|
|
833
882
|
{
|
|
834
883
|
try
|
|
835
884
|
{
|
|
@@ -881,13 +930,15 @@
|
|
|
881
930
|
|
|
882
931
|
public static GameObject GetTagObjectInChildHierarchy(this GameObject gameObject, string tag)
|
|
883
932
|
{
|
|
884
|
-
return gameObject.IterateOverChildGameObjectsRecursivelyIncludingSelf()
|
|
933
|
+
return gameObject.IterateOverChildGameObjectsRecursivelyIncludingSelf()
|
|
934
|
+
.FirstOrDefault(go => go.CompareTag(tag));
|
|
885
935
|
}
|
|
886
936
|
|
|
887
937
|
//https://answers.unity.com/questions/722748/refreshing-the-polygon-collider-2d-upon-sprite-cha.html
|
|
888
938
|
public static void UpdateShapeToSprite(this Component component)
|
|
889
939
|
{
|
|
890
|
-
if (!component.TryGetComponent(out SpriteRenderer spriteRenderer) ||
|
|
940
|
+
if (!component.TryGetComponent(out SpriteRenderer spriteRenderer) ||
|
|
941
|
+
component.TryGetComponent(out PolygonCollider2D collider))
|
|
891
942
|
{
|
|
892
943
|
return;
|
|
893
944
|
}
|
|
@@ -922,7 +973,8 @@
|
|
|
922
973
|
return new Vector3Int(x, y, z);
|
|
923
974
|
}
|
|
924
975
|
|
|
925
|
-
public static GameObject TryGetClosestParentWithComponentIncludingSelf<T>(this GameObject current)
|
|
976
|
+
public static GameObject TryGetClosestParentWithComponentIncludingSelf<T>(this GameObject current)
|
|
977
|
+
where T : Component
|
|
926
978
|
{
|
|
927
979
|
while (current != null)
|
|
928
980
|
{
|
|
@@ -941,7 +993,7 @@
|
|
|
941
993
|
#if UNITY_EDITOR
|
|
942
994
|
public static IEnumerable<GameObject> EnumeratePrefabs(IEnumerable<string> assetPaths = null)
|
|
943
995
|
{
|
|
944
|
-
assetPaths ??= new[] {"Assets/Prefabs", "Assets/Resources"};
|
|
996
|
+
assetPaths ??= new[] { "Assets/Prefabs", "Assets/Resources" };
|
|
945
997
|
|
|
946
998
|
foreach (string assetGuid in AssetDatabase.FindAssets("t:prefab", assetPaths.ToArray()))
|
|
947
999
|
{
|
|
@@ -954,7 +1006,8 @@
|
|
|
954
1006
|
}
|
|
955
1007
|
}
|
|
956
1008
|
|
|
957
|
-
public static IEnumerable<T> EnumerateScriptableObjects<T>(string[] assetPaths = null)
|
|
1009
|
+
public static IEnumerable<T> EnumerateScriptableObjects<T>(string[] assetPaths = null)
|
|
1010
|
+
where T : ScriptableObject
|
|
958
1011
|
{
|
|
959
1012
|
assetPaths ??= new[] { "Assets/Prefabs", "Assets/Resources", "Assets/TileMaps" };
|
|
960
1013
|
|
|
@@ -1038,7 +1091,10 @@
|
|
|
1038
1091
|
{
|
|
1039
1092
|
foreach (MonoBehaviour script in gameObject.GetComponentsInChildren<MonoBehaviour>())
|
|
1040
1093
|
{
|
|
1041
|
-
MethodInfo awakeInfo = AwakeMethodsByType.GetOrAdd(
|
|
1094
|
+
MethodInfo awakeInfo = AwakeMethodsByType.GetOrAdd(
|
|
1095
|
+
script.GetType(),
|
|
1096
|
+
type => type.GetMethod(
|
|
1097
|
+
"Awake", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic));
|
|
1042
1098
|
if (awakeInfo != null)
|
|
1043
1099
|
{
|
|
1044
1100
|
_ = awakeInfo.Invoke(script, null);
|
|
@@ -1093,4 +1149,4 @@
|
|
|
1093
1149
|
}
|
|
1094
1150
|
}
|
|
1095
1151
|
}
|
|
1096
|
-
}
|
|
1152
|
+
}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
namespace UnityHelpers.Utils
|
|
2
|
+
{
|
|
3
|
+
using System.Collections.Generic;
|
|
4
|
+
using System.Linq;
|
|
5
|
+
using UnityEngine;
|
|
6
|
+
using Core.Attributes;
|
|
7
|
+
|
|
8
|
+
/// <summary>
|
|
9
|
+
/// Keeps stack-like track of Colors and Materials of SpriteRenderers
|
|
10
|
+
/// </summary>
|
|
11
|
+
[DisallowMultipleComponent]
|
|
12
|
+
public sealed class SpriteRendererMetadata : MonoBehaviour
|
|
13
|
+
{
|
|
14
|
+
private readonly List<(Component component, Color color)> _colorStack = new();
|
|
15
|
+
private readonly List<(Component component, Material material)> _materialStack = new();
|
|
16
|
+
|
|
17
|
+
private readonly List<(Component component, Color color)> _colorStackCache = new();
|
|
18
|
+
private readonly List<(Component component, Material material)> _materialStackCache = new();
|
|
19
|
+
|
|
20
|
+
public Color OriginalColor => _colorStack[0].color;
|
|
21
|
+
|
|
22
|
+
public Color CurrentColor => _colorStack[^1].color;
|
|
23
|
+
|
|
24
|
+
public Material OriginalMaterial => _materialStack[0].material;
|
|
25
|
+
|
|
26
|
+
public Material CurrentMaterial => _materialStack[^1].material;
|
|
27
|
+
|
|
28
|
+
public IEnumerable<Material> Materials => _materialStack.Select(entry => entry.material);
|
|
29
|
+
|
|
30
|
+
public IEnumerable<Color> Colors => _colorStack.Select(entry => entry.color);
|
|
31
|
+
|
|
32
|
+
[SiblingComponent]
|
|
33
|
+
[SerializeField]
|
|
34
|
+
private SpriteRenderer _spriteRenderer;
|
|
35
|
+
|
|
36
|
+
private bool _enabled;
|
|
37
|
+
|
|
38
|
+
public void PushColor(Component component, Color color, bool force = false)
|
|
39
|
+
{
|
|
40
|
+
if (component == this)
|
|
41
|
+
{
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!force && !enabled)
|
|
46
|
+
{
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
InternalPushColor(component, color);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private void InternalPushColor(Component component, Color color)
|
|
54
|
+
{
|
|
55
|
+
RemoveColor(component);
|
|
56
|
+
_colorStack.Add((component, color));
|
|
57
|
+
_spriteRenderer.color = CurrentColor;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public void PushBackColor(Component component, Color color, bool force = false)
|
|
61
|
+
{
|
|
62
|
+
if (component == this)
|
|
63
|
+
{
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!force && !enabled)
|
|
68
|
+
{
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
RemoveColor(component);
|
|
73
|
+
_colorStack.Insert(1, (component, color));
|
|
74
|
+
_spriteRenderer.color = CurrentColor;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public void PopColor(Component component)
|
|
78
|
+
{
|
|
79
|
+
RemoveColor(component);
|
|
80
|
+
_spriteRenderer.color = CurrentColor;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/// <summary>
|
|
84
|
+
/// Inserts a material as "first in the queue".
|
|
85
|
+
/// </summary>
|
|
86
|
+
/// <param name="component">Component that owns the material.</param>
|
|
87
|
+
/// <param name="material">Material to use.</param>
|
|
88
|
+
/// <param name="force">If true, overrides the enable check.</param>
|
|
89
|
+
/// <returns>The instanced material, if possible.</returns>
|
|
90
|
+
public Material PushMaterial(Component component, Material material, bool force = false)
|
|
91
|
+
{
|
|
92
|
+
if (component == this)
|
|
93
|
+
{
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!force && !enabled)
|
|
98
|
+
{
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
#if UNITY_EDITOR
|
|
103
|
+
if (!Application.isPlaying)
|
|
104
|
+
{
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
#endif
|
|
108
|
+
return InternalPushMaterial(component, material);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private Material InternalPushMaterial(Component component, Material material)
|
|
112
|
+
{
|
|
113
|
+
RemoveMaterial(component);
|
|
114
|
+
_spriteRenderer.material = material;
|
|
115
|
+
Material instanced = _spriteRenderer.material;
|
|
116
|
+
_materialStack.Add((component, instanced));
|
|
117
|
+
return instanced;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/// <summary>
|
|
121
|
+
/// Inserts a material as "last in the queue".
|
|
122
|
+
/// </summary>
|
|
123
|
+
/// <param name="component">Component that owns the material.</param>
|
|
124
|
+
/// <param name="material">Material to use.</param>
|
|
125
|
+
/// <param name="force">If true, overrides the enable check.</param>
|
|
126
|
+
/// <returns>The instanced material, if possible.</returns>
|
|
127
|
+
public Material PushBackMaterial(Component component, Material material, bool force = false)
|
|
128
|
+
{
|
|
129
|
+
if (component == this)
|
|
130
|
+
{
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!force && !enabled)
|
|
135
|
+
{
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
#if UNITY_EDITOR
|
|
140
|
+
if (!Application.isPlaying)
|
|
141
|
+
{
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
#endif
|
|
145
|
+
|
|
146
|
+
RemoveMaterial(component);
|
|
147
|
+
Material instanced = material;
|
|
148
|
+
if (_materialStack.Count <= 1)
|
|
149
|
+
{
|
|
150
|
+
_spriteRenderer.material = material;
|
|
151
|
+
instanced = _spriteRenderer.material;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
_materialStack.Insert(1, (component, instanced));
|
|
155
|
+
return instanced;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
public void PopMaterial(Component component)
|
|
159
|
+
{
|
|
160
|
+
#if UNITY_EDITOR
|
|
161
|
+
if (!Application.isPlaying)
|
|
162
|
+
{
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
#endif
|
|
166
|
+
|
|
167
|
+
RemoveMaterial(component);
|
|
168
|
+
_spriteRenderer.material = CurrentMaterial;
|
|
169
|
+
Material instanced = _spriteRenderer.material;
|
|
170
|
+
Component currentComponent = _materialStack[^1].component;
|
|
171
|
+
_materialStack[^1] = (currentComponent, instanced);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
private void Awake()
|
|
175
|
+
{
|
|
176
|
+
if (_spriteRenderer == null)
|
|
177
|
+
{
|
|
178
|
+
this.AssignSiblingComponents();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
InternalPushColor(this, _spriteRenderer.color);
|
|
182
|
+
_colorStackCache.AddRange(_colorStack);
|
|
183
|
+
_ = InternalPushMaterial(this, _spriteRenderer.material);
|
|
184
|
+
_materialStackCache.AddRange(_materialStack);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private void OnEnable()
|
|
188
|
+
{
|
|
189
|
+
// Ignore the OnEnable call from when the object is first initialized
|
|
190
|
+
if (!_enabled)
|
|
191
|
+
{
|
|
192
|
+
_enabled = true;
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
_colorStack.Clear();
|
|
197
|
+
_colorStack.Add(_colorStackCache[0]);
|
|
198
|
+
List<(Component component, Color color)> colorBuffer = Buffers<(Component component, Color color)>.List;
|
|
199
|
+
colorBuffer.Clear();
|
|
200
|
+
colorBuffer.AddRange(_colorStackCache);
|
|
201
|
+
for (int i = 1; i < colorBuffer.Count; ++i)
|
|
202
|
+
{
|
|
203
|
+
(Component component, Color color) entry = colorBuffer[i];
|
|
204
|
+
PushColor(entry.component, entry.color, force: true);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
_materialStack.Clear();
|
|
208
|
+
_materialStack.Add(_materialStackCache[0]);
|
|
209
|
+
List<(Component component, Material material)> materialBuffer =
|
|
210
|
+
Buffers<(Component component, Material material)>.List;
|
|
211
|
+
materialBuffer.Clear();
|
|
212
|
+
materialBuffer.AddRange(_materialStackCache);
|
|
213
|
+
for (int i = 1; i < materialBuffer.Count; ++i)
|
|
214
|
+
{
|
|
215
|
+
(Component component, Material material) entry = materialBuffer[i];
|
|
216
|
+
PushMaterial(entry.component, entry.material, force: true);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private void OnDisable()
|
|
221
|
+
{
|
|
222
|
+
List<(Component component, Color color)> colorBuffer = Buffers<(Component component, Color color)>.List;
|
|
223
|
+
colorBuffer.Clear();
|
|
224
|
+
colorBuffer.AddRange(_colorStack);
|
|
225
|
+
for (int i = colorBuffer.Count - 1; 1 <= i; --i)
|
|
226
|
+
{
|
|
227
|
+
PopColor(colorBuffer[i].component);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
_colorStackCache.Clear();
|
|
231
|
+
_colorStackCache.AddRange(colorBuffer);
|
|
232
|
+
|
|
233
|
+
List<(Component component, Material material)> materialBuffer =
|
|
234
|
+
Buffers<(Component component, Material material)>.List;
|
|
235
|
+
materialBuffer.Clear();
|
|
236
|
+
materialBuffer.AddRange(_materialStack);
|
|
237
|
+
|
|
238
|
+
for (int i = materialBuffer.Count - 1; 1 <= i; --i)
|
|
239
|
+
{
|
|
240
|
+
PopMaterial(materialBuffer[i].component);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
_materialStackCache.Clear();
|
|
244
|
+
_materialStackCache.AddRange(materialBuffer);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
private void RemoveColor(Component component)
|
|
248
|
+
{
|
|
249
|
+
if (component == this)
|
|
250
|
+
{
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
_ = _colorStack.RemoveAll(
|
|
255
|
+
existingComponent => existingComponent.component == component || existingComponent.component == null);
|
|
256
|
+
_ = _colorStackCache.RemoveAll(
|
|
257
|
+
existingComponent => existingComponent.component == component || existingComponent.component == null);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private void RemoveMaterial(Component component)
|
|
261
|
+
{
|
|
262
|
+
if (component == this)
|
|
263
|
+
{
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
_ = _materialStack.RemoveAll(
|
|
268
|
+
existingComponent => existingComponent.component == component || existingComponent.component == null);
|
|
269
|
+
_ = _materialStackCache.RemoveAll(
|
|
270
|
+
existingComponent => existingComponent.component == component || existingComponent.component == null);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|