EscapeShooter/My project/Assets/Project Files/Modules/Currency/Scripts/Cloud/CurrencyCloud.cs

334 lines
13 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
namespace Watermelon
{
public class CurrencyCloud : MonoBehaviour
{
[SerializeField] Data[] floatingCloudCases;
private static Dictionary<int, Data> floatingCloudLink = new Dictionary<int, Data>();
private static List<Animation> activeClouds = new List<Animation>();
private void Start()
{
for (int i = 0; i < floatingCloudCases.Length; i++)
{
RegisterCase(floatingCloudCases[i]);
}
Currency[] currencies = CurrencyController.Currencies;
if (!currencies.IsNullOrEmpty())
{
foreach (var currency in currencies)
{
Currency.FloatingCloudCase floatingCloudCase = currency.CurrencyCloud;
if (floatingCloudCase.AddToCloud)
{
CurrencyCloudSettings settings;
if (floatingCloudCase.SpecialPrefab != null)
{
settings = new CurrencyCloudSettings(currency.CurrencyType.ToString(), floatingCloudCase.SpecialPrefab);
}
else
{
settings = new CurrencyCloudSettings(currency.CurrencyType.ToString(), currency.Icon, new Vector2(100, 100));
}
settings.SetAudio(floatingCloudCase.AppearAudioClip, floatingCloudCase.CollectAudioClip);
RegisterCase(settings);
}
}
}
}
private void OnDestroy()
{
for (int i = 0; i < activeClouds.Count; i++)
{
activeClouds[i].Clear();
}
activeClouds.Clear();
foreach (Data floatingCloudData in floatingCloudLink.Values)
{
floatingCloudData.Destroy();
}
floatingCloudLink.Clear();
}
public static bool IsRegistered(string key) => floatingCloudLink.ContainsKey(key.GetHashCode());
public static void RegisterCase(CurrencyCloudSettings settings)
{
int cloudHash = settings.Name.GetHashCode();
if (floatingCloudLink.ContainsKey(cloudHash))
{
Debug.LogError($"Cloud {settings.Name} already registered!");
return;
}
Data data = new Data(settings);
data.Init();
floatingCloudLink.Add(cloudHash, data);
}
public static void RegisterCase(Data floatingCloudCase)
{
int cloudHash = floatingCloudCase.Name.GetHashCode();
if (floatingCloudLink.ContainsKey(cloudHash))
{
Debug.LogError($"Cloud {floatingCloudCase.Name} already registered!");
return;
}
floatingCloudCase.Init();
floatingCloudLink.Add(cloudHash, floatingCloudCase);
}
public static void SpawnCurrency(string key, RectTransform rectTransform, RectTransform targetTransform, int elementsAmount, string text, SimpleCallback onCurrencyHittedTarget = null)
{
SpawnCurrency(key.GetHashCode(), rectTransform, targetTransform, elementsAmount, text, onCurrencyHittedTarget);
}
public static void SpawnCurrency(int hash, RectTransform rectTransform, RectTransform targetTransform, int elementsAmount, string text, SimpleCallback onCurrencyHittedTarget = null)
{
if (!floatingCloudLink.ContainsKey(hash))
{
Debug.LogError($"Cloud with hash {hash} isn't registered!");
return;
}
Animation animation = new Animation(floatingCloudLink[hash], rectTransform, targetTransform, elementsAmount, onCurrencyHittedTarget);
animation.PlayAnimation();
activeClouds.Add(animation);
}
public static void OnAnimationFinished(Animation animation)
{
activeClouds.Remove(animation);
}
[System.Serializable]
public class Data
{
[SerializeField] string name;
public string Name => name;
[SerializeField] GameObject prefab;
public GameObject Prefab => prefab;
[SerializeField] AudioClip appearAudioClip;
public AudioClip AppearAudioClip => appearAudioClip;
[SerializeField] AudioClipHandler appearClipHandler;
public AudioClipHandler AppearClipHandler => appearClipHandler;
[SerializeField] AudioClip collectAudioClip;
public AudioClip CollectAudioClip => collectAudioClip;
[SerializeField] AudioClipHandler collectClipHandler;
public AudioClipHandler CollectClipHandler => collectClipHandler;
[Space]
[SerializeField] float cloudRadius;
public float CloudRadius => cloudRadius;
private Pool pool;
public Pool Pool => pool;
public Data(CurrencyCloudSettings settings)
{
name = settings.Name;
prefab = settings.Prefab;
cloudRadius = settings.CloudRadius;
appearAudioClip = settings.AppearAudioClip;
collectAudioClip = settings.CollectAudioClip;
appearClipHandler = new AudioClipHandler(AudioType.Sound, 1.0f);
collectClipHandler = new AudioClipHandler(AudioType.Sound, 1.0f);
}
public void Init()
{
pool = new Pool(prefab, "CurrencyCloud_" + name);
}
public void Destroy()
{
PoolManager.DestroyPool(pool);
pool = null;
}
}
public class Animation
{
private Data floatingCloudData;
private RectTransform rectTransform;
private RectTransform targetTransform;
private int elementsAmount;
private List<RectTransform> elementsList = new List<RectTransform>();
private SimpleCallback onCurrencyHittedTarget;
private Transform fakeTargetTransform;
private TweenCaseCollection tweenCaseCollection;
private bool currencyHittedTarget;
public Animation(Data floatingCloudData, RectTransform rectTransform, RectTransform targetTransform, int elementsAmount, SimpleCallback onCurrencyHittedTarget)
{
this.floatingCloudData = floatingCloudData;
this.rectTransform = rectTransform;
this.targetTransform = targetTransform;
this.elementsAmount = elementsAmount;
this.elementsList = new List<RectTransform>();
this.onCurrencyHittedTarget = onCurrencyHittedTarget;
GameObject fakeTargetObject = new GameObject("Fake Target");
fakeTargetTransform = fakeTargetObject.transform;
fakeTargetTransform.SetParent(targetTransform.parent);
fakeTargetTransform.position = targetTransform.position;
fakeTargetTransform.localScale = targetTransform.localScale;
fakeTargetTransform.localRotation = targetTransform.localRotation;
}
public void PlayAnimation()
{
RectTransform targetRectTransform = targetTransform;
tweenCaseCollection = Tween.BeginTweenCaseCollection();
if (floatingCloudData.AppearAudioClip != null)
floatingCloudData.AppearClipHandler.Play(floatingCloudData.AppearAudioClip);
float cloudRadius = floatingCloudData.CloudRadius;
Vector3 centerPoint = rectTransform.position;
int finishedElementsAmount = 0;
for (int i = 0; i < elementsAmount; i++)
{
TweenCase currencyTweenCase = null;
GameObject elementObject = floatingCloudData.Pool.GetPooledObject();
RectTransform elementRectTransform = (RectTransform)elementObject.transform;
elementRectTransform.SetParent(fakeTargetTransform);
elementRectTransform.position = centerPoint;
elementRectTransform.localRotation = Quaternion.identity;
elementRectTransform.localScale = Vector3.one;
elementsList.Add(elementRectTransform);
// Custom prefabs (shine/trail effects, ...) drive their own fade via
// ICurrencyCloudFlyable; plain prefabs fall back to fading their root Image.
ICurrencyCloudFlyable flyable = elementObject.GetComponent<ICurrencyCloudFlyable>();
Image elementImage = flyable == null ? elementObject.GetComponent<Image>() : null;
void SetAlpha(float alpha)
{
if (flyable != null) flyable.SetAlpha(alpha);
else elementImage.color = elementImage.color.SetAlpha(alpha);
}
SetAlpha(0);
flyable?.OnFlightStart();
float moveTime = Random.Range(0.6f, 0.8f);
if (flyable != null)
tweenCaseCollection.AddTween(Tween.DoFloat(0f, 1f, 0.2f, SetAlpha, unscaledTime: true));
else
elementImage.DOFade(1, 0.2f, unscaledTime: true);
elementRectTransform.DOAnchoredPosition(elementRectTransform.anchoredPosition + (Random.insideUnitCircle * cloudRadius), moveTime, unscaledTime: true).SetEasing(Ease.Type.CubicOut).OnComplete(delegate
{
tweenCaseCollection.AddTween(Tween.DelayedCall(0.1f, delegate
{
tweenCaseCollection.AddTween(elementRectTransform.DOScale(0.3f, 0.5f, unscaledTime: true).SetEasing(Ease.Type.ExpoIn));
tweenCaseCollection.AddTween(elementRectTransform.DOLocalMove(Vector3.zero, 0.5f, unscaledTime: true).SetEasing(Ease.Type.SineIn).OnComplete(delegate
{
if (!currencyHittedTarget)
{
if (onCurrencyHittedTarget != null)
onCurrencyHittedTarget.Invoke();
currencyHittedTarget = true;
}
bool punchTarget = true;
if (currencyTweenCase != null)
{
if (currencyTweenCase.State < 0.8f)
{
punchTarget = false;
}
else
{
currencyTweenCase.Kill();
}
}
if (punchTarget)
{
if (floatingCloudData.CollectAudioClip != null)
floatingCloudData.CollectClipHandler.Play(floatingCloudData.CollectAudioClip);
currencyTweenCase = targetRectTransform.DOScale(1.2f, 0.15f, unscaledTime: true).OnComplete(delegate
{
currencyTweenCase = targetRectTransform.DOScale(1.0f, 0.1f, unscaledTime: true);
tweenCaseCollection.AddTween(currencyTweenCase);
});
tweenCaseCollection.AddTween(currencyTweenCase);
}
flyable?.OnFlightEnd();
elementObject.transform.SetParent(floatingCloudData.Pool.ObjectsContainer);
elementObject.SetActive(false);
finishedElementsAmount++;
if (finishedElementsAmount >= elementsAmount)
{
CurrencyCloud.OnAnimationFinished(this);
GameObject.Destroy(fakeTargetTransform.gameObject);
}
}));
}, unscaledTime: true));
});
}
Tween.EndTweenCaseCollection();
}
public void Clear()
{
// Callers may credit currency inside onCurrencyHittedTarget — if the animation
// is killed before the first element lands, fire it so the reward isn't lost
if (!currencyHittedTarget)
{
currencyHittedTarget = true;
if (onCurrencyHittedTarget != null)
onCurrencyHittedTarget.Invoke();
}
tweenCaseCollection.Kill();
if (fakeTargetTransform != null)
GameObject.Destroy(fakeTargetTransform.gameObject);
}
}
}
}