using UnityEngine; using UnityEngine.UI; using UnityEngine.SceneManagement; using System.Collections; using DG.Tweening; public class SongButton : MonoBehaviour { [Header("thisSong_so")] public ScriptableObject thisSong_so; [Header("展示的信息")] public Text songNameText; public Text multiNameText; public Text joinTime_and_dlcName_Text; public Text songOverallDescriptionText; public Text highestScoreText; public Text highestScoreDifficultyText; public Text difficultyIDText; public Text songIDText; public Image buttonImage; public Image scoreLevelImage; [Header("头图")] public Image profileImage; public int song_songSerialID; [Header("select mark")] public Image selected_boarder; public Image fade_image; [Header("计数百分比")] public float easePercent = 1f; public float ssPercent = 0.95f; public float sPercent = 0.9f; public float aPercent = 0.8f; public float bPercent = 0.7f; public float cPercent = 0.6f; public float dPercent = 0.5f; public float ePercent = 0.4f; public float fPercent = 0.3f; [Header("阶段图")] public Sprite easeSprite; public Sprite ssSprite; public Sprite sSprite; public Sprite aSprite; public Sprite bSprite; public Sprite cSprite; public Sprite dSprite; public Sprite eSprite; public Sprite fSprite; public Sprite ufSprite; [Header("Fade Image Settings")] public float minAlpha = 0f; public float maxAlpha = 1f; public float blinkDuration = 0.5f; private static SongButton currentSelected; private Coroutine fadeCoroutine; private Coroutine blinkCoroutine; public void Start() { if (selected_boarder != null) { Color c = selected_boarder.color; c.a = 0f; selected_boarder.color = c; } if (fade_image != null) { Color c = fade_image.color; c.a = 0f; fade_image.color = c; } } public void SetButtonData(string songName, int highestScore, int difficultyID, Sprite songSprite, int songID) { Debug.Log("SetButtonData 被调用, songID 参数: " + songID); var sd = SongDataLibrary.Instance != null ? SongDataLibrary.Instance.GetSongDataByID(songID) : null; if (sd != null) { if (songNameText != null) songNameText.text = sd.songName; if (multiNameText != null) multiNameText.text = "音乐:" + sd.artistName + " | 曲绘:" + sd.painter + " | 制谱:" + sd.level_creator; if (joinTime_and_dlcName_Text != null) { string join = string.IsNullOrEmpty(sd.thisLevel_addDateString) ? "未知" : sd.thisLevel_addDateString; string dlc = string.IsNullOrEmpty(sd.belongsTo_whichDLC) ? "未归档DLC" : sd.belongsTo_whichDLC; joinTime_and_dlcName_Text.text = "歌曲收录时间:" + join + " | " + "所属DLC:" + dlc; } if (songOverallDescriptionText != null) { songOverallDescriptionText.text = string.IsNullOrEmpty(sd.thisLevel_overallDescription) ? "暂无歌曲简介。" : sd.thisLevel_overallDescription; } // Robust logic: compute best total across chartFiles if present int bestTotal = -1; int bestDiff = -1; if (sd.chartFiles != null && sd.chartFiles.Count > 0) { foreach (var entry in sd.chartFiles) { if (entry == null) continue; int total = 0; // prefer stored total if > 0 if (entry.totalPersonalRecordForThisDifficulty > 0) { total = entry.totalPersonalRecordForThisDifficulty; } else { // else compute from entry fields int p = entry.chartPersonalRecordForThisDifficulty; int i = entry.idolPersonalRecordForThisDifficulty; total = p + i; // as fallback also check SongData maps if (total == 0 && sd.personalRecordMap != null) { int pm = sd.personalRecordMap.ContainsKey(entry.difficulty) ? sd.personalRecordMap[entry.difficulty] : 0; int im = sd.idolRecordMap != null && sd.idolRecordMap.ContainsKey(entry.difficulty) ? sd.idolRecordMap[entry.difficulty] : 0; total = pm + im; } } if (bestDiff == -1 || total > bestTotal) { bestTotal = total; bestDiff = entry.difficulty; } } } // If still not found, fallback to maps if (bestDiff == -1) { if (sd.personalRecordMap != null) { foreach (var kvp in sd.personalRecordMap) { int diff = kvp.Key; int p = kvp.Value; int i = sd.GetIdolRecord(diff); int combined = p + i; if (bestDiff == -1 || combined > bestTotal) { bestTotal = combined; bestDiff = diff; } } } } // final fallback if (bestDiff == -1) { bestTotal = sd.personalRecord; bestDiff = sd.thisLevel_selectedDifficultyID; } if (bestTotal < 0) bestTotal = 0; if (highestScoreText != null) highestScoreText.text = bestTotal.ToString(); // Map difficulty index to label and set highestScoreDifficultyText as (Label) if (highestScoreDifficultyText != null) { string label = ""; switch (bestDiff) { case 0: label = "(Easy)"; break; case 1: label = "(Hard)"; break; case 2: label = "(Incredible)"; break; case 3: label = "(Impossible)"; break; default: label = ""; break; } highestScoreDifficultyText.text = label; } // Assign scoreLevelImage based on thresholds relative to 2,000,000 if (scoreLevelImage != null) { Sprite chosenSprite = null; float baseScore = 2000000f; // Evaluate from top to bottom thresholds if (bestTotal >= baseScore * easePercent && easeSprite != null) chosenSprite = easeSprite; else if (bestTotal >= baseScore * ssPercent && ssSprite != null) chosenSprite = ssSprite; else if (bestTotal >= baseScore * sPercent && sSprite != null) chosenSprite = sSprite; else if (bestTotal >= baseScore * aPercent && aSprite != null) chosenSprite = aSprite; else if (bestTotal >= baseScore * bPercent && bSprite != null) chosenSprite = bSprite; else if (bestTotal >= baseScore * cPercent && cSprite != null) chosenSprite = cSprite; else if (bestTotal >= baseScore * dPercent && dSprite != null) chosenSprite = dSprite; else if (bestTotal >= baseScore * ePercent && eSprite != null) chosenSprite = eSprite; else if (bestTotal >= baseScore * fPercent && fSprite != null) chosenSprite = fSprite; else if (ufSprite != null) chosenSprite = ufSprite; if (chosenSprite != null) scoreLevelImage.sprite = chosenSprite; } // Determine displayed difficulty: show the highest difficultyLEVEL present in chartFiles (if any) string diffDisplay = "0"; if (sd.chartFiles != null && sd.chartFiles.Count > 0) { float maxLevel = float.MinValue; foreach (var entry in sd.chartFiles) { if (entry == null) continue; if (entry.difficultyLEVEL > maxLevel) { maxLevel = entry.difficultyLEVEL; } } if (maxLevel != float.MinValue) { diffDisplay = maxLevel.ToString(); } } if (difficultyIDText != null) difficultyIDText.text = diffDisplay; if (buttonImage != null) buttonImage.sprite = sd.backgroudPIC; if (profileImage != null) { profileImage.sprite = sd.card_profileImage; if (sd.card_profileImage != null) { profileImage.color = new Color(profileImage.color.r, profileImage.color.g, profileImage.color.b, 1f); profileImage.enabled = true; } else { profileImage.enabled = false; } } song_songSerialID = songID; if (songIDText != null) songIDText.text = "数据库索引号:" + song_songSerialID.ToString(); } else { if (songNameText != null) songNameText.text = songName; if (highestScoreText != null) highestScoreText.text = "PR: " + highestScore.ToString(); if (difficultyIDText != null) difficultyIDText.text = difficultyID.ToString(); if (buttonImage != null) buttonImage.sprite = songSprite; song_songSerialID = songID; if (songIDText != null) songIDText.text = "Song ID: " + song_songSerialID.ToString(); } } public void OnSongButtonClick() { Debug.Log("点击按钮的 song_songSerialID: " + song_songSerialID); SongData selectedSong = SongDataLibrary.Instance.GetSongDataByID(song_songSerialID); if (selectedSong != null) { if (currentSelected != null && currentSelected != this) { currentSelected.FadeOutSelectedBorder(); } currentSelected = this; FadeInSelectedBorder(); SongDataHolder.SelectedSongData = selectedSong; var selectedInfo = FindObjectOfType(); if (selectedInfo != null) { selectedInfo.UpdateSelectedSongDisplay(); } // Save per-DLC selected song index to PlayerPrefs string dlcKey = SongSelectUI.CurrentDlcKey; if (string.IsNullOrEmpty(dlcKey)) dlcKey = "default_0"; string prefsKey = "song_selected_" + dlcKey; int index = GetIndexAmongSongButtons(); PlayerPrefs.SetInt(prefsKey, index); PlayerPrefs.Save(); Debug.Log($"SongButton: saved selected song index {index} for key {prefsKey}"); } else { Debug.LogError("未找到对应的 SongData, songID: " + song_songSerialID); } } private int GetIndexAmongSongButtons() { // Use parent traversal to find only SongButton siblings, to avoid mismatch when other UI children exist. var parent = transform.parent; if (parent == null) return 0; int idx = 0; for (int i = 0; i < parent.childCount; i++) { var child = parent.GetChild(i); var sb = child != null ? child.GetComponent() : null; if (sb == null) continue; if (sb == this) return idx; idx++; } return 0; } private void FadeInSelectedBorder() { if (selected_boarder != null) { if (fadeCoroutine != null) StopCoroutine(fadeCoroutine); fadeCoroutine = StartCoroutine(FadeImage(selected_boarder, selected_boarder.color.a, 1f, 0.3f)); } if (fade_image != null) { if (blinkCoroutine != null) StopCoroutine(blinkCoroutine); blinkCoroutine = StartCoroutine(BlinkFadeImage()); } } private void FadeOutSelectedBorder() { if (selected_boarder != null) { if (fadeCoroutine != null) StopCoroutine(fadeCoroutine); fadeCoroutine = StartCoroutine(FadeImage(selected_boarder, selected_boarder.color.a, 0f, 0.3f)); } if (fade_image != null) { if (blinkCoroutine != null) StopCoroutine(blinkCoroutine); fadeCoroutine = StartCoroutine(FadeImage(fade_image, fade_image.color.a, 0f, 0.3f)); } } private IEnumerator FadeImage(Image img, float startAlpha, float endAlpha, float duration) { if (img == null) yield break; float time = 0f; Color color = img.color; while (time < duration) { time += Time.deltaTime; float alpha = Mathf.Lerp(startAlpha, endAlpha, time / duration); color.a = alpha; img.color = color; yield return null; } color.a = endAlpha; img.color = color; } private IEnumerator BlinkFadeImage() { if (fade_image == null) yield break; Color color = fade_image.color; while (true) { float time = 0f; while (time < blinkDuration / 2f) { time += Time.deltaTime; float alpha = Mathf.Lerp(minAlpha, maxAlpha, time / (blinkDuration / 2f)); color.a = alpha; fade_image.color = color; yield return null; } time = 0f; while (time < blinkDuration / 2f) { time += Time.deltaTime; float alpha = Mathf.Lerp(maxAlpha, minAlpha, time / (blinkDuration / 2f)); color.a = alpha; fade_image.color = color; yield return null; } } } }