using UnityEngine; using System.Collections; public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour { public static Animation_GenerateJudgementSituationPrefab Instance; [Header("生成位置 (五个轨道)")] public GameObject redEffect; public GameObject greenEffect; public GameObject yellowEffect; public GameObject purpleEffect; public GameObject blueEffect; [Header("判定飘字 Prefabs")] public GameObject perfect_judge_prefab; public GameObject great_judge_prefab; public GameObject good_judge_prefab; public GameObject miss_judge_prefab; [Header("缩放与随机")] public float baseScale = 1.0f; public bool useRandomScale = true; public float minScaleMultiplier = 0.8f; public float maxScaleMultiplier = 1.2f; [Header("物理跳跃设置")] public float jumpForce = 5.0f; // 向上弹起的初始速度 public float gravity = -12.0f; // 重力 [Header("时间与透明度控制 (秒)")] public float fadeInTime = 0.1f; // 生成后多少秒完成渐显 (0->1) public float fadeOutStartTime = 0.6f; // 生成后第几秒开始渐隐 public float fadeOutDuration = 0.3f; // 渐隐动画持续时长 // Cache spawn transforms to avoid accessing destroyed GameObject references. private Transform redSpawn; private Transform greenSpawn; private Transform yellowSpawn; private Transform purpleSpawn; private Transform blueSpawn; private void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); } else if (Instance != this) { Destroy(gameObject); return; } CacheSpawnPoints(); } private void Start() { // Ensure spawn points are cached after all scene objects are initialized if (redSpawn == null && redEffect != null) { CacheSpawnPoints(); } } private void OnEnable() { // In case this object survives scene changes / references are assigned late. if (Instance == null) { Instance = this; } if (redSpawn == null && redEffect != null) { CacheSpawnPoints(); } } private void CacheSpawnPoints() { // Important: check Unity "fake null" before accessing .transform redSpawn = redEffect != null ? redEffect.transform : null; greenSpawn = greenEffect != null ? greenEffect.transform : null; yellowSpawn = yellowEffect != null ? yellowEffect.transform : null; purpleSpawn = purpleEffect != null ? purpleEffect.transform : null; blueSpawn = blueEffect != null ? blueEffect.transform : null; if (GameConfig.verboseLogs) { Debug.Log($"[Animation_Generate] Cached spawn points: red={redSpawn!=null}, green={greenSpawn!=null}, yellow={yellowSpawn!=null}, purple={purpleSpawn!=null}, blue={blueSpawn!=null}"); } } public void SpawnJudgePrefab(string color, string judgeResult) { if (string.IsNullOrEmpty(color)) { Debug.LogError("[Animation_Generate] SpawnJudgePrefab called with empty color!"); return; } if (string.IsNullOrEmpty(judgeResult)) { Debug.LogError("[Animation_Generate] SpawnJudgePrefab called with empty judgeResult!"); return; } Transform spawnPoint = GetSpawnPoint(color); if (spawnPoint == null) { Debug.LogError($"[Animation_Generate] Could not find spawn point for color: {color}"); return; } GameObject prefabToUse = GetJudgePrefab(judgeResult); if (prefabToUse == null) { Debug.LogError($"[Animation_Generate] Could not find judge prefab for result: {judgeResult}. Available: perfect={perfect_judge_prefab != null}, great={great_judge_prefab != null}, good={good_judge_prefab != null}, miss={miss_judge_prefab != null}"); return; } if (GameConfig.verboseLogs) Debug.Log($"[Animation_Generate] Spawning judge prefab: color={color}, result={judgeResult}, prefab={prefabToUse.name}"); GameObject instance = Instantiate(prefabToUse, spawnPoint); instance.transform.localPosition = Vector3.zero; // 处理缩放 float finalScale = baseScale; if (useRandomScale) finalScale *= Random.Range(minScaleMultiplier, maxScaleMultiplier); instance.transform.localScale = new Vector3(finalScale, finalScale, 1f); // 开启运动逻辑 StartCoroutine(AnimateSprite(instance)); } private IEnumerator AnimateSprite(GameObject obj) { if (obj == null) yield break; SpriteRenderer sr = obj.GetComponent(); float elapsed = 0f; float vVelocity = jumpForce; Vector3 currentLocalPos = Vector3.zero; // 计算总生命周期:开始渐隐的时间 + 渐隐持续的时长 float totalLifeTime = fadeOutStartTime + fadeOutDuration; // 初始透明度 if (sr != null) { Color c = sr.color; c.a = 0f; sr.color = c; } // 只要没到总寿命,就持续执行 while (elapsed < totalLifeTime) { if (obj == null) yield break; float dt = Time.deltaTime; elapsed += dt; // --- 1. 物理位移 --- vVelocity += gravity * dt; currentLocalPos.y += vVelocity * dt; obj.transform.localPosition = currentLocalPos; // --- 2. 透明度逻辑 (基于秒数) --- if (sr != null) { float alpha; // 渐显阶段:当前时间 < fadeInTime if (elapsed < fadeInTime) { alpha = Mathf.InverseLerp(0f, fadeInTime, elapsed); } // 渐隐阶段:当前时间 > fadeOutStartTime else if (elapsed > fadeOutStartTime) { // 在 fadeOutStartTime 到 totalLifeTime 之间从 1 变到 0 alpha = Mathf.InverseLerp(totalLifeTime, fadeOutStartTime, elapsed); } // 中间完全显示阶段 else { alpha = 1f; } Color c = sr.color; c.a = Mathf.Clamp01(alpha); sr.color = c; } yield return null; } // --- 确保最后一帧是完全透明的 --- if (obj != null && sr != null) { Color c = sr.color; c.a = 0f; sr.color = c; } // 等待渲染完成,防止闪删 yield return new WaitForEndOfFrame(); if (obj != null) Destroy(obj); } private Transform GetSpawnPoint(string color) { if (string.IsNullOrEmpty(color)) return null; // If references were destroyed (Unity fake null) try to rebuild cache once. if (redSpawn == null && greenSpawn == null && yellowSpawn == null && purpleSpawn == null && blueSpawn == null) { if (GameConfig.verboseLogs) Debug.Log("[Animation_Generate] Rebuilding spawn point cache"); CacheSpawnPoints(); } Transform point = null; switch (color.ToLower()) { case "red": point = redSpawn; break; case "green": point = greenSpawn; break; case "yellow": point = yellowSpawn; break; case "purple": point = purpleSpawn; break; case "blue": point = blueSpawn; break; default: Debug.LogWarning($"[Animation_Generate] Unknown color: {color}"); return null; } if (point == null) { Debug.LogError($"[Animation_Generate] Spawn point for color {color} is null. Check if effects are assigned in inspector. Make sure the effect object is active in the scene."); } return point; } private GameObject GetJudgePrefab(string result) { if (string.IsNullOrEmpty(result)) return null; GameObject prefab = null; switch (result.ToLower()) { case "perfect": prefab = perfect_judge_prefab; break; case "great": prefab = great_judge_prefab; break; case "good": prefab = good_judge_prefab; break; case "miss": prefab = miss_judge_prefab; break; default: Debug.LogWarning($"[Animation_Generate] Unknown judge result: {result}"); return null; } if (prefab == null) { Debug.LogError($"[Animation_Generate] Judge prefab for '{result}' is not assigned in inspector! Check Animation_GenerateJudgementSituationPrefab component."); } return prefab; } }