notebook实装功能,galgame继续,一些bug修复
This commit is contained in:
@@ -23,10 +23,26 @@ public class GameManager : MonoBehaviour
|
||||
[Header("canvas")]
|
||||
public GameObject startCanvas;
|
||||
public CanvasGroup cg_startCanvas;
|
||||
public GameObject extraStartObject;
|
||||
private CanvasGroup extraStartCG;
|
||||
public float canvasFadeTime;
|
||||
private Coroutine fade_canvasGroup;
|
||||
public CanvasGroup settleCG;
|
||||
|
||||
[Header("Start Canvas Anim")]
|
||||
[SerializeField] private bool enableStartCanvasDetailedAnim = true;
|
||||
[SerializeField] private float startCanvasBtmFadeIn = 0.28f;
|
||||
[SerializeField] private float startCanvasBtmFadeOut = 0.22f;
|
||||
[SerializeField] private int startCanvasFlashCount = 2;
|
||||
[SerializeField] private float startCanvasFlashUnit = 0.055f;
|
||||
[SerializeField] private float startCanvasImageFadeIn = 0.2f;
|
||||
[SerializeField] private float startCanvasMoveInDuration = 0.3f;
|
||||
[SerializeField] private float startCanvasMoveOutDuration = 0.22f;
|
||||
[SerializeField] private float startCanvasMoveStagger = 0.06f;
|
||||
[SerializeField] private float startCanvasMoveOffsetY = 80f;
|
||||
[SerializeField] private float startCanvasPanelExitOffsetY = 120f;
|
||||
[SerializeField] private float startCanvasEntryGap = 0.04f;
|
||||
|
||||
[Header("buttons")]
|
||||
public Button startGame;
|
||||
public Button backtoSelectingPage;
|
||||
@@ -67,6 +83,35 @@ public class GameManager : MonoBehaviour
|
||||
private SongData currentSong;
|
||||
private bool timeRecorded = false;
|
||||
|
||||
private Coroutine startCanvasIntroRoutine;
|
||||
private bool startCanvasIntroCompleted = false;
|
||||
private bool startCanvasExitStarted = false;
|
||||
|
||||
private RectTransform startupCanvasRoot;
|
||||
private RectTransform startup_btm;
|
||||
private RectTransform startup_boarder;
|
||||
private RectTransform startup_image;
|
||||
private RectTransform startup_text;
|
||||
private RectTransform startup_start;
|
||||
private RectTransform startup_escape;
|
||||
private RectTransform startup_tips;
|
||||
private RectTransform startup_uiBack;
|
||||
|
||||
private CanvasGroup startup_btmCg;
|
||||
private CanvasGroup startup_boarderCg;
|
||||
private CanvasGroup startup_imageCg;
|
||||
private CanvasGroup startup_textCg;
|
||||
private CanvasGroup startup_startCg;
|
||||
private CanvasGroup startup_escapeCg;
|
||||
private CanvasGroup startup_tipsCg;
|
||||
private CanvasGroup startup_uiBackCg;
|
||||
|
||||
private Vector2 startup_boarderBasePos;
|
||||
private Vector2 startup_imageBasePos;
|
||||
private Vector2 startup_textBasePos;
|
||||
private Vector2 startup_startBasePos;
|
||||
private Vector2 startup_escapeBasePos;
|
||||
|
||||
private void SubscribeToPauseManager()
|
||||
{
|
||||
if (pauseSubscribed) return;
|
||||
@@ -299,8 +344,15 @@ public class GameManager : MonoBehaviour
|
||||
Debug.LogWarning("[GameManager] No SongData found for statistics tracking");
|
||||
}
|
||||
|
||||
// Start a new per-level skill timeline log (overwrites previous level log).
|
||||
string skillLogSessionName = currentSong != null ? currentSong.songName : "UnknownSong";
|
||||
GameplaySkillLogger.BeginSession(skillLogSessionName);
|
||||
Debug.Log($"[GameManager] Skill timeline log reset: {GameplaySkillLogger.LogFilePath}");
|
||||
|
||||
// Ensure start canvas and its CanvasGroup are active and visible at scene start
|
||||
if (startCanvas != null && !startCanvas.activeSelf) startCanvas.SetActive(true);
|
||||
if (startCanvas != null && startCanvas.transform.localScale.sqrMagnitude < 0.0001f)
|
||||
startCanvas.transform.localScale = Vector3.one;
|
||||
if (cg_startCanvas != null)
|
||||
{
|
||||
cg_startCanvas.alpha = 1f;
|
||||
@@ -308,6 +360,18 @@ public class GameManager : MonoBehaviour
|
||||
cg_startCanvas.blocksRaycasts = true;
|
||||
}
|
||||
|
||||
// Initialize extra start object and its CanvasGroup
|
||||
if (extraStartObject != null)
|
||||
{
|
||||
extraStartCG = extraStartObject.GetComponent<CanvasGroup>();
|
||||
}
|
||||
|
||||
startCanvasExitStarted = false;
|
||||
startCanvasIntroCompleted = false;
|
||||
InitializeStartCanvasAnimRefs();
|
||||
PrepareStartCanvasEntryState();
|
||||
StartStartCanvasIntro();
|
||||
|
||||
// Try to apply assigned SongData (if any) to background and UI after scene load
|
||||
StartCoroutine(WaitAndApplyAssignedSong(2f));
|
||||
|
||||
@@ -477,12 +541,28 @@ public class GameManager : MonoBehaviour
|
||||
StopCoroutine(fade_canvasGroup);
|
||||
fade_canvasGroup = null;
|
||||
}
|
||||
|
||||
if (startCanvasIntroRoutine != null)
|
||||
{
|
||||
StopCoroutine(startCanvasIntroRoutine);
|
||||
startCanvasIntroRoutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Start the fade coroutine for the start canvas group (safe to call multiple times)
|
||||
private void StartFadeStartCanvas()
|
||||
{
|
||||
if (cg_startCanvas == null || startCanvas == null) return;
|
||||
if (startCanvasExitStarted) return;
|
||||
startCanvasExitStarted = true;
|
||||
|
||||
if (startCanvasIntroRoutine != null)
|
||||
{
|
||||
StopCoroutine(startCanvasIntroRoutine);
|
||||
startCanvasIntroRoutine = null;
|
||||
}
|
||||
SetStartButtonsInteractable(false);
|
||||
|
||||
if (fade_canvasGroup != null) StopCoroutine(fade_canvasGroup);
|
||||
fade_canvasGroup = StartCoroutine(FadeStartCanvasCoroutine(canvasFadeTime));
|
||||
}
|
||||
@@ -491,13 +571,70 @@ public class GameManager : MonoBehaviour
|
||||
{
|
||||
if (cg_startCanvas == null || startCanvas == null) yield break;
|
||||
|
||||
if (enableStartCanvasDetailedAnim)
|
||||
{
|
||||
ApplyStartCanvasEntryFinalState();
|
||||
|
||||
// text / START / escape: sequential move down + fade out
|
||||
yield return StartCoroutine(AnimateMoveAndFade(startup_text, startup_textCg, startup_textBasePos, startup_textBasePos + new Vector2(0f, -startCanvasMoveOffsetY), 1f, 0f, startCanvasMoveOutDuration, false));
|
||||
yield return WaitRealtime(startCanvasMoveStagger);
|
||||
yield return StartCoroutine(AnimateMoveAndFade(startup_start, startup_startCg, startup_startBasePos, startup_startBasePos + new Vector2(0f, -startCanvasMoveOffsetY), 1f, 0f, startCanvasMoveOutDuration, false));
|
||||
yield return WaitRealtime(startCanvasMoveStagger);
|
||||
yield return StartCoroutine(AnimateMoveAndFade(startup_escape, startup_escapeCg, startup_escapeBasePos, startup_escapeBasePos + new Vector2(0f, -startCanvasMoveOffsetY), 1f, 0f, startCanvasMoveOutDuration, false));
|
||||
|
||||
// TIPS / UIback: flicker out
|
||||
Coroutine tipsOut = null;
|
||||
Coroutine uiBackOut = null;
|
||||
if (startup_tipsCg != null) tipsOut = StartCoroutine(FlashOut(startup_tipsCg, startCanvasFlashCount, startCanvasFlashUnit));
|
||||
if (startup_uiBackCg != null) uiBackOut = StartCoroutine(FlashOut(startup_uiBackCg, startCanvasFlashCount, startCanvasFlashUnit));
|
||||
|
||||
// boarder + Image: wait for text/START/escape, then move down + fade
|
||||
Coroutine boarderOut = StartCoroutine(AnimateMoveAndFade(startup_boarder, startup_boarderCg, startup_boarderBasePos, startup_boarderBasePos + new Vector2(0f, -startCanvasPanelExitOffsetY), 1f, 0f, startCanvasMoveOutDuration, false));
|
||||
Coroutine imageOut = StartCoroutine(AnimateMoveAndFade(startup_image, startup_imageCg, startup_imageBasePos, startup_imageBasePos + new Vector2(0f, -startCanvasPanelExitOffsetY), 1f, 0f, startCanvasMoveOutDuration, false));
|
||||
if (boarderOut != null || imageOut != null)
|
||||
yield return WaitRealtime(startCanvasMoveOutDuration + 0.01f);
|
||||
|
||||
if (tipsOut != null || uiBackOut != null)
|
||||
yield return WaitRealtime(startCanvasFlashUnit * Mathf.Max(2, startCanvasFlashCount * 2) + 0.01f);
|
||||
|
||||
// btm fade out at last
|
||||
yield return StartCoroutine(FadeCanvasGroupAlpha(startup_btmCg, 1f, 0f, startCanvasBtmFadeOut, false));
|
||||
|
||||
cg_startCanvas.alpha = 0f;
|
||||
cg_startCanvas.interactable = false;
|
||||
cg_startCanvas.blocksRaycasts = false;
|
||||
startCanvas.SetActive(false);
|
||||
|
||||
if (extraStartCG != null)
|
||||
{
|
||||
extraStartCG.alpha = 0f;
|
||||
extraStartCG.interactable = false;
|
||||
extraStartCG.blocksRaycasts = false;
|
||||
if (extraStartObject != null) extraStartObject.SetActive(false);
|
||||
}
|
||||
|
||||
fade_canvasGroup = null;
|
||||
yield break;
|
||||
}
|
||||
|
||||
float elapsed = 0f;
|
||||
float startA = cg_startCanvas.alpha;
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.unscaledDeltaTime;
|
||||
float frac = Mathf.Clamp01(elapsed / Mathf.Max(0.0001f, duration));
|
||||
cg_startCanvas.alpha = Mathf.Lerp(startA, 0f, frac);
|
||||
float currentAlpha = Mathf.Lerp(startA, 0f, frac);
|
||||
|
||||
cg_startCanvas.alpha = currentAlpha;
|
||||
if (extraStartCG != null)
|
||||
{
|
||||
extraStartCG.alpha = currentAlpha;
|
||||
// Sync raycast state with alpha
|
||||
bool visible = currentAlpha > 0.001f;
|
||||
extraStartCG.interactable = visible;
|
||||
extraStartCG.blocksRaycasts = visible;
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
@@ -505,9 +642,339 @@ public class GameManager : MonoBehaviour
|
||||
cg_startCanvas.interactable = false;
|
||||
cg_startCanvas.blocksRaycasts = false;
|
||||
startCanvas.SetActive(false);
|
||||
|
||||
if (extraStartCG != null)
|
||||
{
|
||||
extraStartCG.alpha = 0f;
|
||||
extraStartCG.interactable = false;
|
||||
extraStartCG.blocksRaycasts = false;
|
||||
if (extraStartObject != null) extraStartObject.SetActive(false);
|
||||
}
|
||||
|
||||
fade_canvasGroup = null;
|
||||
}
|
||||
|
||||
private void StartStartCanvasIntro()
|
||||
{
|
||||
if (!enableStartCanvasDetailedAnim)
|
||||
{
|
||||
ApplyStartCanvasEntryFinalState();
|
||||
startCanvasIntroCompleted = true;
|
||||
SetStartButtonsInteractable(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (startCanvasIntroRoutine != null)
|
||||
{
|
||||
StopCoroutine(startCanvasIntroRoutine);
|
||||
startCanvasIntroRoutine = null;
|
||||
}
|
||||
startCanvasIntroRoutine = StartCoroutine(StartCanvasIntroCoroutine());
|
||||
}
|
||||
|
||||
private IEnumerator StartCanvasIntroCoroutine()
|
||||
{
|
||||
startCanvasIntroCompleted = false;
|
||||
SetStartButtonsInteractable(false);
|
||||
|
||||
yield return StartCoroutine(FadeCanvasGroupAlpha(startup_btmCg, 0f, 1f, startCanvasBtmFadeIn, false));
|
||||
|
||||
float flashDuration = startCanvasFlashUnit * Mathf.Max(2, startCanvasFlashCount * 2);
|
||||
Coroutine boarderIn = null;
|
||||
Coroutine tipsIn = null;
|
||||
Coroutine uiBackIn = null;
|
||||
|
||||
if (startup_boarderCg != null) boarderIn = StartCoroutine(FlashIn(startup_boarderCg, startCanvasFlashCount, startCanvasFlashUnit, false));
|
||||
if (startup_tipsCg != null) tipsIn = StartCoroutine(FlashIn(startup_tipsCg, startCanvasFlashCount, startCanvasFlashUnit, false));
|
||||
if (startup_uiBackCg != null) uiBackIn = StartCoroutine(FlashIn(startup_uiBackCg, startCanvasFlashCount, startCanvasFlashUnit, false));
|
||||
if (boarderIn != null || tipsIn != null || uiBackIn != null)
|
||||
yield return WaitRealtime(flashDuration + 0.01f);
|
||||
|
||||
yield return WaitRealtime(startCanvasEntryGap);
|
||||
yield return StartCoroutine(FadeCanvasGroupAlpha(startup_imageCg, 0f, 1f, startCanvasImageFadeIn, false));
|
||||
|
||||
Vector2 textFrom = startup_textBasePos + new Vector2(0f, -startCanvasMoveOffsetY);
|
||||
Vector2 startFrom = startup_startBasePos + new Vector2(0f, -startCanvasMoveOffsetY);
|
||||
Vector2 escapeFrom = startup_escapeBasePos + new Vector2(0f, -startCanvasMoveOffsetY);
|
||||
|
||||
yield return StartCoroutine(AnimateMoveAndFade(startup_text, startup_textCg, textFrom, startup_textBasePos, 0f, 1f, startCanvasMoveInDuration, false));
|
||||
yield return WaitRealtime(startCanvasMoveStagger);
|
||||
yield return StartCoroutine(AnimateMoveAndFade(startup_start, startup_startCg, startFrom, startup_startBasePos, 0f, 1f, startCanvasMoveInDuration, true));
|
||||
yield return WaitRealtime(startCanvasMoveStagger);
|
||||
yield return StartCoroutine(AnimateMoveAndFade(startup_escape, startup_escapeCg, escapeFrom, startup_escapeBasePos, 0f, 1f, startCanvasMoveInDuration, true));
|
||||
|
||||
startCanvasIntroCompleted = true;
|
||||
SetStartButtonsInteractable(true);
|
||||
startCanvasIntroRoutine = null;
|
||||
}
|
||||
|
||||
private void InitializeStartCanvasAnimRefs()
|
||||
{
|
||||
startupCanvasRoot = null;
|
||||
startup_btm = null;
|
||||
startup_boarder = null;
|
||||
startup_image = null;
|
||||
startup_text = null;
|
||||
startup_start = null;
|
||||
startup_escape = null;
|
||||
startup_tips = null;
|
||||
startup_uiBack = null;
|
||||
|
||||
startup_btmCg = null;
|
||||
startup_boarderCg = null;
|
||||
startup_imageCg = null;
|
||||
startup_textCg = null;
|
||||
startup_startCg = null;
|
||||
startup_escapeCg = null;
|
||||
startup_tipsCg = null;
|
||||
startup_uiBackCg = null;
|
||||
|
||||
if (startCanvas == null) return;
|
||||
|
||||
Transform root = startCanvas.transform;
|
||||
startupCanvasRoot = FindRectByName(root, "startupCanvas");
|
||||
if (startupCanvasRoot == null) startupCanvasRoot = root as RectTransform;
|
||||
if (startupCanvasRoot == null) return;
|
||||
|
||||
startup_btm = FindDirectChildRectByName(startupCanvasRoot, "btm");
|
||||
startup_boarder = FindDirectChildRectByName(startupCanvasRoot, "boarder");
|
||||
startup_image = FindDirectChildRectByName(startupCanvasRoot, "Image");
|
||||
startup_text = FindDirectChildRectByName(startupCanvasRoot, "text");
|
||||
startup_start = FindDirectChildRectByName(startupCanvasRoot, "START");
|
||||
startup_escape = FindDirectChildRectByName(startupCanvasRoot, "escape");
|
||||
startup_tips = FindDirectChildRectByName(startupCanvasRoot, "TIPS");
|
||||
startup_uiBack = FindDirectChildRectByName(startupCanvasRoot, "UIback");
|
||||
|
||||
if (startup_tips == null) startup_tips = FindRectByName(startupCanvasRoot, "TIPS");
|
||||
if (startup_uiBack == null) startup_uiBack = FindRectByName(startupCanvasRoot, "UIback");
|
||||
|
||||
startup_btmCg = GetOrAddCanvasGroup(startup_btm);
|
||||
startup_boarderCg = GetOrAddCanvasGroup(startup_boarder);
|
||||
startup_imageCg = GetOrAddCanvasGroup(startup_image);
|
||||
startup_textCg = GetOrAddCanvasGroup(startup_text);
|
||||
startup_startCg = GetOrAddCanvasGroup(startup_start);
|
||||
startup_escapeCg = GetOrAddCanvasGroup(startup_escape);
|
||||
startup_tipsCg = GetOrAddCanvasGroup(startup_tips);
|
||||
startup_uiBackCg = GetOrAddCanvasGroup(startup_uiBack);
|
||||
|
||||
if (startup_boarder != null) startup_boarderBasePos = startup_boarder.anchoredPosition;
|
||||
if (startup_image != null) startup_imageBasePos = startup_image.anchoredPosition;
|
||||
if (startup_text != null) startup_textBasePos = startup_text.anchoredPosition;
|
||||
if (startup_start != null) startup_startBasePos = startup_start.anchoredPosition;
|
||||
if (startup_escape != null) startup_escapeBasePos = startup_escape.anchoredPosition;
|
||||
}
|
||||
|
||||
private void PrepareStartCanvasEntryState()
|
||||
{
|
||||
if (cg_startCanvas == null || startCanvas == null) return;
|
||||
|
||||
if (!startCanvas.activeSelf) startCanvas.SetActive(true);
|
||||
cg_startCanvas.alpha = 1f;
|
||||
cg_startCanvas.interactable = true;
|
||||
cg_startCanvas.blocksRaycasts = true;
|
||||
|
||||
if (extraStartCG != null)
|
||||
{
|
||||
if (extraStartObject != null && !extraStartObject.activeSelf) extraStartObject.SetActive(true);
|
||||
extraStartCG.alpha = 1f;
|
||||
extraStartCG.interactable = true;
|
||||
extraStartCG.blocksRaycasts = true;
|
||||
}
|
||||
|
||||
if (!enableStartCanvasDetailedAnim)
|
||||
{
|
||||
ApplyStartCanvasEntryFinalState();
|
||||
return;
|
||||
}
|
||||
|
||||
SetCanvasGroupAlpha(startup_btmCg, 0f, false);
|
||||
SetCanvasGroupAlpha(startup_boarderCg, 0f, false);
|
||||
SetCanvasGroupAlpha(startup_imageCg, 0f, false);
|
||||
SetCanvasGroupAlpha(startup_textCg, 0f, false);
|
||||
SetCanvasGroupAlpha(startup_startCg, 0f, true);
|
||||
SetCanvasGroupAlpha(startup_escapeCg, 0f, true);
|
||||
SetCanvasGroupAlpha(startup_tipsCg, 0f, false);
|
||||
SetCanvasGroupAlpha(startup_uiBackCg, 0f, false);
|
||||
|
||||
if (startup_boarder != null) startup_boarder.anchoredPosition = startup_boarderBasePos;
|
||||
if (startup_image != null) startup_image.anchoredPosition = startup_imageBasePos;
|
||||
if (startup_text != null) startup_text.anchoredPosition = startup_textBasePos + new Vector2(0f, -startCanvasMoveOffsetY);
|
||||
if (startup_start != null) startup_start.anchoredPosition = startup_startBasePos + new Vector2(0f, -startCanvasMoveOffsetY);
|
||||
if (startup_escape != null) startup_escape.anchoredPosition = startup_escapeBasePos + new Vector2(0f, -startCanvasMoveOffsetY);
|
||||
}
|
||||
|
||||
private void ApplyStartCanvasEntryFinalState()
|
||||
{
|
||||
if (startup_boarder != null) startup_boarder.anchoredPosition = startup_boarderBasePos;
|
||||
if (startup_image != null) startup_image.anchoredPosition = startup_imageBasePos;
|
||||
if (startup_text != null) startup_text.anchoredPosition = startup_textBasePos;
|
||||
if (startup_start != null) startup_start.anchoredPosition = startup_startBasePos;
|
||||
if (startup_escape != null) startup_escape.anchoredPosition = startup_escapeBasePos;
|
||||
|
||||
SetCanvasGroupAlpha(startup_btmCg, 1f, false);
|
||||
SetCanvasGroupAlpha(startup_boarderCg, 1f, false);
|
||||
SetCanvasGroupAlpha(startup_imageCg, 1f, false);
|
||||
SetCanvasGroupAlpha(startup_textCg, 1f, false);
|
||||
SetCanvasGroupAlpha(startup_startCg, 1f, true);
|
||||
SetCanvasGroupAlpha(startup_escapeCg, 1f, true);
|
||||
SetCanvasGroupAlpha(startup_tipsCg, 1f, false);
|
||||
SetCanvasGroupAlpha(startup_uiBackCg, 1f, false);
|
||||
}
|
||||
|
||||
private void SetStartButtonsInteractable(bool interactable)
|
||||
{
|
||||
if (startGame != null) startGame.interactable = interactable;
|
||||
if (backtoSelectingPage != null) backtoSelectingPage.interactable = interactable;
|
||||
}
|
||||
|
||||
private IEnumerator AnimateMoveAndFade(RectTransform rt, CanvasGroup cg, Vector2 from, Vector2 to, float fromAlpha, float toAlpha, float duration, bool allowRaycastWhenVisible)
|
||||
{
|
||||
if (rt == null || cg == null) yield break;
|
||||
|
||||
float dur = Mathf.Max(0.01f, duration);
|
||||
float elapsed = 0f;
|
||||
rt.anchoredPosition = from;
|
||||
SetCanvasGroupAlpha(cg, fromAlpha, allowRaycastWhenVisible);
|
||||
|
||||
while (elapsed < dur)
|
||||
{
|
||||
elapsed += Time.unscaledDeltaTime;
|
||||
float t = EaseOutCubic(Mathf.Clamp01(elapsed / dur));
|
||||
rt.anchoredPosition = Vector2.LerpUnclamped(from, to, t);
|
||||
float a = Mathf.LerpUnclamped(fromAlpha, toAlpha, t);
|
||||
SetCanvasGroupAlpha(cg, a, allowRaycastWhenVisible);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
rt.anchoredPosition = to;
|
||||
SetCanvasGroupAlpha(cg, toAlpha, allowRaycastWhenVisible);
|
||||
}
|
||||
|
||||
private IEnumerator FadeCanvasGroupAlpha(CanvasGroup cg, float fromAlpha, float toAlpha, float duration, bool allowRaycastWhenVisible)
|
||||
{
|
||||
if (cg == null) yield break;
|
||||
float dur = Mathf.Max(0.01f, duration);
|
||||
float elapsed = 0f;
|
||||
SetCanvasGroupAlpha(cg, fromAlpha, allowRaycastWhenVisible);
|
||||
|
||||
while (elapsed < dur)
|
||||
{
|
||||
elapsed += Time.unscaledDeltaTime;
|
||||
float t = EaseOutCubic(Mathf.Clamp01(elapsed / dur));
|
||||
float a = Mathf.LerpUnclamped(fromAlpha, toAlpha, t);
|
||||
SetCanvasGroupAlpha(cg, a, allowRaycastWhenVisible);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
SetCanvasGroupAlpha(cg, toAlpha, allowRaycastWhenVisible);
|
||||
}
|
||||
|
||||
private IEnumerator FlashIn(CanvasGroup cg, int flashes, float unitDuration, bool allowRaycastWhenVisible)
|
||||
{
|
||||
if (cg == null) yield break;
|
||||
int count = Mathf.Max(1, flashes);
|
||||
float step = Mathf.Max(0.01f, unitDuration);
|
||||
SetCanvasGroupAlpha(cg, 0f, allowRaycastWhenVisible);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
SetCanvasGroupAlpha(cg, 1f, allowRaycastWhenVisible);
|
||||
yield return WaitRealtime(step);
|
||||
if (i < count - 1)
|
||||
{
|
||||
SetCanvasGroupAlpha(cg, 0f, allowRaycastWhenVisible);
|
||||
yield return WaitRealtime(step);
|
||||
}
|
||||
}
|
||||
SetCanvasGroupAlpha(cg, 1f, allowRaycastWhenVisible);
|
||||
}
|
||||
|
||||
private IEnumerator FlashOut(CanvasGroup cg, int flashes, float unitDuration)
|
||||
{
|
||||
if (cg == null) yield break;
|
||||
int count = Mathf.Max(1, flashes);
|
||||
float step = Mathf.Max(0.01f, unitDuration);
|
||||
SetCanvasGroupAlpha(cg, 1f, false);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
SetCanvasGroupAlpha(cg, 0f, false);
|
||||
yield return WaitRealtime(step);
|
||||
if (i < count - 1)
|
||||
{
|
||||
SetCanvasGroupAlpha(cg, 1f, false);
|
||||
yield return WaitRealtime(step);
|
||||
}
|
||||
}
|
||||
SetCanvasGroupAlpha(cg, 0f, false);
|
||||
}
|
||||
|
||||
private IEnumerator WaitRealtime(float duration)
|
||||
{
|
||||
float elapsed = 0f;
|
||||
float dur = Mathf.Max(0f, duration);
|
||||
while (elapsed < dur)
|
||||
{
|
||||
elapsed += Time.unscaledDeltaTime;
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static float EaseOutCubic(float t)
|
||||
{
|
||||
float inv = 1f - t;
|
||||
return 1f - inv * inv * inv;
|
||||
}
|
||||
|
||||
private static CanvasGroup GetOrAddCanvasGroup(RectTransform rt)
|
||||
{
|
||||
if (rt == null) return null;
|
||||
CanvasGroup cg = rt.GetComponent<CanvasGroup>();
|
||||
if (cg == null) cg = rt.gameObject.AddComponent<CanvasGroup>();
|
||||
return cg;
|
||||
}
|
||||
|
||||
private static void SetCanvasGroupAlpha(CanvasGroup cg, float alpha, bool allowRaycastWhenVisible)
|
||||
{
|
||||
if (cg == null) return;
|
||||
float a = Mathf.Clamp01(alpha);
|
||||
cg.alpha = a;
|
||||
bool visible = a > 0.001f;
|
||||
cg.interactable = visible && allowRaycastWhenVisible;
|
||||
cg.blocksRaycasts = visible && allowRaycastWhenVisible;
|
||||
}
|
||||
|
||||
private static RectTransform FindDirectChildRectByName(Transform root, string exactName)
|
||||
{
|
||||
if (root == null || string.IsNullOrEmpty(exactName)) return null;
|
||||
for (int i = 0; i < root.childCount; i++)
|
||||
{
|
||||
Transform c = root.GetChild(i);
|
||||
if (c == null) continue;
|
||||
if (string.Equals(c.name, exactName, System.StringComparison.OrdinalIgnoreCase))
|
||||
return c as RectTransform;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static RectTransform FindRectByName(Transform root, string exactName)
|
||||
{
|
||||
Transform t = FindDescendantByName(root, exactName);
|
||||
return t as RectTransform;
|
||||
}
|
||||
|
||||
private static Transform FindDescendantByName(Transform root, string exactName)
|
||||
{
|
||||
if (root == null || string.IsNullOrEmpty(exactName)) return null;
|
||||
Transform[] all = root.GetComponentsInChildren<Transform>(true);
|
||||
for (int i = 0; i < all.Length; i++)
|
||||
{
|
||||
Transform t = all[i];
|
||||
if (t == null) continue;
|
||||
if (string.Equals(t.name, exactName, System.StringComparison.OrdinalIgnoreCase))
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void OnAllNotesSpawned()
|
||||
{
|
||||
// All notes have been spawned - trigger settlement decision logic
|
||||
|
||||
Reference in New Issue
Block a user