986 lines
33 KiB
C#
986 lines
33 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using TMPro;
|
|
using UnityEngine.SceneManagement;
|
|
using UnityEngine.Audio;
|
|
using Object = UnityEngine.Object;
|
|
|
|
[ExecuteAlways]
|
|
public class BgmUiBinder : MonoBehaviour
|
|
{
|
|
public static BgmUiBinder Instance { get; private set; }
|
|
[Header("Lookup Names")]
|
|
public string musicRootName = "MusicPic";
|
|
public string timeRootName = "TIME";
|
|
public string progressName = "BGM_Progress";
|
|
public string pointerName = "Zhizhen";
|
|
public string spectrumRootName = "SpectrumRoot";
|
|
public string musicPicCanvasName = "MusicPicCanvas";
|
|
|
|
[Header("Buttons")]
|
|
public string prevButtonName = "Previous_Song";
|
|
public string nextButtonName = "Next_Song";
|
|
public string pauseButtonName = "pause_Song";
|
|
public string musicToggleButtonName = "Button_Music";
|
|
public Button prevButton;
|
|
public Button nextButton;
|
|
public Button pauseButton;
|
|
public Button musicToggleButton;
|
|
public bool useManualMusicToggle = true;
|
|
public bool bindMusicToggleButton = false;
|
|
|
|
[Header("Bindings (optional)")]
|
|
public Image progressImage;
|
|
public Slider progressSlider;
|
|
|
|
public TMP_Text timeTmp;
|
|
public Text timeText;
|
|
public RectTransform pointerRect;
|
|
public Vector2 pointerOffset = Vector2.zero;
|
|
public bool enableMusicPicGyro = false;
|
|
|
|
[Header("MusicPic Toggle")]
|
|
public bool keepMusicPicAcrossScenes = false;
|
|
public bool showMusicPicInLobby = false;
|
|
public bool forceHideOnSceneLoad = true;
|
|
public string lobbySceneName = "UI_UI";
|
|
public string gameplaySceneName = "gamePlay_gamePlay";
|
|
[Tooltip("Main menu scene name where spectrum should be hidden.")]
|
|
public string mainSceneName = "Main_main";
|
|
[Tooltip("Startup/EULA scene name where spectrum should be hidden.")]
|
|
public string beforeEverythingSceneName = "beforeEverything";
|
|
public bool hideSpectrumInMainScene = true;
|
|
public float musicPicFadeDuration = 0.3f;
|
|
public bool useUnscaledTime = true;
|
|
|
|
[Header("Auto Create")]
|
|
public bool autoCreateProgress = false;
|
|
public Vector2 defaultProgressSize = new Vector2(320f, 8f);
|
|
public Vector2 defaultProgressPosition = Vector2.zero;
|
|
public Color progressColor = Color.white;
|
|
public Vector2 pointerStartPos = new Vector2(-190.98f, -87.05f);
|
|
public Vector2 pointerEndPos = new Vector2(195.3f, -87.05f);
|
|
public Vector2 spectrumPosition = new Vector2(-238.9f, -111.5f);
|
|
|
|
[Header("Audio")]
|
|
public AudioMixerGroup outputMixerGroup;
|
|
|
|
private readonly List<TMP_Text> timeTmps = new List<TMP_Text>();
|
|
private readonly List<Text> timeTexts = new List<Text>();
|
|
|
|
private System.Text.StringBuilder _sb = new System.Text.StringBuilder(32);
|
|
private int _lastSeconds = -1;
|
|
private int _lastTotalSeconds = -1;
|
|
|
|
private RectTransform musicRoot;
|
|
private bool hasExplicitMusicRoot = false;
|
|
private RectTransform progressRect;
|
|
private float pointerBaseY = 0f;
|
|
private bool musicPicVisible = true;
|
|
private Coroutine musicPicTween;
|
|
private Coroutine lobbyShowRoutine;
|
|
private CanvasGroup musicPicGroup;
|
|
private RectTransform spectrumRoot;
|
|
|
|
private void Awake()
|
|
{
|
|
if (Instance != null && Instance != this)
|
|
{
|
|
Destroy(gameObject);
|
|
return;
|
|
}
|
|
Instance = this;
|
|
}
|
|
|
|
private string _cachedGameplaySceneName;
|
|
private bool _shouldHideSpectrumForCurrentScene;
|
|
private bool _spectrumHiddenForCurrentScene = false;
|
|
|
|
private void OnEnable()
|
|
{
|
|
SceneManager.sceneLoaded += OnSceneLoaded;
|
|
_cachedGameplaySceneName = gameplaySceneName;
|
|
_shouldHideSpectrumForCurrentScene = ShouldHideSpectrumInScene(SceneManager.GetActiveScene().name);
|
|
_spectrumHiddenForCurrentScene = false;
|
|
_buttonsBound = false;
|
|
Bind();
|
|
ApplyDefaultMusicPicVisibility(SceneManager.GetActiveScene().name);
|
|
if (Application.isPlaying)
|
|
{
|
|
var mgr = BgmPlaybackManager.EnsureInstance();
|
|
if (outputMixerGroup != null)
|
|
mgr.SetOutputMixerGroup(outputMixerGroup);
|
|
mgr.EnsurePlaying();
|
|
}
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
SceneManager.sceneLoaded -= OnSceneLoaded;
|
|
}
|
|
|
|
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
|
{
|
|
_shouldHideSpectrumForCurrentScene = ShouldHideSpectrumInScene(scene.name);
|
|
_spectrumHiddenForCurrentScene = false;
|
|
_buttonsBound = false;
|
|
Bind();
|
|
ApplyDefaultMusicPicVisibility(scene.name);
|
|
}
|
|
|
|
public void Bind()
|
|
{
|
|
musicRoot = null;
|
|
hasExplicitMusicRoot = false;
|
|
|
|
Canvas sceneCanvas = FindSceneCanvas();
|
|
var controller = SceneObjectLookupCache.FindAny<btmandtopController>();
|
|
if (controller != null && controller.bgmMixerGroup != null)
|
|
{
|
|
outputMixerGroup = controller.bgmMixerGroup;
|
|
if (Application.isPlaying)
|
|
{
|
|
var mgr = BgmPlaybackManager.Instance ?? BgmPlaybackManager.EnsureInstance();
|
|
mgr.SetOutputMixerGroup(outputMixerGroup);
|
|
}
|
|
}
|
|
|
|
if (controller != null && controller.musicPicRoot != null)
|
|
{
|
|
SetMusicRoot(controller.musicPicRoot, sceneCanvas);
|
|
return;
|
|
}
|
|
RectTransform persistentMusic = null;
|
|
var persistentCanvasGo = SceneObjectLookupCache.Find(musicPicCanvasName);
|
|
if (!keepMusicPicAcrossScenes && persistentCanvasGo != null)
|
|
{
|
|
if (Application.isPlaying)
|
|
Destroy(persistentCanvasGo);
|
|
else
|
|
DestroyImmediate(persistentCanvasGo);
|
|
persistentCanvasGo = null;
|
|
}
|
|
if (persistentCanvasGo != null)
|
|
{
|
|
var candidate = persistentCanvasGo.transform.Find(musicRootName);
|
|
if (candidate != null)
|
|
persistentMusic = candidate as RectTransform;
|
|
}
|
|
|
|
var candidates = FindAllMusicPic();
|
|
RectTransform sceneMusic = null;
|
|
var activeScene = SceneManager.GetActiveScene();
|
|
for (int i = 0; i < candidates.Count; i++)
|
|
{
|
|
var c = candidates[i];
|
|
if (c == null || c.gameObject.scene != activeScene)
|
|
continue;
|
|
if (sceneMusic == null)
|
|
sceneMusic = c;
|
|
if (c.GetComponentInParent<btmandtopController>(true) != null)
|
|
{
|
|
sceneMusic = c;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (persistentMusic != null)
|
|
musicRoot = persistentMusic;
|
|
else
|
|
musicRoot = sceneMusic;
|
|
|
|
hasExplicitMusicRoot = musicRoot != null;
|
|
|
|
if (candidates.Count > 1)
|
|
{
|
|
for (int i = 0; i < candidates.Count; i++)
|
|
{
|
|
var c = candidates[i];
|
|
if (c == null) continue;
|
|
if (c == musicRoot) continue;
|
|
if (Application.isPlaying)
|
|
Destroy(c.gameObject);
|
|
else
|
|
DestroyImmediate(c.gameObject);
|
|
}
|
|
}
|
|
|
|
if (musicRoot == null)
|
|
{
|
|
var canvas = SceneObjectLookupCache.FindAny<Canvas>();
|
|
if (canvas != null)
|
|
musicRoot = canvas.GetComponent<RectTransform>();
|
|
}
|
|
|
|
if (hasExplicitMusicRoot)
|
|
{
|
|
EnsureMusicPicCanvas(sceneCanvas);
|
|
EnsureMusicPicCanvasGroup();
|
|
if (Application.isPlaying && forceHideOnSceneLoad)
|
|
SetMusicPicVisible(false, true);
|
|
}
|
|
|
|
if (progressSlider == null && progressImage == null)
|
|
{
|
|
if (musicRoot != null)
|
|
{
|
|
var target = musicRoot.Find(progressName);
|
|
if (target != null)
|
|
{
|
|
progressSlider = target.GetComponent<Slider>();
|
|
progressImage = target.GetComponent<Image>();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (autoCreateProgress && progressSlider == null && progressImage == null && musicRoot != null)
|
|
{
|
|
var go = new GameObject(progressName, typeof(RectTransform), typeof(Image));
|
|
var rt = go.GetComponent<RectTransform>();
|
|
rt.SetParent(musicRoot, false);
|
|
rt.sizeDelta = defaultProgressSize;
|
|
rt.anchoredPosition = defaultProgressPosition;
|
|
var img = go.GetComponent<Image>();
|
|
img.type = Image.Type.Filled;
|
|
img.fillMethod = Image.FillMethod.Horizontal;
|
|
img.fillOrigin = 0;
|
|
img.fillAmount = 0f;
|
|
img.color = progressColor;
|
|
progressImage = img;
|
|
}
|
|
|
|
// If a progress bar exists outside MusicPic, ignore it and let cleanup remove it.
|
|
if (musicRoot != null)
|
|
{
|
|
if (progressSlider != null && !progressSlider.transform.IsChildOf(musicRoot))
|
|
progressSlider = null;
|
|
if (progressImage != null && !progressImage.transform.IsChildOf(musicRoot))
|
|
progressImage = null;
|
|
}
|
|
|
|
// Cleanup any BGM_Progress that isn't under MusicPic
|
|
CleanupProgressOutsideMusicRoot();
|
|
|
|
progressRect = null;
|
|
if (progressSlider != null) progressRect = progressSlider.GetComponent<RectTransform>();
|
|
if (progressRect == null && progressImage != null) progressRect = progressImage.rectTransform;
|
|
|
|
if (pointerRect == null)
|
|
{
|
|
Transform pointer = null;
|
|
if (musicRoot != null)
|
|
pointer = musicRoot.Find(pointerName);
|
|
if (pointer == null)
|
|
{
|
|
var go = FindByNameContains(pointerName);
|
|
if (go != null) pointer = go.transform;
|
|
}
|
|
if (pointer != null)
|
|
pointerRect = pointer.GetComponent<RectTransform>();
|
|
}
|
|
if (pointerRect != null)
|
|
{
|
|
pointerBaseY = pointerRect.anchoredPosition.y;
|
|
pointerRect.anchoredPosition = pointerStartPos;
|
|
pointerBaseY = pointerStartPos.y;
|
|
}
|
|
|
|
if (enableMusicPicGyro && musicRoot != null)
|
|
{
|
|
var gyro = musicRoot.GetComponent<BgmGyroRotator>();
|
|
if (gyro == null) gyro = musicRoot.gameObject.AddComponent<BgmGyroRotator>();
|
|
gyro.target = musicRoot;
|
|
}
|
|
|
|
BindButtons();
|
|
EnsureSpectrum();
|
|
CacheTimeTargets();
|
|
HideSpectrumInGameplay(SceneManager.GetActiveScene().name);
|
|
}
|
|
|
|
public void SetMusicRoot(RectTransform root, Canvas sceneCanvas = null)
|
|
{
|
|
musicRoot = root;
|
|
hasExplicitMusicRoot = musicRoot != null;
|
|
if (!hasExplicitMusicRoot)
|
|
return;
|
|
EnsureMusicPicCanvas(sceneCanvas);
|
|
EnsureMusicPicCanvasGroup();
|
|
EnsureSpectrum();
|
|
CacheTimeTargets();
|
|
}
|
|
|
|
private void CacheTimeTargets()
|
|
{
|
|
timeTmps.Clear();
|
|
timeTexts.Clear();
|
|
|
|
if (timeTmp != null) timeTmps.Add(timeTmp);
|
|
if (timeText != null) timeTexts.Add(timeText);
|
|
|
|
if (timeTmps.Count == 0 && timeTexts.Count == 0)
|
|
{
|
|
Transform timeRoot = null;
|
|
if (musicRoot != null)
|
|
{
|
|
var all = musicRoot.GetComponentsInChildren<Transform>(true);
|
|
for (int i = 0; i < all.Length; i++)
|
|
{
|
|
var t = all[i];
|
|
if (t == null) continue;
|
|
if (string.Equals(t.name, timeRootName, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
timeRoot = t;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (timeRoot == null)
|
|
{
|
|
var timeGo = SceneObjectLookupCache.Find(timeRootName);
|
|
if (timeGo != null) timeRoot = timeGo.transform;
|
|
}
|
|
|
|
if (timeRoot != null)
|
|
{
|
|
timeTmps.AddRange(timeRoot.GetComponentsInChildren<TMP_Text>(true));
|
|
timeTexts.AddRange(timeRoot.GetComponentsInChildren<Text>(true));
|
|
if (!timeRoot.gameObject.activeSelf)
|
|
timeRoot.gameObject.SetActive(true);
|
|
for (int i = 0; i < timeTmps.Count; i++)
|
|
{
|
|
if (timeTmps[i] != null && !timeTmps[i].gameObject.activeSelf)
|
|
timeTmps[i].gameObject.SetActive(true);
|
|
}
|
|
for (int i = 0; i < timeTexts.Count; i++)
|
|
{
|
|
if (timeTexts[i] != null && !timeTexts[i].gameObject.activeSelf)
|
|
timeTexts[i].gameObject.SetActive(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (timeTmps.Count == 0 && timeTexts.Count == 0)
|
|
{
|
|
var allTmps = Object.FindObjectsByType<TMP_Text>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
foreach (var t in allTmps)
|
|
{
|
|
if (t == null) continue;
|
|
if (t.name.ToUpper().Contains("TIME") || (t.text != null && t.text.ToUpper().Contains("TIME")))
|
|
{
|
|
timeTmps.Add(t);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (timeTmps.Count == 0 && timeTexts.Count == 0)
|
|
{
|
|
var allTexts = Object.FindObjectsByType<Text>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
foreach (var t in allTexts)
|
|
{
|
|
if (t == null) continue;
|
|
if (t.name.ToUpper().Contains("TIME") || (t.text != null && t.text.ToUpper().Contains("TIME")))
|
|
{
|
|
timeTexts.Add(t);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool _buttonsBound = false;
|
|
private string _cachedMusicRootNameNormalized;
|
|
|
|
private void Update()
|
|
{
|
|
if (!Application.isPlaying)
|
|
return;
|
|
|
|
if (_shouldHideSpectrumForCurrentScene && !_spectrumHiddenForCurrentScene)
|
|
{
|
|
HideSpectrumInGameplay(SceneManager.GetActiveScene().name);
|
|
_spectrumHiddenForCurrentScene = true;
|
|
}
|
|
|
|
if (!_buttonsBound)
|
|
{
|
|
BindButtons();
|
|
_buttonsBound = true;
|
|
}
|
|
|
|
if (useManualMusicToggle && musicToggleButton != null && Input.GetMouseButtonDown(0))
|
|
{
|
|
if (IsPointerOverButton(musicToggleButton))
|
|
ToggleMusicPic();
|
|
}
|
|
|
|
// keep spectrum alive if MusicPic gets rebuilt or moved
|
|
if (spectrumRoot == null && musicRoot != null)
|
|
{
|
|
EnsureSpectrum();
|
|
}
|
|
|
|
var mgr = BgmPlaybackManager.Instance;
|
|
if (mgr == null || !mgr.IsReady)
|
|
return;
|
|
|
|
float total = mgr.TotalTime;
|
|
float current = mgr.CurrentTime;
|
|
if (total <= 0.01f) return;
|
|
|
|
float t = Mathf.Clamp01(current / total);
|
|
if (progressSlider != null)
|
|
progressSlider.value = t;
|
|
if (progressImage != null)
|
|
progressImage.fillAmount = t;
|
|
|
|
UpdatePointer(t);
|
|
|
|
int curS = Mathf.FloorToInt(current);
|
|
int totS = Mathf.FloorToInt(total);
|
|
if (curS != _lastSeconds || totS != _lastTotalSeconds)
|
|
{
|
|
_lastSeconds = curS;
|
|
_lastTotalSeconds = totS;
|
|
|
|
_sb.Clear();
|
|
AppendTime(_sb, curS);
|
|
_sb.Append(" / ");
|
|
AppendTime(_sb, totS);
|
|
string timeStr = _sb.ToString();
|
|
|
|
for (int i = 0; i < timeTmps.Count; i++)
|
|
{
|
|
if (timeTmps[i] != null) timeTmps[i].text = timeStr;
|
|
}
|
|
for (int i = 0; i < timeTexts.Count; i++)
|
|
{
|
|
if (timeTexts[i] != null) timeTexts[i].text = timeStr;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void AppendTime(System.Text.StringBuilder sb, int totalSeconds)
|
|
{
|
|
int m = totalSeconds / 60;
|
|
int s = totalSeconds % 60;
|
|
if (m < 10) sb.Append('0');
|
|
sb.Append(m);
|
|
sb.Append(':');
|
|
if (s < 10) sb.Append('0');
|
|
sb.Append(s);
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if (musicRoot != null && spectrumRoot != null && enableMusicPicGyro)
|
|
spectrumRoot.localRotation = musicRoot.localRotation;
|
|
}
|
|
|
|
|
|
|
|
private void UpdatePointer(float t)
|
|
{
|
|
if (pointerRect == null || progressRect == null) return;
|
|
var parent = pointerRect.parent as RectTransform;
|
|
if (parent == null) return;
|
|
|
|
float x = Mathf.Lerp(pointerStartPos.x, pointerEndPos.x, t);
|
|
pointerRect.anchoredPosition = new Vector2(x + pointerOffset.x, pointerStartPos.y + pointerOffset.y);
|
|
}
|
|
|
|
private void CleanupProgressOutsideMusicRoot()
|
|
{
|
|
var all = Resources.FindObjectsOfTypeAll<RectTransform>();
|
|
for (int i = 0; i < all.Length; i++)
|
|
{
|
|
var rt = all[i];
|
|
if (rt == null) continue;
|
|
if (!string.Equals(rt.name, progressName, StringComparison.OrdinalIgnoreCase)) continue;
|
|
if (musicRoot != null && rt.transform.IsChildOf(musicRoot)) continue;
|
|
if (Application.isPlaying)
|
|
Destroy(rt.gameObject);
|
|
else
|
|
DestroyImmediate(rt.gameObject);
|
|
}
|
|
}
|
|
|
|
private void BindButtons()
|
|
{
|
|
if (prevButton == null) prevButton = FindButton(prevButtonName);
|
|
if (nextButton == null) nextButton = FindButton(nextButtonName);
|
|
if (pauseButton == null) pauseButton = FindButton(pauseButtonName);
|
|
if (musicToggleButton == null) musicToggleButton = FindButton(musicToggleButtonName);
|
|
useManualMusicToggle = musicToggleButton == null;
|
|
|
|
var mgr = BgmPlaybackManager.Instance ?? BgmPlaybackManager.EnsureInstance();
|
|
if (prevButton != null)
|
|
{
|
|
prevButton.onClick.RemoveAllListeners();
|
|
prevButton.onClick.AddListener(mgr.Previous);
|
|
}
|
|
if (nextButton != null)
|
|
{
|
|
nextButton.onClick.RemoveAllListeners();
|
|
nextButton.onClick.AddListener(mgr.Next);
|
|
}
|
|
if (pauseButton != null)
|
|
{
|
|
pauseButton.onClick.RemoveAllListeners();
|
|
pauseButton.onClick.AddListener(mgr.TogglePause);
|
|
}
|
|
if (musicToggleButton != null)
|
|
{
|
|
if (bindMusicToggleButton)
|
|
{
|
|
musicToggleButton.onClick.RemoveAllListeners();
|
|
musicToggleButton.onClick.AddListener(ToggleMusicPic);
|
|
}
|
|
}
|
|
}
|
|
|
|
private Button FindButton(string name)
|
|
{
|
|
if (string.IsNullOrEmpty(name)) return null;
|
|
var go = FindByNameContains(name);
|
|
if (go == null) return null;
|
|
return go.GetComponent<Button>();
|
|
}
|
|
|
|
private bool IsPointerOverButton(Button button)
|
|
{
|
|
if (button == null) return false;
|
|
RectTransform rect = button.GetComponent<RectTransform>();
|
|
if (rect == null)
|
|
rect = button.targetGraphic != null ? button.targetGraphic.rectTransform : null;
|
|
if (rect == null)
|
|
{
|
|
var graphics = button.GetComponentsInChildren<Graphic>(true);
|
|
rect = GetLargestRect(graphics);
|
|
}
|
|
if (rect == null) return false;
|
|
|
|
var canvas = rect.GetComponentInParent<Canvas>();
|
|
Camera cam = (canvas != null && canvas.renderMode != RenderMode.ScreenSpaceOverlay) ? canvas.worldCamera : null;
|
|
return RectTransformUtility.RectangleContainsScreenPoint(rect, Input.mousePosition, cam);
|
|
}
|
|
|
|
private RectTransform GetLargestRect(Graphic[] graphics)
|
|
{
|
|
if (graphics == null || graphics.Length == 0) return null;
|
|
RectTransform best = null;
|
|
float bestArea = 0f;
|
|
for (int i = 0; i < graphics.Length; i++)
|
|
{
|
|
var g = graphics[i];
|
|
if (g == null) continue;
|
|
var rt = g.rectTransform;
|
|
float area = Mathf.Abs(rt.rect.width * rt.rect.height);
|
|
if (area > bestArea)
|
|
{
|
|
bestArea = area;
|
|
best = rt;
|
|
}
|
|
}
|
|
return best;
|
|
}
|
|
|
|
private GameObject FindByNameContains(string name)
|
|
{
|
|
if (string.IsNullOrEmpty(name)) return null;
|
|
string target = name.Replace(" ", "");
|
|
var exact = SceneObjectLookupCache.Find(name);
|
|
if (exact != null) return exact;
|
|
var all = Object.FindObjectsByType<Transform>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
for (int i = 0; i < all.Length; i++)
|
|
{
|
|
var t = all[i];
|
|
if (t == null) continue;
|
|
if (!t.gameObject.scene.IsValid() || !t.gameObject.scene.isLoaded) continue;
|
|
var n = t.name.Replace(" ", "");
|
|
if (n.Contains(target))
|
|
return t.gameObject;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void EnsureSpectrum()
|
|
{
|
|
if (musicRoot == null)
|
|
{
|
|
var foundMusic = FindByNameContains(musicRootName);
|
|
if (foundMusic != null)
|
|
musicRoot = foundMusic.GetComponent<RectTransform>();
|
|
}
|
|
if (musicRoot == null)
|
|
{
|
|
CleanupSpectrumRoots(true);
|
|
return;
|
|
}
|
|
|
|
RectTransform existing = musicRoot.Find(spectrumRootName) as RectTransform;
|
|
var activeScene = SceneManager.GetActiveScene();
|
|
var all = Resources.FindObjectsOfTypeAll<RectTransform>();
|
|
List<RectTransform> found = new List<RectTransform>();
|
|
for (int i = 0; i < all.Length; i++)
|
|
{
|
|
var rt = all[i];
|
|
if (rt == null) continue;
|
|
if (!rt.gameObject.scene.IsValid() || rt.gameObject.scene != activeScene) continue;
|
|
if (!string.Equals(rt.name, spectrumRootName, StringComparison.OrdinalIgnoreCase)) continue;
|
|
found.Add(rt);
|
|
}
|
|
|
|
RectTransform preferred = null;
|
|
for (int i = 0; i < found.Count; i++)
|
|
{
|
|
var rt = found[i];
|
|
if (rt != null && rt.transform.IsChildOf(musicRoot))
|
|
{
|
|
preferred = rt;
|
|
break;
|
|
}
|
|
}
|
|
if (preferred == null && found.Count > 0)
|
|
preferred = found[0];
|
|
|
|
if (preferred != null)
|
|
{
|
|
if (preferred.parent != musicRoot)
|
|
preferred.SetParent(musicRoot, false);
|
|
existing = preferred;
|
|
}
|
|
|
|
if (existing == null)
|
|
{
|
|
var any = FindByNameContains(spectrumRootName);
|
|
if (any != null)
|
|
existing = any.transform as RectTransform;
|
|
}
|
|
if (existing == null)
|
|
{
|
|
var go = new GameObject(spectrumRootName, typeof(RectTransform));
|
|
var rt = go.GetComponent<RectTransform>();
|
|
rt.SetParent(musicRoot, false);
|
|
rt.sizeDelta = new Vector2(420f, 120f);
|
|
rt.anchoredPosition = spectrumPosition;
|
|
existing = rt;
|
|
}
|
|
else if (existing.parent != musicRoot)
|
|
{
|
|
existing.SetParent(musicRoot, false);
|
|
}
|
|
spectrumRoot = existing as RectTransform;
|
|
if (spectrumRoot != null)
|
|
{
|
|
spectrumRoot.localRotation = Quaternion.identity;
|
|
spectrumRoot.localScale = Vector3.one;
|
|
spectrumRoot.anchoredPosition = spectrumPosition;
|
|
spectrumRoot.gameObject.SetActive(true);
|
|
}
|
|
var viz = existing.GetComponent<BgmSpectrumVisualizer>();
|
|
if (viz == null)
|
|
viz = existing.gameObject.AddComponent<BgmSpectrumVisualizer>();
|
|
if (viz != null)
|
|
viz.enabled = true;
|
|
CleanupSpectrumRoots(false);
|
|
|
|
// If this scene should not show spectrum (e.g. gameplay or main menu), hide after ensuring.
|
|
HideSpectrumInGameplay(SceneManager.GetActiveScene().name);
|
|
}
|
|
|
|
private void EnsureMusicPicCanvas()
|
|
{
|
|
EnsureMusicPicCanvas(null);
|
|
}
|
|
|
|
private void EnsureMusicPicCanvas(Canvas sceneCanvas)
|
|
{
|
|
if (!keepMusicPicAcrossScenes || musicRoot == null)
|
|
return;
|
|
|
|
var currentCanvas = musicRoot.GetComponentInParent<Canvas>();
|
|
var persistent = SceneObjectLookupCache.Find(musicPicCanvasName);
|
|
Canvas persistentCanvas = null;
|
|
if (persistent == null)
|
|
{
|
|
var go = new GameObject(musicPicCanvasName, typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster));
|
|
persistentCanvas = go.GetComponent<Canvas>();
|
|
persistentCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
|
var scaler = go.GetComponent<CanvasScaler>();
|
|
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
|
scaler.referenceResolution = new Vector2(1920f, 1080f);
|
|
scaler.matchWidthOrHeight = 0.5f;
|
|
DontDestroyOnLoad(go);
|
|
persistent = go;
|
|
}
|
|
else
|
|
{
|
|
persistentCanvas = persistent.GetComponent<Canvas>();
|
|
}
|
|
|
|
var sourceCanvas = sceneCanvas != null ? sceneCanvas : currentCanvas;
|
|
if (sourceCanvas != null && persistentCanvas != null)
|
|
{
|
|
persistentCanvas.renderMode = sourceCanvas.renderMode;
|
|
persistentCanvas.worldCamera = sourceCanvas.worldCamera;
|
|
persistentCanvas.planeDistance = sourceCanvas.planeDistance;
|
|
persistentCanvas.sortingLayerID = sourceCanvas.sortingLayerID;
|
|
persistentCanvas.overrideSorting = true;
|
|
persistentCanvas.sortingOrder = sourceCanvas.sortingOrder + 50;
|
|
var srcScaler = sourceCanvas.GetComponent<CanvasScaler>();
|
|
var dstScaler = persistentCanvas.GetComponent<CanvasScaler>();
|
|
if (srcScaler != null && dstScaler != null)
|
|
{
|
|
dstScaler.uiScaleMode = srcScaler.uiScaleMode;
|
|
dstScaler.referenceResolution = srcScaler.referenceResolution;
|
|
dstScaler.matchWidthOrHeight = srcScaler.matchWidthOrHeight;
|
|
dstScaler.referencePixelsPerUnit = srcScaler.referencePixelsPerUnit;
|
|
}
|
|
}
|
|
|
|
if (musicRoot != null && musicRoot.transform.parent != persistent.transform)
|
|
musicRoot.SetParent(persistent.transform, false);
|
|
}
|
|
|
|
private Canvas FindSceneCanvas()
|
|
{
|
|
var canvases = Object.FindObjectsByType<Canvas>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
var activeScene = SceneManager.GetActiveScene();
|
|
for (int i = 0; i < canvases.Length; i++)
|
|
{
|
|
var c = canvases[i];
|
|
if (c == null) continue;
|
|
if (c.gameObject.scene != activeScene) continue;
|
|
if (c.name == musicPicCanvasName) continue;
|
|
return c;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void EnsureMusicPicCanvasGroup()
|
|
{
|
|
if (musicRoot == null)
|
|
return;
|
|
if (musicPicGroup == null)
|
|
musicPicGroup = musicRoot.GetComponent<CanvasGroup>();
|
|
if (musicPicGroup == null)
|
|
musicPicGroup = musicRoot.gameObject.AddComponent<CanvasGroup>();
|
|
musicRoot.SetAsLastSibling();
|
|
}
|
|
|
|
private void ApplyDefaultMusicPicVisibility(string sceneName)
|
|
{
|
|
bool shouldShow = false;
|
|
if (lobbyShowRoutine != null)
|
|
{
|
|
StopCoroutine(lobbyShowRoutine);
|
|
lobbyShowRoutine = null;
|
|
}
|
|
|
|
if (musicRoot != null && hasExplicitMusicRoot)
|
|
SetMusicPicVisible(shouldShow, true);
|
|
|
|
if (ShouldHideSpectrumInScene(sceneName))
|
|
{
|
|
CleanupSpectrumRoots(true);
|
|
HideSpectrumInGameplay(sceneName);
|
|
}
|
|
}
|
|
|
|
public void ToggleMusicPic()
|
|
{
|
|
if (musicRoot == null || !hasExplicitMusicRoot)
|
|
Bind();
|
|
if (musicRoot == null || !hasExplicitMusicRoot)
|
|
{
|
|
var go = FindByNameContains(musicRootName);
|
|
if (go != null)
|
|
{
|
|
musicRoot = go.GetComponent<RectTransform>();
|
|
hasExplicitMusicRoot = musicRoot != null;
|
|
}
|
|
}
|
|
if (musicRoot == null || !hasExplicitMusicRoot) return;
|
|
SetMusicPicVisible(!musicPicVisible, false);
|
|
}
|
|
|
|
public RectTransform GetSpectrumRoot()
|
|
{
|
|
return spectrumRoot;
|
|
}
|
|
|
|
private void SetMusicPicVisible(bool visible, bool instant)
|
|
{
|
|
if (musicRoot == null) return;
|
|
EnsureMusicPicCanvasGroup();
|
|
|
|
if (musicPicTween != null)
|
|
{
|
|
StopCoroutine(musicPicTween);
|
|
musicPicTween = null;
|
|
}
|
|
|
|
musicPicVisible = visible;
|
|
|
|
if (instant)
|
|
{
|
|
if (musicPicGroup != null)
|
|
{
|
|
musicPicGroup.alpha = visible ? 1f : 0f;
|
|
musicPicGroup.interactable = visible;
|
|
musicPicGroup.blocksRaycasts = visible;
|
|
}
|
|
musicRoot.gameObject.SetActive(visible);
|
|
if (!visible)
|
|
CleanupSpectrumRoots(true);
|
|
return;
|
|
}
|
|
|
|
musicRoot.gameObject.SetActive(true);
|
|
musicPicTween = StartCoroutine(FadeMusicPic(visible));
|
|
}
|
|
|
|
private System.Collections.IEnumerator FadeMusicPic(bool visibleAtEnd)
|
|
{
|
|
if (musicPicGroup == null)
|
|
yield break;
|
|
|
|
float start = musicPicGroup.alpha;
|
|
float target = visibleAtEnd ? 1f : 0f;
|
|
float t = 0f;
|
|
while (t < 1f)
|
|
{
|
|
float dt = useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
|
|
t += dt / Mathf.Max(0.0001f, musicPicFadeDuration);
|
|
float eased = Mathf.SmoothStep(0f, 1f, t);
|
|
musicPicGroup.alpha = Mathf.LerpUnclamped(start, target, eased);
|
|
yield return null;
|
|
}
|
|
musicPicGroup.alpha = target;
|
|
musicPicGroup.interactable = visibleAtEnd;
|
|
musicPicGroup.blocksRaycasts = visibleAtEnd;
|
|
if (!visibleAtEnd && musicRoot != null)
|
|
musicRoot.gameObject.SetActive(false);
|
|
if (!visibleAtEnd)
|
|
CleanupSpectrumRoots(true);
|
|
}
|
|
|
|
private void CleanupSpectrumRoots(bool disableOnly)
|
|
{
|
|
var all = Resources.FindObjectsOfTypeAll<RectTransform>();
|
|
for (int i = 0; i < all.Length; i++)
|
|
{
|
|
var rt = all[i];
|
|
if (rt == null) continue;
|
|
if (!string.Equals(rt.name, spectrumRootName, StringComparison.OrdinalIgnoreCase)) continue;
|
|
if (musicRoot != null && rt.transform.IsChildOf(musicRoot)) continue;
|
|
if (disableOnly)
|
|
{
|
|
rt.gameObject.SetActive(false);
|
|
}
|
|
else
|
|
{
|
|
if (Application.isPlaying)
|
|
Destroy(rt.gameObject);
|
|
else
|
|
DestroyImmediate(rt.gameObject);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HideSpectrumInGameplay(string sceneName)
|
|
{
|
|
bool shouldHide = ShouldHideSpectrumInScene(sceneName);
|
|
if (!shouldHide) return;
|
|
|
|
var all = Resources.FindObjectsOfTypeAll<RectTransform>();
|
|
for (int i = 0; i < all.Length; i++)
|
|
{
|
|
var rt = all[i];
|
|
if (rt == null) continue;
|
|
if (!string.Equals(rt.name, spectrumRootName, StringComparison.OrdinalIgnoreCase)) continue;
|
|
if (!rt.gameObject.scene.IsValid() || !rt.gameObject.scene.isLoaded) continue;
|
|
var viz = rt.GetComponent<BgmSpectrumVisualizer>();
|
|
if (viz != null) viz.enabled = false;
|
|
rt.gameObject.SetActive(false);
|
|
}
|
|
|
|
if (spectrumRoot != null)
|
|
{
|
|
var viz = spectrumRoot.GetComponent<BgmSpectrumVisualizer>();
|
|
if (viz != null) viz.enabled = false;
|
|
spectrumRoot.gameObject.SetActive(false);
|
|
}
|
|
}
|
|
|
|
private bool ShouldHideSpectrumInScene(string sceneName)
|
|
{
|
|
if (string.IsNullOrEmpty(sceneName))
|
|
return false;
|
|
|
|
if (string.Equals(sceneName, gameplaySceneName, StringComparison.OrdinalIgnoreCase))
|
|
return true;
|
|
|
|
if (hideSpectrumInMainScene && string.Equals(sceneName, mainSceneName, StringComparison.OrdinalIgnoreCase))
|
|
return true;
|
|
|
|
if (string.Equals(sceneName, beforeEverythingSceneName, StringComparison.OrdinalIgnoreCase))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
private System.Collections.IEnumerator ShowLobbyMusicPicNextFrame()
|
|
{
|
|
int tries = 0;
|
|
while (tries < 3)
|
|
{
|
|
yield return null;
|
|
if (musicRoot == null || !hasExplicitMusicRoot)
|
|
Bind();
|
|
|
|
if (musicRoot != null && hasExplicitMusicRoot)
|
|
break;
|
|
|
|
tries++;
|
|
}
|
|
|
|
if (musicRoot == null || !hasExplicitMusicRoot)
|
|
yield break;
|
|
|
|
EnsureSpectrum();
|
|
EnsureMusicPicCanvasGroup();
|
|
if (musicPicGroup != null)
|
|
musicPicGroup.alpha = 0f;
|
|
SetMusicPicVisible(true, false);
|
|
}
|
|
|
|
private List<RectTransform> FindAllMusicPic()
|
|
{
|
|
var list = new List<RectTransform>();
|
|
var all = Resources.FindObjectsOfTypeAll<RectTransform>();
|
|
for (int i = 0; i < all.Length; i++)
|
|
{
|
|
var rt = all[i];
|
|
if (rt == null) continue;
|
|
if (!rt.gameObject.scene.IsValid() || !rt.gameObject.scene.isLoaded) continue;
|
|
var n = rt.name.Replace(" ", "");
|
|
var target = musicRootName.Replace(" ", "");
|
|
if (n.IndexOf("Canvas", StringComparison.OrdinalIgnoreCase) >= 0)
|
|
continue;
|
|
|
|
bool match = n.Equals(target, StringComparison.OrdinalIgnoreCase) ||
|
|
n.StartsWith(target + "(", StringComparison.OrdinalIgnoreCase) ||
|
|
n.StartsWith(target + "_", StringComparison.OrdinalIgnoreCase);
|
|
if (match)
|
|
list.Add(rt);
|
|
}
|
|
return list;
|
|
}
|
|
}
|
|
|