using System.Collections.Generic; using System.Linq; using UnityEngine; public class InGamePerformanceManager : MonoBehaviour { public static InGamePerformanceManager Instance { get; private set; } public int HighestComboThisRun { get; private set; } [Header("Inspector")] [Tooltip("Achievement definitions loaded from Resources.")] [SerializeField] private List achievementLibrary = new List(); [Header("Inspector")] public GameObject archievePrefab; public GameObject place_to_putdown; [System.Serializable] public class CategoryDisplayMapping { public AchievementCategory category; public GameObject parent; } public List categoryDisplays = new List(); private class UnlockedAchievementInfo { public AchievementLevel level; public InGameAchievementSO sourceSO; } private readonly Dictionary unlockedAchievements = new Dictionary(); private void Awake() { if (Instance == null) { Instance = this; HighestComboThisRun = 0; LoadAchievementLibrary(); } else { Destroy(gameObject); } } private void Start() { // 如果开启了自动打击模式,直接授予 Autoplay 成就 if (GameConfig.autoPlayEnabled) { CheckAutoplayAchievement(); } } private void CheckAutoplayAchievement() { // 查找属于 Autoplay 分类的配置 var autoplaySO = achievementLibrary.FirstOrDefault(a => a != null && a.category == AchievementCategory.Autoplay); if (autoplaySO != null && autoplaySO.levels != null && autoplaySO.levels.Count > 0) { // 自动打击模式下,直接解锁该分类下的第一个等级(观赏模式成就) var level = autoplaySO.levels[0]; unlockedAchievements.Clear(); // 确保排他性:只保留这一个成就 unlockedAchievements.Add(AchievementCategory.Autoplay, new UnlockedAchievementInfo { level = level, sourceSO = autoplaySO }); Debug.Log("[PerformanceManager] 自动打击模式已开启:锁定 Autoplay 成就,禁用其他成就。"); } } private void LoadAchievementLibrary() { achievementLibrary.Clear(); var loaded = Resources.LoadAll("Achievements"); if (loaded == null || loaded.Length == 0) loaded = Resources.LoadAll(string.Empty); if (loaded == null || loaded.Length == 0) { Debug.LogError("[PerformanceManager] No InGameAchievementSO found under Resources."); return; } for (int i = 0; i < loaded.Length; i++) { var so = loaded[i]; if (so != null && !achievementLibrary.Contains(so)) achievementLibrary.Add(so); } Debug.Log($"[PerformanceManager] Loaded {achievementLibrary.Count} achievement categories."); } public void UpdateCombo(int currentCombo) { if (currentCombo > HighestComboThisRun) { HighestComboThisRun = currentCombo; } CheckAchievementsByCategory(AchievementCategory.Combo, currentCombo); } public void UpdateTotalCure(float totalCure) { CheckAchievementsByCategory(AchievementCategory.TotalCure, totalCure); } public void UpdateTotalDamage(float totalDamage) { CheckAchievementsByCategory(AchievementCategory.TotalDamage, totalDamage); } public void UpdateTotalManaRestored(float totalMana) { CheckAchievementsByCategory(AchievementCategory.TotalManaRestored, totalMana); } public void UpdateTotalScore(float totalScore) { CheckAchievementsByCategory(AchievementCategory.TotalScore, totalScore); } private void CheckAchievementsByCategory(AchievementCategory category, float currentValue) { // 如果开启了自动打击模式,禁止获得除 Autoplay 以外的任何成就 if (GameConfig.autoPlayEnabled) { if (category != AchievementCategory.Autoplay) return; } if (achievementLibrary == null || achievementLibrary.Count == 0) return; var categorySOs = achievementLibrary.Where(a => a != null && a.category == category); foreach (var categorySO in categorySOs) { if (categorySO.levels == null || categorySO.levels.Count == 0) continue; var bestLevelForThisSO = categorySO.levels .Where(l => l != null && currentValue >= l.triggerValue) .OrderByDescending(l => l.triggerValue) .FirstOrDefault(); if (bestLevelForThisSO == null) continue; if (unlockedAchievements.TryGetValue(category, out var existingInfo)) { if (existingInfo == null || existingInfo.level == null || bestLevelForThisSO.triggerValue > existingInfo.level.triggerValue) { unlockedAchievements[category] = new UnlockedAchievementInfo { level = bestLevelForThisSO, sourceSO = categorySO }; } } else { unlockedAchievements.Add(category, new UnlockedAchievementInfo { level = bestLevelForThisSO, sourceSO = categorySO }); } } } public void LoadArchievePrefab() { if (archievePrefab == null) { Debug.LogWarning("[PerformanceManager] archievePrefab is not assigned."); return; } if (place_to_putdown != null) { foreach (Transform child in place_to_putdown.transform) Destroy(child.gameObject); } for (int i = 0; i < categoryDisplays.Count; i++) { var mapping = categoryDisplays[i]; if (mapping != null && mapping.parent != null) { foreach (Transform child in mapping.parent.transform) Destroy(child.gameObject); } } var sortedAchievements = unlockedAchievements.Values .Where(v => v != null && v.level != null) .OrderByDescending(info => (int)info.level.rarity) .ToList(); for (int i = 0; i < sortedAchievements.Count; i++) { var info = sortedAchievements[i]; var cat = info.sourceSO != null ? info.sourceSO.category : AchievementCategory.Combo; GameObject targetParent = place_to_putdown; var mapping = categoryDisplays.FirstOrDefault(m => m != null && m.category == cat && m.parent != null); if (mapping != null && mapping.parent != null) targetParent = mapping.parent; if (targetParent == null) continue; GameObject prefabToSpawn = (info.sourceSO != null && info.sourceSO.customPrefab != null) ? info.sourceSO.customPrefab : archievePrefab; GameObject go = Instantiate(prefabToSpawn, targetParent.transform); UI_OrderedEntryAnimator.PlayFadeOnly(go, i, 0.16f, 0.012f, true); var script = go.GetComponent(); if (script != null) script.Setup(info.level); } Debug.Log($"[PerformanceManager] Spawned {sortedAchievements.Count} achievement cards."); } }