using UnityEngine; using UnityEngine.UI; using TMPro; public class SongDetailsUI : MonoBehaviour { [Header("this_song_SO")] public ScriptableObject this_song_SO; [Header("basic UI")] public Image song_bgImage; public Text songNameText; public Text artistNameText; public Text painterNameText; public Text difficultyText; public Text difficultyDesciptionText; public Text charterNameText; public Text dlcNameText; public TextMeshProUGUI bpmText; public Text songSerialNumberText; public Text personalRecordText; // Documentation text normalized. public Text chartScoreText; public Text thisSong_progressText; public Text thisSong_lastScoreText; // will show last run total score if available public Text idolRecordText; public TextMeshProUGUI timeSpentText; public TextMeshProUGUI enterTimeText; public Text difficultyIdText; public Image progressImage; public GameObject progressNumberObject; public TextMeshProUGUI progressPercentText; public Image rankLevel_img; public RankConfig rc; //public Image songImage; public int id_of_thisSong; [Header("Inspector")] public GameObject picDetail; public Image profound_image; public Text detail_informations_text; [Header("Inspector")] public Button Button_EZ; public Button Button_HD; public Button Button_IN; public Button Button_IM; private SongData currentSong; void Start() { if (SongDataHolder.SelectedSongData != null) { // Documentation text normalized. currentSong = SongDataHolder.SelectedSongData; this_song_SO = currentSong; song_bgImage.sprite = currentSong.backgroudPIC; // Documentation text normalized. songNameText.text = currentSong.songName; artistNameText.text = currentSong.artistName; painterNameText.text = currentSong.painter; charterNameText.text = currentSong.level_creator; dlcNameText.text = currentSong.belongsTo_whichDLC; songSerialNumberText.text = currentSong.songID.ToString(); bpmText.text = "BPM : " + currentSong.bpm.ToString(); profound_image.sprite = currentSong.fullscreen_songPicture; if (timeSpentText != null) timeSpentText.text = "PlayTime: " + currentSong.time_totalPlayingTime.ToString("F0") + "s"; if (enterTimeText != null) enterTimeText.text = "PlayCount: " + currentSong.game_enterTimes.ToString(); id_of_thisSong = currentSong.songID; detail_informations_text.text = $"{currentSong.artistName}" + " - " + $"{currentSong.songName}" + " | " + $"曲绘: {currentSong.painter}" + " | " + $"制谱: {currentSong.level_creator}" + " | " + $"DLC: {currentSong.belongsTo_whichDLC}"; if (currentSong.illustration != null) { //songImage.sprite = currentSong.illustration; //songImage.enabled = true; } else { Debug.LogWarning("歌曲封面为空:" + currentSong.songName); } Debug.Log("加载歌曲数据: " + currentSong.songName); } else { // Documentation text normalized. } picDetail.SetActive(false); // Documentation text normalized. if (currentSong != null) { SetDifficultyButtons(currentSong.thisLevel_selectedDifficultyID); UpdateDifficultyUI(currentSong.thisLevel_selectedDifficultyID); Button_EZ.onClick.AddListener(() => OnDifficultySelected(0)); Button_HD.onClick.AddListener(() => OnDifficultySelected(1)); Button_IN.onClick.AddListener(() => OnDifficultySelected(2)); Button_IM.onClick.AddListener(() => OnDifficultySelected(3)); } } private void SetDifficultyButtons(int selectedDifficulty) { Button_EZ.image.color = new Color(1, 1, 1, selectedDifficulty == 0 ? 1 : 0); Button_HD.image.color = new Color(1, 1, 1, selectedDifficulty == 1 ? 1 : 0); Button_IN.image.color = new Color(1, 1, 1, selectedDifficulty == 2 ? 1 : 0); Button_IM.image.color = new Color(1, 1, 1, selectedDifficulty == 3 ? 1 : 0); } private void OnDifficultySelected(int difficulty) { if (currentSong != null) { currentSong.thisLevel_selectedDifficultyID = difficulty; SetDifficultyButtons(difficulty); UpdateDifficultyUI(difficulty); } } private void UpdateDifficultyUI(int difficulty) { var entry = GetChartEntry(difficulty); if (entry != null) { difficultyText.text = entry.difficultyLEVEL.ToString(); difficultyDesciptionText.text = entry.difficultyDescription; if (difficultyIdText != null) difficultyIdText.text = entry.difficultyLEVEL.ToString(); if (progressImage != null) progressImage.fillAmount = entry.levelProgressForThisDifficulty; UpdateProgressUI(entry.levelProgressForThisDifficulty); // read values from SongData (SO) int chartPersonal = currentSong.GetPersonalRecord(difficulty); // Documentation text normalized. int idol = currentSong.GetIdolRecord(difficulty); // Documentation text normalized. // Determine total: prefer stored total if present (>0), otherwise compute chartPersonal + idol int total; if (entry.totalPersonalRecordForThisDifficulty > 0) { total = entry.totalPersonalRecordForThisDifficulty; } else { total = chartPersonal + idol; } // show total (personalRecord) and idol separately personalRecordText.text = total.ToString(); if (idolRecordText != null) idolRecordText.text = idol.ToString(); // Documentation text normalized. if (chartScoreText != null) chartScoreText.text = chartPersonal.ToString(); // show last run total score if UI text provided if (thisSong_lastScoreText != null) { int lastRun = currentSong.GetChartScore(difficulty); thisSong_lastScoreText.text = lastRun.ToString(); } if (rankLevel_img != null && rc != null) rankLevel_img.sprite = rc.GetRankSprite(total); // also keep per-entry convenience fields in sync for inspector visibility entry.chartPersonalRecordForThisDifficulty = chartPersonal; entry.idolPersonalRecordForThisDifficulty = idol; entry.totalPersonalRecordForThisDifficulty = total; } else { difficultyText.text = difficulty.ToString(); if (difficultyIdText != null) difficultyIdText.text = difficulty.ToString(); if (progressImage != null) progressImage.fillAmount = 0f; UpdateProgressUI(0f); difficultyDesciptionText.text = ""; personalRecordText.text = "0"; if (idolRecordText != null) idolRecordText.text = "0"; if (chartScoreText != null) chartScoreText.text = "0"; if (thisSong_lastScoreText != null) thisSong_lastScoreText.text = "0"; if (rankLevel_img != null && rc != null) rankLevel_img.sprite = rc.defaultSprite; } } private void UpdateProgressUI(float progress) { // 1. Update Text (can exceed 100%) if (progressPercentText != null) { progressPercentText.text = Mathf.FloorToInt(progress * 100f).ToString() + "%"; } // 2. Clamp for visual elements (fillAmount and Object position) float clampedProgress = Mathf.Clamp01(progress); // Update fillAmount again just in case, though handled in caller if (progressImage != null) { progressImage.fillAmount = clampedProgress; } // 3. Update Object Position (Linear transformation: 0% -> -785, 100% -> -195) if (progressNumberObject != null) { RectTransform rect = progressNumberObject.GetComponent(); if (rect != null) { float targetX = Mathf.Lerp(-785f, -195f, clampedProgress); Vector2 anchoredPos = rect.anchoredPosition; anchoredPos.x = targetX; rect.anchoredPosition = anchoredPos; } } } private ChartFileEntry GetChartEntry(int difficulty) { foreach (var entry in currentSong.chartFiles) { if (entry.difficulty == difficulty) return entry; } return null; } }