技能主要更新,修复卡顿并加入动画,以及各种其他更新。

This commit is contained in:
FloatGaming
2026-02-07 21:05:17 +08:00
parent abeca51be5
commit 1ac3cd0104
1349 changed files with 1526749 additions and 24850 deletions
@@ -1,9 +1,10 @@
using UnityEngine;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using UnityEngine.SceneManagement;
using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
public class SongSelectUI : MonoBehaviour
{
@@ -13,12 +14,31 @@ public class SongSelectUI : MonoBehaviour
[SerializeField] Button button_Main;
[SerializeField] string ui_Main_Scene_Name = "UI_UI";
[Header("Enter Animation")]
[SerializeField] bool play_Enter_Anim = true;
[SerializeField] float enter_Anim_Delay = 0.05f;
[Header("Async Build")]
[SerializeField] bool useAsyncBuild = true;
[SerializeField] int buildBatch = 8;
[Header("Switch Animations")]
[SerializeField] bool play_Switch_Anim = true;
[SerializeField] RectTransform list_Anim_Root;
[SerializeField] float list_FadeOut_Time = 0.12f;
[SerializeField] float list_FadeIn_Time = 0.18f;
[SerializeField] float list_Move_Offset = 24f;
[SerializeField] Ease list_Move_Ease = Ease.OutCubic;
[SerializeField] bool list_Use_Unscaled = true;
// Current DLC key used for per-DLC saved song selection
public static string CurrentDlcKey = "dlc_default_0";
// Track pending restore to avoid multiple overlapping restores
private Coroutine restoreCoroutine;
private Coroutine buildCoroutine;
private Coroutine switchCoroutine;
private CanvasGroup listCanvasGroup;
private Vector2 listBasePos;
private bool listBaseCached;
void Start()
{
@@ -29,36 +49,201 @@ public class SongSelectUI : MonoBehaviour
}
button_Main.onClick.AddListener(
() => SceneManager.LoadScene(ui_Main_Scene_NAME(), LoadSceneMode.Single));
() => StartCoroutine(LoadSceneAsync(ui_Main_Scene_NAME())));
// Do not populate the song list at start. DLC buttons will request songs when clicked.
if (play_Enter_Anim)
{
UI_SelectSong_EnterAnim anim = GetComponent<UI_SelectSong_EnterAnim>();
if (anim == null)
{
anim = gameObject.AddComponent<UI_SelectSong_EnterAnim>();
}
anim.SetDelay(enter_Anim_Delay);
anim.Play();
}
}
private IEnumerator LoadSceneAsync(string sceneName)
{
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Single);
while (!asyncLoad.isDone)
{
yield return null;
}
}
// 显示所有歌曲 (kept for manual use)
public void DisplaySongs()
{
ClearSongList();
foreach (SongData song in songList.songs)
{
InstantiateSongButton(song);
}
if (restoreCoroutine != null) StopCoroutine(restoreCoroutine);
restoreCoroutine = StartCoroutine(RestoreSelectedSongNextFrame());
DisplaySongsFromList(songList != null ? songList.songs : null);
}
// Instantiate from a provided list (used by dlcButton to show DLC songs)
public void DisplaySongsFromList(List<SongData> list)
{
ClearSongList();
if (buildCoroutine != null)
{
StopCoroutine(buildCoroutine);
}
if (switchCoroutine != null)
{
StopCoroutine(switchCoroutine);
switchCoroutine = null;
}
if (play_Switch_Anim)
{
switchCoroutine = StartCoroutine(SwitchSongsRoutine(list));
}
else
{
buildCoroutine = StartCoroutine(BuildSongsAsync(list));
}
}
if (list == null) return;
private IEnumerator SwitchSongsRoutine(List<SongData> list)
{
yield return PlayListSwitchOut();
yield return BuildSongsAsync(list);
yield return PlayListSwitchIn();
switchCoroutine = null;
}
private IEnumerator BuildSongsAsync(List<SongData> list)
{
ClearSongList();
if (list == null)
{
buildCoroutine = null;
yield break;
}
// allow UI to render a frame before heavy instantiation
yield return null;
int count = 0;
foreach (var song in list)
{
InstantiateSongButton(song);
count++;
if (useAsyncBuild && buildBatch > 0 && (count % buildBatch) == 0)
{
yield return null;
}
}
// After populating, attempt to restore per-DLC selected song (next frame to avoid stale objects)
if (restoreCoroutine != null) StopCoroutine(restoreCoroutine);
restoreCoroutine = StartCoroutine(RestoreSelectedSongNextFrame());
buildCoroutine = null;
}
private RectTransform GetListAnimRoot()
{
if (list_Anim_Root != null)
{
return list_Anim_Root;
}
return contentPanel as RectTransform;
}
private CanvasGroup EnsureListCanvasGroup(RectTransform root)
{
if (root == null) return null;
if (listCanvasGroup == null || listCanvasGroup.gameObject != root.gameObject)
{
listCanvasGroup = root.GetComponent<CanvasGroup>();
if (listCanvasGroup == null)
{
listCanvasGroup = root.gameObject.AddComponent<CanvasGroup>();
}
}
return listCanvasGroup;
}
private void CacheListBase(RectTransform root)
{
if (root == null) return;
if (!listBaseCached)
{
listBasePos = root.anchoredPosition;
listBaseCached = true;
}
}
private IEnumerator PlayListSwitchOut()
{
if (!play_Switch_Anim)
{
yield break;
}
RectTransform root = GetListAnimRoot();
if (root == null)
{
yield break;
}
CacheListBase(root);
CanvasGroup cg = EnsureListCanvasGroup(root);
if (cg == null)
{
yield break;
}
root.DOKill();
cg.DOKill();
float moveOffset = list_Move_Offset;
if (root.GetComponent<LayoutGroup>() != null)
{
moveOffset = 0f;
}
Sequence seq = DOTween.Sequence().SetUpdate(list_Use_Unscaled);
seq.Join(cg.DOFade(0f, list_FadeOut_Time));
if (Mathf.Abs(moveOffset) > 0.01f)
{
seq.Join(root.DOAnchorPos(listBasePos + new Vector2(-moveOffset, 0f), list_FadeOut_Time).SetEase(list_Move_Ease));
}
yield return seq.WaitForCompletion();
}
private IEnumerator PlayListSwitchIn()
{
if (!play_Switch_Anim)
{
yield break;
}
RectTransform root = GetListAnimRoot();
if (root == null)
{
yield break;
}
CacheListBase(root);
CanvasGroup cg = EnsureListCanvasGroup(root);
if (cg == null)
{
yield break;
}
root.DOKill();
cg.DOKill();
float moveOffset = list_Move_Offset;
if (root.GetComponent<LayoutGroup>() != null)
{
moveOffset = 0f;
}
if (Mathf.Abs(moveOffset) > 0.01f)
{
root.anchoredPosition = listBasePos + new Vector2(moveOffset, 0f);
}
else
{
root.anchoredPosition = listBasePos;
}
cg.alpha = 0f;
Sequence seq = DOTween.Sequence().SetUpdate(list_Use_Unscaled);
seq.Join(cg.DOFade(1f, list_FadeIn_Time));
if (Mathf.Abs(moveOffset) > 0.01f)
{
seq.Join(root.DOAnchorPos(listBasePos, list_FadeIn_Time).SetEase(list_Move_Ease));
}
yield return seq.WaitForCompletion();
}
private IEnumerator RestoreSelectedSongNextFrame()
@@ -135,10 +320,25 @@ public class SongSelectUI : MonoBehaviour
GameObject songButtonObj = Instantiate(songButtonPrefab, contentPanel);
songButtonObj.transform.SetParent(contentPanel, false);
SongData sd = song;
if (SongDataLibrary.Instance != null && SongDataLibrary.Instance.IsLoaded)
{
sd = SongDataLibrary.Instance.GetSongDataByID(song.songID) ?? song;
}
int bestTotal = sd != null ? sd.personalRecord : song.personalRecord;
int bestDiff = -1;
string bestDiffName = "";
if (sd != null)
{
sd.GetAbsoluteHighestScore(out bestTotal, out bestDiff, out bestDiffName);
}
SongButton songButton = songButtonObj.GetComponent<SongButton>();
if (songButton != null)
{
songButton.SetButtonData(song.songName, song.personalRecord, song.difficultyID, song.illustration, song.songID);
songButton.thisSong_so = sd != null ? sd : song;
int diffForDisplay = bestDiff >= 0 ? bestDiff : song.difficultyID;
songButton.SetButtonData(song.songName, bestTotal, diffForDisplay, song.illustration, song.songID);
}
Image songImage = songButtonObj.GetComponentInChildren<Image>();
@@ -153,8 +353,15 @@ public class SongSelectUI : MonoBehaviour
if (texts.Length >= 4)
{
texts[0].text = song.songName;
texts[1].text = "Record : " + song.personalRecord;
texts[3].text = "" + song.difficultyID;
texts[1].text = "Record : " + bestTotal;
if (bestTotal <= 0)
{
texts[3].text = "";
}
else
{
texts[3].text = string.IsNullOrEmpty(bestDiffName) ? bestDiff.ToString() : bestDiffName;
}
texts[2].text = "SongID : " + song.songID.ToString();
}