Files
bansonic_beta_main/Assets/scripts/Team/TeamSelectorAnimController.cs
T

564 lines
19 KiB
C#

using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Object = UnityEngine.Object;
public class TeamSelectorAnimController : MonoBehaviour
{
public static TeamSelectorAnimController Instance { get; private set; }
[Header("Roots")]
[SerializeField] RectTransform teamCanvas;
[SerializeField] RectTransform leftSlotsContainer;
[SerializeField] RectTransform rightTopPanel;
[SerializeField] RectTransform rightBottomPanel;
[SerializeField] RectTransform confirmButton;
[SerializeField] RectTransform titleText;
[SerializeField] RectTransform smallCardsContainer;
[Header("Timing")]
[SerializeField] bool useUnscaled = true;
[SerializeField] float panelEnterOffset = 200f;
[SerializeField] float panelEnterTime = 0.35f;
[SerializeField] float panelStagger = 0.08f;
[SerializeField] float slotEnterOffset = 140f;
[SerializeField] float slotEnterTime = 0.3f;
[SerializeField] float slotStagger = 0.06f;
[SerializeField] float confirmEnterOffset = 120f;
[SerializeField] float confirmEnterTime = 0.3f;
[SerializeField] float titleBlinkTime = 0.06f;
[SerializeField] int titleBlinkCount = 2;
[SerializeField] float cardBlinkTime = 0.05f;
[SerializeField] int cardBlinkCount = 2;
[SerializeField] float skillsBlinkTime = 0.05f;
[SerializeField] int skillsBlinkCount = 2;
bool teamChanged;
int[] cachedTeam = new int[5];
bool playRequested;
static bool pendingTeamChanged;
void Awake()
{
if (Instance == null) Instance = this;
}
void OnEnable()
{
if (Instance == null) Instance = this;
CacheTeamSnapshot();
if (pendingTeamChanged) teamChanged = true;
pendingTeamChanged = false;
BindConfirmButton();
if (!playRequested)
{
playRequested = true;
StartCoroutine(PlayOpenAnim());
}
}
void OnDisable()
{
playRequested = false;
if (HasTeamChanged())
{
FlashTeammatesProfiles();
}
teamChanged = false;
}
void OnDestroy()
{
if (Instance == this) Instance = null;
}
public static void NotifyTeamChanged()
{
pendingTeamChanged = true;
if (Instance != null) Instance.teamChanged = true;
}
public static void PlaySkillsFlash(RectTransform container = null)
{
if (Instance == null) return;
Instance.PlaySkillsFlashInternal(container);
}
IEnumerator PlayOpenAnim()
{
yield return null; // wait one frame for layout
EnsureRefs();
if (teamCanvas != null && teamCanvas.localScale == Vector3.zero)
{
teamCanvas.localScale = Vector3.one;
}
AnimatePanel(rightTopPanel, panelEnterOffset, 0f);
AnimatePanel(rightBottomPanel, panelEnterOffset, panelStagger);
AnimateConfirm(confirmButton);
FlickerTitle();
StartCoroutine(AnimateSlots());
StartCoroutine(AnimateSmallCards());
// skills flash after bottom panel enters
float delay = panelEnterTime + panelStagger + 0.05f;
DOVirtual.DelayedCall(delay, () => PlaySkillsFlashInternal(null)).SetUpdate(useUnscaled);
}
void EnsureRefs()
{
if (teamCanvas == null)
{
var child = transform.Find("teamCanvas");
teamCanvas = child as RectTransform;
}
if (teamCanvas != null && teamCanvas.localScale == Vector3.zero)
{
teamCanvas.localScale = Vector3.one;
}
if (leftSlotsContainer == null)
{
if (newTeamSelector.Instance != null && newTeamSelector.Instance.container != null)
leftSlotsContainer = newTeamSelector.Instance.container;
else if (teamCanvas != null)
leftSlotsContainer = FindChildByName(teamCanvas, "horizontal");
}
if (rightTopPanel == null && teamCanvas != null)
rightTopPanel = FindChildByName(teamCanvas, "selectBase_hero");
if (rightBottomPanel == null && teamCanvas != null)
rightBottomPanel = FindChildByName(teamCanvas, "selectBase_skills");
if (confirmButton == null && teamCanvas != null)
confirmButton = FindChildByName(teamCanvas, "confirmTeamSelecting");
if (titleText == null && teamCanvas != null)
titleText = FindChildByName(teamCanvas, "titleTXT");
if (smallCardsContainer == null && rightTopPanel != null)
{
smallCardsContainer = FindSmallCardsContainer(rightTopPanel);
}
}
void CacheTeamSnapshot()
{
cachedTeam[0] = PlayerPrefs.GetInt("selected_heroSlot01_heroID", 0);
cachedTeam[1] = PlayerPrefs.GetInt("selected_heroSlot02_heroID", 0);
cachedTeam[2] = PlayerPrefs.GetInt("selected_heroSlot03_heroID", 0);
cachedTeam[3] = PlayerPrefs.GetInt("selected_heroSlot04_heroID", 0);
cachedTeam[4] = PlayerPrefs.GetInt("selected_heroSlot05_heroID", 0);
}
bool HasTeamChanged()
{
if (teamChanged) return true;
if (cachedTeam[0] != PlayerPrefs.GetInt("selected_heroSlot01_heroID", 0)) return true;
if (cachedTeam[1] != PlayerPrefs.GetInt("selected_heroSlot02_heroID", 0)) return true;
if (cachedTeam[2] != PlayerPrefs.GetInt("selected_heroSlot03_heroID", 0)) return true;
if (cachedTeam[3] != PlayerPrefs.GetInt("selected_heroSlot04_heroID", 0)) return true;
if (cachedTeam[4] != PlayerPrefs.GetInt("selected_heroSlot05_heroID", 0)) return true;
return false;
}
IEnumerator AnimateSlots()
{
List<RectTransform> slotRects = GetSlotRects();
int tries = 0;
while ((slotRects == null || slotRects.Count == 0) && tries < 10)
{
tries++;
yield return null;
slotRects = GetSlotRects();
}
if (slotRects == null || slotRects.Count == 0) yield break;
LayoutGroup layout = leftSlotsContainer != null ? leftSlotsContainer.GetComponent<LayoutGroup>() : null;
bool layoutEnabled = layout != null && layout.enabled;
if (leftSlotsContainer != null)
LayoutRebuilder.ForceRebuildLayoutImmediate(leftSlotsContainer);
slotRects.Sort((a, b) => a.position.y.CompareTo(b.position.y));
if (layoutEnabled) layout.enabled = false;
for (int i = 0; i < slotRects.Count; i++)
{
RectTransform rt = slotRects[i];
if (rt == null) continue;
Vector2 basePos = rt.anchoredPosition;
rt.DOKill();
rt.anchoredPosition = basePos + new Vector2(0f, -slotEnterOffset);
rt.DOAnchorPos(basePos, slotEnterTime)
.SetEase(Ease.OutCubic)
.SetDelay(i * slotStagger)
.SetUpdate(useUnscaled)
.SetLink(rt.gameObject, LinkBehaviour.KillOnDisable);
}
float total = slotEnterTime + slotStagger * Mathf.Max(0, slotRects.Count - 1);
float t = 0f;
while (t < total)
{
t += useUnscaled ? Time.unscaledDeltaTime : Time.deltaTime;
yield return null;
}
if (layoutEnabled) layout.enabled = true;
if (leftSlotsContainer != null)
LayoutRebuilder.ForceRebuildLayoutImmediate(leftSlotsContainer);
}
IEnumerator AnimateSmallCards()
{
if (smallCardsContainer == null)
EnsureRefs();
// wait for top panel to slide in
float t = panelEnterTime + 0.02f;
while (t > 0f)
{
t -= useUnscaled ? Time.unscaledDeltaTime : Time.deltaTime;
yield return null;
}
List<RectTransform> cards = FindSmallCards();
if (cards.Count == 0) yield break;
cards.Sort((a, b) => a.anchoredPosition.x.CompareTo(b.anchoredPosition.x));
for (int i = 0; i < cards.Count; i++)
{
RectTransform rt = cards[i];
if (rt == null) continue;
if (rt.GetComponent<TeamSelectorMiniCardHover>() == null)
rt.gameObject.AddComponent<TeamSelectorMiniCardHover>();
EnsureRaycastTarget(rt);
CanvasGroup cg = EnsureCanvasGroup(rt);
if (cg == null) continue;
cg.DOKill();
cg.alpha = 0f;
Sequence seq = DOTween.Sequence().SetUpdate(useUnscaled);
seq.SetDelay(i * 0.04f);
seq.Append(cg.DOFade(1f, cardBlinkTime));
for (int b = 0; b < cardBlinkCount; b++)
{
seq.Append(cg.DOFade(0f, cardBlinkTime));
seq.Append(cg.DOFade(1f, cardBlinkTime));
}
seq.SetLink(cg.gameObject, LinkBehaviour.KillOnDisable);
}
}
void AnimatePanel(RectTransform panel, float offsetX, float delay)
{
if (panel == null) return;
Vector2 basePos = panel.anchoredPosition;
panel.DOKill();
panel.anchoredPosition = basePos + new Vector2(offsetX, 0f);
panel.DOAnchorPos(basePos, panelEnterTime)
.SetEase(Ease.OutCubic)
.SetDelay(delay)
.SetUpdate(useUnscaled)
.SetLink(panel.gameObject, LinkBehaviour.KillOnDisable);
}
void AnimateConfirm(RectTransform button)
{
if (button == null) return;
Vector2 basePos = button.anchoredPosition;
button.DOKill();
button.anchoredPosition = basePos + new Vector2(0f, -confirmEnterOffset);
button.DOAnchorPos(basePos, confirmEnterTime)
.SetEase(Ease.OutCubic)
.SetUpdate(useUnscaled)
.SetLink(button.gameObject, LinkBehaviour.KillOnDisable);
}
void FlickerTitle()
{
if (titleText == null) return;
CanvasGroup cg = EnsureCanvasGroup(titleText);
if (cg == null) return;
cg.DOKill();
cg.alpha = 0f;
Sequence seq = DOTween.Sequence().SetUpdate(useUnscaled);
seq.Append(cg.DOFade(1f, titleBlinkTime));
for (int i = 0; i < titleBlinkCount; i++)
{
seq.Append(cg.DOFade(0f, titleBlinkTime));
seq.Append(cg.DOFade(1f, titleBlinkTime));
}
seq.SetLink(cg.gameObject, LinkBehaviour.KillOnDisable);
}
void PlaySkillsFlashInternal(RectTransform container)
{
Transform target = container != null ? container.transform : FindSkillContainer();
if (target == null) target = rightBottomPanel != null ? rightBottomPanel.transform : null;
if (target == null) return;
var skillSlots = target.GetComponentsInChildren<slots_skillSlots>(true);
if (skillSlots != null && skillSlots.Length > 0)
{
for (int i = 0; i < skillSlots.Length; i++)
{
var slot = skillSlots[i];
if (slot == null) continue;
CanvasGroup cg = EnsureCanvasGroup(slot.transform as RectTransform);
if (cg == null) continue;
cg.DOKill();
cg.alpha = 0f;
Sequence seq = DOTween.Sequence().SetUpdate(useUnscaled);
seq.SetDelay(i * 0.03f);
seq.Append(cg.DOFade(1f, skillsBlinkTime));
for (int b = 0; b < skillsBlinkCount; b++)
{
seq.Append(cg.DOFade(0f, skillsBlinkTime));
seq.Append(cg.DOFade(1f, skillsBlinkTime));
}
seq.SetLink(cg.gameObject, LinkBehaviour.KillOnDisable);
}
return;
}
// fallback: blink all graphics under the panel if no skill slots yet
var graphics = target.GetComponentsInChildren<Graphic>(true);
for (int i = 0; i < graphics.Length; i++)
{
Graphic g = graphics[i];
if (g == null) continue;
CanvasGroup cg = EnsureCanvasGroup(g.transform as RectTransform);
if (cg == null) continue;
cg.DOKill();
cg.alpha = 0f;
Sequence seq = DOTween.Sequence().SetUpdate(useUnscaled);
seq.SetDelay(i * 0.02f);
seq.Append(cg.DOFade(1f, skillsBlinkTime));
for (int b = 0; b < skillsBlinkCount; b++)
{
seq.Append(cg.DOFade(0f, skillsBlinkTime));
seq.Append(cg.DOFade(1f, skillsBlinkTime));
}
seq.SetLink(cg.gameObject, LinkBehaviour.KillOnDisable);
}
}
void FlashTeammatesProfiles()
{
GameObject go = GameObject.Find("teammates_profilesHorizontalLayout");
if (go == null) return;
CanvasGroup cg = EnsureCanvasGroup(go.transform as RectTransform);
if (cg == null) return;
cg.DOKill();
cg.alpha = 0f;
Sequence seq = DOTween.Sequence().SetUpdate(useUnscaled);
seq.Append(cg.DOFade(1f, 0.06f));
seq.Append(cg.DOFade(0f, 0.06f));
seq.Append(cg.DOFade(1f, 0.06f));
seq.SetLink(cg.gameObject, LinkBehaviour.KillOnDisable);
}
RectTransform FindChildByName(Transform root, string name)
{
if (root == null || string.IsNullOrEmpty(name)) return null;
Transform found = root.Find(name);
if (found != null) return found as RectTransform;
foreach (Transform child in root.GetComponentsInChildren<Transform>(true))
{
if (child.name == name) return child as RectTransform;
}
return null;
}
RectTransform FindSmallCardsContainer(Transform root)
{
if (root == null) return null;
var all = root.GetComponentsInChildren<RectTransform>(true);
Transform parent = null;
int count = 0;
for (int i = 0; i < all.Length; i++)
{
RectTransform rt = all[i];
if (rt == null) continue;
if (!rt.name.StartsWith("teamSettings_teammateProfile")) continue;
parent = rt.parent;
count++;
}
if (count > 0 && parent != null)
{
return parent as RectTransform;
}
return null;
}
List<RectTransform> FindSmallCards()
{
List<RectTransform> list = new List<RectTransform>();
if (rightTopPanel == null) return list;
var all = rightTopPanel.GetComponentsInChildren<RectTransform>(true);
for (int i = 0; i < all.Length; i++)
{
RectTransform rt = all[i];
if (rt == null) continue;
if (!rt.name.StartsWith("teamSettings_teammateProfile")) continue;
list.Add(rt);
}
return list;
}
Transform FindSkillContainer()
{
if (rightBottomPanel == null) return null;
var slot = rightBottomPanel.GetComponentInChildren<slots_skillSlots>(true);
return slot != null ? slot.transform.parent : null;
}
List<RectTransform> GetSlotRects()
{
List<RectTransform> list = new List<RectTransform>();
if (newTeamSelector.Instance != null)
{
var created = newTeamSelector.Instance.GetCreatedSlots();
if (created != null && created.Count > 0)
{
for (int i = 0; i < created.Count; i++)
{
if (created[i] == null) continue;
RectTransform rt = created[i].transform as RectTransform;
if (rt != null) list.Add(rt);
}
return list;
}
}
if (leftSlotsContainer != null)
{
var slots = leftSlotsContainer.GetComponentsInChildren<slots_heroSlots>(true);
for (int i = 0; i < slots.Length; i++)
{
if (slots[i] == null) continue;
RectTransform rt = slots[i].transform as RectTransform;
if (rt != null) list.Add(rt);
}
}
return list;
}
void BindConfirmButton()
{
if (confirmButton == null) return;
Button btn = confirmButton.GetComponent<Button>();
if (btn == null) return;
btn.onClick.RemoveListener(OnConfirmClicked);
btn.onClick.AddListener(OnConfirmClicked);
}
void OnConfirmClicked()
{
if (HasTeamChanged())
{
FlashTeammatesProfiles();
teamChanged = false;
}
}
CanvasGroup EnsureCanvasGroup(RectTransform rt)
{
if (rt == null) return null;
CanvasGroup cg = rt.GetComponent<CanvasGroup>();
if (cg == null)
{
cg = rt.gameObject.AddComponent<CanvasGroup>();
}
return cg;
}
void EnsureRaycastTarget(RectTransform rt)
{
if (rt == null) return;
Graphic g = rt.GetComponent<Graphic>();
if (g != null) g.raycastTarget = true;
}
}
static class TeamSelectorAnimBootstrap
{
static bool installed;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void Reset()
{
installed = false;
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void Install()
{
if (installed) return;
installed = true;
GameObject runner = GameObject.Find("__TeamSelectorAnimRunner");
if (runner == null)
{
runner = new GameObject("__TeamSelectorAnimRunner");
Object.DontDestroyOnLoad(runner);
}
if (runner.GetComponent<TeamSelectorAnimRunner>() == null)
{
runner.AddComponent<TeamSelectorAnimRunner>();
}
}
}
class TeamSelectorAnimRunner : MonoBehaviour
{
void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
SceneManager.activeSceneChanged += OnActiveSceneChanged;
TryAttach(SceneManager.GetActiveScene());
}
void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.activeSceneChanged -= OnActiveSceneChanged;
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
TryAttach(scene);
}
void OnActiveSceneChanged(Scene from, Scene to)
{
TryAttach(to);
}
void TryAttach(Scene scene)
{
if (!scene.IsValid() || !scene.isLoaded) return;
GameObject target = FindTeamSelectorInScene(scene);
if (target == null) return;
if (target.GetComponent<TeamSelectorAnimController>() == null)
{
target.AddComponent<TeamSelectorAnimController>();
}
}
GameObject FindTeamSelectorInScene(Scene scene)
{
var all = Resources.FindObjectsOfTypeAll<GameObject>();
for (int i = 0; i < all.Length; i++)
{
var go = all[i];
if (go == null) continue;
if (go.name != "teamSelector") continue;
if (!go.scene.IsValid() || go.scene != scene) continue;
return go;
}
return null;
}
}