169 lines
5.6 KiB
C#
169 lines
5.6 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using TMPro;
|
|
using UnityEngine.SceneManagement;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
public class SongSelectUI : MonoBehaviour
|
|
{
|
|
public SongList songList; // 存储歌曲列表的 ScriptableObject
|
|
public GameObject songButtonPrefab; // 歌曲按钮的 Prefab (Button)
|
|
public Transform contentPanel; // 滚动视图的 Content 面板
|
|
|
|
[SerializeField] Button button_Main;
|
|
[SerializeField] string ui_Main_Scene_Name = "UI_UI";
|
|
|
|
// 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;
|
|
|
|
void Start()
|
|
{
|
|
if (songList == null || songButtonPrefab == null || contentPanel == null)
|
|
{
|
|
Debug.LogError("请在 Inspector 中分配所有字段!");
|
|
return;
|
|
}
|
|
|
|
button_Main.onClick.AddListener(
|
|
() => SceneManager.LoadScene(ui_Main_Scene_NAME(), LoadSceneMode.Single));
|
|
// Do not populate the song list at start. DLC buttons will request songs when clicked.
|
|
}
|
|
|
|
// 显示所有歌曲 (kept for manual use)
|
|
public void DisplaySongs()
|
|
{
|
|
ClearSongList();
|
|
|
|
foreach (SongData song in songList.songs)
|
|
{
|
|
InstantiateSongButton(song);
|
|
}
|
|
|
|
if (restoreCoroutine != null) StopCoroutine(restoreCoroutine);
|
|
restoreCoroutine = StartCoroutine(RestoreSelectedSongNextFrame());
|
|
}
|
|
|
|
// Instantiate from a provided list (used by dlcButton to show DLC songs)
|
|
public void DisplaySongsFromList(List<SongData> list)
|
|
{
|
|
ClearSongList();
|
|
|
|
if (list == null) return;
|
|
foreach (var song in list)
|
|
InstantiateSongButton(song);
|
|
|
|
// After populating, attempt to restore per-DLC selected song (next frame to avoid stale objects)
|
|
if (restoreCoroutine != null) StopCoroutine(restoreCoroutine);
|
|
restoreCoroutine = StartCoroutine(RestoreSelectedSongNextFrame());
|
|
}
|
|
|
|
private IEnumerator RestoreSelectedSongNextFrame()
|
|
{
|
|
// Wait one frame so Destroy() in ClearSongList fully completes and stale SongButtons are gone.
|
|
yield return null;
|
|
RestoreSelectedSongForCurrentDlc();
|
|
restoreCoroutine = null;
|
|
}
|
|
|
|
private void RestoreSelectedSongForCurrentDlc()
|
|
{
|
|
// read saved index using CurrentDlcKey
|
|
string dlcKey = (string.IsNullOrEmpty(CurrentDlcKey) ? "default_0" : CurrentDlcKey);
|
|
string key = "song_selected_" + dlcKey;
|
|
|
|
// collect song buttons under contentPanel
|
|
var allSongButtons = contentPanel.GetComponentsInChildren<SongButton>(true);
|
|
if (allSongButtons == null || allSongButtons.Length == 0)
|
|
{
|
|
Debug.LogWarning("SongSelectUI.RestoreSelectedSongForCurrentDlc: no song buttons found to restore selection");
|
|
return;
|
|
}
|
|
|
|
// Ensure every DLC has a default persisted value (0)
|
|
int savedIndex;
|
|
if (!PlayerPrefs.HasKey(key))
|
|
{
|
|
PlayerPrefs.SetInt(key, 0);
|
|
PlayerPrefs.Save();
|
|
savedIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
savedIndex = PlayerPrefs.GetInt(key, 0);
|
|
}
|
|
|
|
if (savedIndex < 0) savedIndex = 0;
|
|
if (savedIndex >= allSongButtons.Length) savedIndex = 0;
|
|
|
|
var btn = allSongButtons[savedIndex];
|
|
if (btn == null)
|
|
{
|
|
// hard fallback to first
|
|
btn = allSongButtons[0];
|
|
}
|
|
|
|
if (btn != null)
|
|
{
|
|
// simulate click
|
|
btn.OnSongButtonClick();
|
|
Debug.Log($"SongSelectUI: restored and clicked song index={savedIndex} for key={key}, totalButtons={allSongButtons.Length}");
|
|
}
|
|
}
|
|
|
|
private void ClearSongList()
|
|
{
|
|
if (contentPanel == null) return;
|
|
for (int i = contentPanel.childCount - 1; i >= 0; i--)
|
|
{
|
|
#if UNITY_EDITOR
|
|
if (!Application.isPlaying) DestroyImmediate(contentPanel.GetChild(i).gameObject);
|
|
else Destroy(contentPanel.GetChild(i).gameObject);
|
|
#else
|
|
Destroy(contentPanel.GetChild(i).gameObject);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
private void InstantiateSongButton(SongData song)
|
|
{
|
|
if (songButtonPrefab == null || contentPanel == null) return;
|
|
|
|
GameObject songButtonObj = Instantiate(songButtonPrefab, contentPanel);
|
|
songButtonObj.transform.SetParent(contentPanel, false);
|
|
|
|
SongButton songButton = songButtonObj.GetComponent<SongButton>();
|
|
if (songButton != null)
|
|
{
|
|
songButton.SetButtonData(song.songName, song.personalRecord, song.difficultyID, song.illustration, song.songID);
|
|
}
|
|
|
|
Image songImage = songButtonObj.GetComponentInChildren<Image>();
|
|
TMP_Text[] texts = songButtonObj.GetComponentsInChildren<TMP_Text>();
|
|
|
|
if (songImage != null && song.illustration != null)
|
|
{
|
|
songImage.sprite = song.illustration;
|
|
songImage.enabled = true;
|
|
}
|
|
|
|
if (texts.Length >= 4)
|
|
{
|
|
texts[0].text = song.songName;
|
|
texts[1].text = "Record : " + song.personalRecord;
|
|
texts[3].text = "" + song.difficultyID;
|
|
texts[2].text = "SongID : " + song.songID.ToString();
|
|
}
|
|
|
|
Button button = songButtonObj.GetComponent<Button>();
|
|
if (button != null && songButton != null)
|
|
button.onClick.AddListener(() => songButton.OnSongButtonClick());
|
|
}
|
|
|
|
// helper to avoid hardcoding scene name string in delegate - keeps serializer-friendly field
|
|
private string ui_Main_Scene_NAME() => ui_Main_Scene_Name;
|
|
}
|