using UnityEngine; using System.Collections; using System.Collections.Generic; using DarkTonic.MasterAudio; using DG.Tweening; /// /// 水晶雕像事件 - 继承CutsceneBase /// 管理三轮水晶雕像挑战的完整流程 /// public class CrystalStatueEvent : CutsceneBase { #region 配置 [Header("雕像预制体")] public GameObject crystalStatuePrefab; [Header("生成配置")] public int statueCount = 5; public float statueRadius = 3f; // 五角星排列半径 public float statueHeight = 0f; // 雕像高度 [Header("时间配置")] public float roundTimeLimit = 90f; // 每轮时间限制(秒) public float delayBetweenRounds = 3f; // 轮次间隔 [Header("音效配置")] public string audioRound1Intro = "1.5"; // 第一轮介绍 public string audioRound1Success = "1.7"; // 第一轮成功 public string audioRound2Intro = "1.8"; // 第二轮介绍 public string audioRound2Success = "1.9"; // 第二轮成功 public string audioRound3Intro = "1.10"; // 第三轮介绍 public string audioRound3Success = "1.11"; // 第三轮成功 public string audioFail = "1.6"; // 失败提示 public string audioCrystalBreak = "2.1"; // 水晶敲碎 public string audioSuccessEffect = "2.2"; // 成功音效 public string audioEvilLaugh = "2.3"; // 狞笑音效 [Header("场景配置")] public GameObject crystalWorldEnvironment; // 水晶世界环境 #endregion #region 状态 public enum CrystalEventState { None, SceneTransition, // 场景切换 Round1_Intro, // 第一轮介绍 Round1_Playing, // 第一轮进行中 Round1_Success, // 第一轮成功 Round1_Fail, // 第一轮失败 Round2_Intro, // 第二轮介绍 Round2_Playing, // 第二轮进行中 Round2_Success, // 第二轮成功 Round2_Fail, // 第二轮失败 Round3_Intro, // 第三轮介绍 Round3_Playing, // 第三轮进行中 Round3_Success, // 第三轮成功 Round3_Fail, // 第三轮失败 TimeUp, // 超时失败 Complete // 全部完成 } public CrystalEventState currentState = CrystalEventState.None; public int currentRound = 0; #endregion #region 私有变量 private List spawnedStatues = new List(); private CrystalStatue targetStatue; // 当前目标雕像 private float currentRoundTime; // 当前剩余时间 private bool isRoundActive; // 当前轮次是否激活 private bool isTimeUp; // 时间是否耗尽 private Coroutine roundTimerCoroutine; #endregion #region 实现抽象方法 public override void StartCutscene() { if (isPlaying) { Debug.LogWarning("[CrystalStatueEvent] 事件已在进行中"); return; } isPlaying = true; currentStep = 0; currentRound = 0; currentState = CrystalEventState.None; if (debugMode) Debug.Log("[CrystalStatueEvent] ========== 开始水晶雕像事件 =========="); // 进入雕像事件模式,切换道具 if (GameManager.Ins.playerRightHand != null) { GameManager.Ins.playerRightHand.EnterStatueEventMode(); } StartCoroutine(PlayEventSequence()); } public override string GetCurrentStateDescription() { return $"轮次{currentRound}: {currentState}, 剩余时间: {currentRoundTime:F1}秒"; } #endregion #region 事件流程 private IEnumerator PlayEventSequence() { // ========== 场景切换 ========== currentState = CrystalEventState.SceneTransition; currentStep = 1; if (debugMode) Debug.Log("[CrystalStatueEvent] 步骤1: 场景切换到水晶世界"); // 激活水晶世界环境 if (crystalWorldEnvironment != null) crystalWorldEnvironment.SetActive(true); // 播放BGM GameManager.Ins.PlayBGM(1); yield return new WaitForSeconds(1f); // ========== 第一轮:邪恶表情 ========== currentRound = 1; yield return StartCoroutine(PlayRound(1, CrystalStatue.StatueType.EvilFace, audioRound1Intro, audioRound1Success)); if (!isPlaying) yield break; // ========== 第二轮:恶毒双手 ========== currentRound = 2; yield return new WaitForSeconds(delayBetweenRounds); yield return StartCoroutine(PlayRound(2, CrystalStatue.StatueType.EvilHands, audioRound2Intro, audioRound2Success)); if (!isPlaying) yield break; // ========== 第三轮:嫉妒之心 ========== currentRound = 3; yield return new WaitForSeconds(delayBetweenRounds); yield return StartCoroutine(PlayRound(3, CrystalStatue.StatueType.JealousHeart, audioRound3Intro, audioRound3Success)); if (!isPlaying) yield break; // ========== 完成 ========== currentState = CrystalEventState.Complete; currentStep = 10; if (debugMode) Debug.Log("[CrystalStatueEvent] ========== 水晶雕像事件完成 =========="); // 清理雕像 CleanupStatues(); TriggerComplete(); } /// /// 执行一轮挑战 /// private IEnumerator PlayRound(int round, CrystalStatue.StatueType type, string introAudio, string successAudio) { // 设置状态 SetRoundState(round, CrystalEventState.Round1_Intro, CrystalEventState.Round2_Intro, CrystalEventState.Round3_Intro); // 生成雕像 SpawnStatuesForRound(round, type); // 播放介绍语音 PlayAudio2D(introAudio); if (debugMode) Debug.Log($"[CrystalStatueEvent] 第{round}轮开始: {type}"); // 等待介绍语音播放完成 yield return StartCoroutine(WaitForAudioComplete(introAudio, 10f)); // 额外等待一小段时间 yield return new WaitForSeconds(0.5f); // 开始游戏 SetRoundState(round, CrystalEventState.Round1_Playing, CrystalEventState.Round2_Playing, CrystalEventState.Round3_Playing); // 启动计时器 isRoundActive = true; isTimeUp = false; currentRoundTime = roundTimeLimit; roundTimerCoroutine = StartCoroutine(RoundTimer()); // 等待结果 bool roundComplete = false; bool roundSuccess = false; System.Action onRoundEnd = (success) => { roundComplete = true; roundSuccess = success; }; // 注册雕像碎裂回调 foreach (var statue in spawnedStatues) { statue.OnStatueBroken = (s, isTarget) => { if (isTarget) { // 击中目标,成功 onRoundEnd(true); } else { // 击中非目标,失败 onRoundEnd(false); } }; } // 等待玩家操作 yield return new WaitUntil(() => roundComplete || isTimeUp); // 停止计时器 if (roundTimerCoroutine != null) { StopCoroutine(roundTimerCoroutine); roundTimerCoroutine = null; } isRoundActive = false; // 处理结果 // 第三轮特殊处理:无论成功失败都结束事件 if (round == 3) { if (isTimeUp) { // 第三轮超时失败 currentState = CrystalEventState.TimeUp; yield return StartCoroutine(HandleTimeUp()); yield return StartCoroutine(WaitForAudioComplete(audioFail, 10f)); if (debugMode) Debug.Log("[CrystalStatueEvent] 第三轮超时失败,结束水晶雕像事件"); } else if (roundSuccess) { // 第三轮成功 currentState = CrystalEventState.Round3_Success; yield return StartCoroutine(AllStatuesDisappearExcept(null)); PlayAudio2D(successAudio); PlayAudio2D(audioSuccessEffect); if (debugMode) Debug.Log("[CrystalStatueEvent] 第三轮成功! 播放1.11语音"); yield return StartCoroutine(WaitForAudioComplete(successAudio, 10f)); } else { // 第三轮失败(击打错误) currentState = CrystalEventState.Round3_Fail; yield return StartCoroutine(HandleFailButContinue()); yield return StartCoroutine(WaitForAudioComplete(audioFail, 10f)); if (debugMode) Debug.Log("[CrystalStatueEvent] 第三轮失败,播放1.6语音,结束水晶雕像事件"); } // 第三轮结束,清理雕像并完成事件 CleanupStatues(); currentState = CrystalEventState.Complete; currentStep = 10; if (debugMode) Debug.Log("[CrystalStatueEvent] ========== 水晶雕像事件完成 =========="); TriggerComplete(); yield break; // 直接结束,不继续后续流程 } // 第一轮和第二轮的处理 if (isTimeUp) { // 超时失败 currentState = CrystalEventState.TimeUp; yield return StartCoroutine(HandleTimeUp()); // 等待失败语音播放完成后再进入下一轮 yield return StartCoroutine(WaitForAudioComplete(audioFail, 10f)); yield return new WaitForSeconds(0.5f); if (debugMode) Debug.Log($"[CrystalStatueEvent] 第{round}轮超时,进入下一轮"); } else if (roundSuccess) { // 成功 SetRoundState(round, CrystalEventState.Round1_Success, CrystalEventState.Round2_Success, CrystalEventState.Round3_Success); // 所有其他雕像消失 yield return StartCoroutine(AllStatuesDisappearExcept(null)); // 播放成功语音 PlayAudio2D(successAudio); PlayAudio2D(audioSuccessEffect); if (debugMode) Debug.Log($"[CrystalStatueEvent] 第{round}轮成功!"); // 等待成功语音播放完成后再进入下一轮 yield return StartCoroutine(WaitForAudioComplete(successAudio, 10f)); yield return new WaitForSeconds(0.5f); } else { // 失败(击打错误)- 播放失败提示,但仍进入下一轮 SetRoundState(round, CrystalEventState.Round1_Fail, CrystalEventState.Round2_Fail, CrystalEventState.Round3_Fail); yield return StartCoroutine(HandleFailButContinue()); // 等待失败语音播放完成后再进入下一轮 yield return StartCoroutine(WaitForAudioComplete(audioFail, 10f)); yield return new WaitForSeconds(0.5f); if (debugMode) Debug.Log($"[CrystalStatueEvent] 第{round}轮失败(击打错误),进入下一轮"); } // 清理雕像 CleanupStatues(); } /// /// 设置轮次状态 /// private void SetRoundState(int round, CrystalEventState state1, CrystalEventState state2, CrystalEventState state3) { switch (round) { case 1: currentState = state1; break; case 2: currentState = state2; break; case 3: currentState = state3; break; } } #endregion #region 计时器 private IEnumerator RoundTimer() { while (isRoundActive && currentRoundTime > 0) { currentRoundTime -= Time.deltaTime; // 更新UI(如果有) UpdateTimerUI(currentRoundTime); yield return null; } if (currentRoundTime <= 0) { isTimeUp = true; if (debugMode) Debug.Log("[CrystalStatueEvent] 时间耗尽!"); } } /// /// 等待音频播放完成 /// private IEnumerator WaitForAudioComplete(string audioName, float maxWaitTime = 10f) { float elapsedTime = 0f; // 等待音频开始播放 yield return new WaitForSeconds(0.1f); while (elapsedTime < maxWaitTime) { MasterAudioGroup audioGroup = MasterAudio.GrabGroup(audioName); if (audioGroup == null || audioGroup.ActiveVoices <= 0) { // 音频播放完成 if (debugMode) Debug.Log($"[CrystalStatueEvent] 音频 {audioName} 播放完成,耗时: {elapsedTime:F1}秒"); yield break; } elapsedTime += Time.deltaTime; yield return null; } if (debugMode) Debug.Log($"[CrystalStatueEvent] 音频 {audioName} 等待超时"); } /// /// 更新计时器UI(子类可重写) /// protected virtual void UpdateTimerUI(float remainingTime) { // TODO: 更新HUD倒计时显示 // HUDPanel.Ins.UpdateTimer(remainingTime); } #endregion #region 雕像生成 /// /// 为指定轮次生成雕像 /// private void SpawnStatuesForRound(int round, CrystalStatue.StatueType type) { CleanupStatues(); // 生成五角星排列的位置 Vector3[] positions = GeneratePentagramPositions(GameLocal.Ins.self.transform.position, statueRadius); // 随机选择目标位置 int targetIndex = Random.Range(0, statueCount); for (int i = 0; i < statueCount; i++) { Vector3 pos = positions[i]; pos.y = statueHeight; GameObject statueObj = Instantiate(crystalStatuePrefab, pos, Quaternion.identity); statueObj.name = $"CrystalStatue_{i}"; // 面向中心 statueObj.transform.LookAt(GameLocal.Ins.self.transform.position); statueObj.transform.eulerAngles = new Vector3(0, statueObj.transform.eulerAngles.y, 0); CrystalStatue statue = statueObj.GetComponent(); if (statue == null) { statue = statueObj.AddComponent(); } // 初始化雕像 bool isTarget = (i == targetIndex); statue.Initialize(type, isTarget); if (isTarget) { targetStatue = statue; if (debugMode) Debug.Log($"[CrystalStatueEvent] 目标雕像: 位置{i}"); } spawnedStatues.Add(statue); } if (debugMode) Debug.Log($"[CrystalStatueEvent] 生成{statueCount}个雕像, 类型: {type}"); } /// /// 生成五角星排列位置 /// private Vector3[] GeneratePentagramPositions(Vector3 center, float radius) { Vector3[] positions = new Vector3[statueCount]; for (int i = 0; i < statueCount; i++) { // 五角星角度,从顶部开始 float angle = i * (360f / statueCount) * Mathf.Deg2Rad - 90f * Mathf.Deg2Rad; positions[i] = center + new Vector3( Mathf.Cos(angle) * radius, 0, Mathf.Sin(angle) * radius ); } return positions; } #endregion #region 结果处理 /// /// 处理超时 /// private IEnumerator HandleTimeUp() { if (debugMode) Debug.Log("[CrystalStatueEvent] 处理超时失败"); // 所有雕像消失 yield return StartCoroutine(AllStatuesDisappear()); // 播放失败语音 PlayAudio2D(audioFail); } /// /// 处理失败 /// private IEnumerator HandleFail() { if (debugMode) Debug.Log("[CrystalStatueEvent] 处理失败"); // 所有雕像狞笑 foreach (var statue in spawnedStatues) { if (!statue.IsBroken()) { statue.PlayEvilLaugh(); } } // 播放狞笑音效 PlayAudio2D(audioEvilLaugh); yield return new WaitForSeconds(1f); // 所有雕像消失 yield return StartCoroutine(AllStatuesDisappear()); // 播放失败语音 PlayAudio2D(audioFail); } /// /// 处理失败但继续进入下一轮 /// private IEnumerator HandleFailButContinue() { if (debugMode) Debug.Log("[CrystalStatueEvent] 处理失败(继续下一轮)"); // 所有雕像狞笑 foreach (var statue in spawnedStatues) { if (!statue.IsBroken()) { statue.PlayEvilLaugh(); } } // 播放狞笑音效 PlayAudio2D(audioEvilLaugh); yield return new WaitForSeconds(1f); // 所有雕像消失 yield return StartCoroutine(AllStatuesDisappear()); // 播放失败提示语音 PlayAudio2D(audioFail); } /// /// 所有雕像消失 /// private IEnumerator AllStatuesDisappear() { foreach (var statue in spawnedStatues) { if (!statue.IsBroken()) { statue.ForceDisappear(0.5f); } } yield return new WaitForSeconds(0.6f); } /// /// 除指定雕像外所有雕像消失 /// private IEnumerator AllStatuesDisappearExcept(CrystalStatue exception) { foreach (var statue in spawnedStatues) { if (statue != exception && !statue.IsBroken()) { statue.ForceDisappear(0.5f); } } yield return new WaitForSeconds(0.6f); } #endregion #region 清理 /// /// 清理所有雕像 /// private void CleanupStatues() { foreach (var statue in spawnedStatues) { if (statue != null) { Destroy(statue.gameObject); } } spawnedStatues.Clear(); targetStatue = null; } public override void Cleanup() { CleanupStatues(); if (crystalWorldEnvironment != null) crystalWorldEnvironment.SetActive(false); // 退出雕像事件模式,恢复道具 if (GameManager.Ins.playerRightHand != null) { GameManager.Ins.playerRightHand.ExitStatueEventMode(); } base.Cleanup(); } #endregion #region 编辑器辅助 #if UNITY_EDITOR [ContextMenu("开始事件")] private void TestStartEvent() { StartCutscene(); } [ContextMenu("停止事件")] private void TestStopEvent() { StopCutscene(); } [ContextMenu("清理雕像")] private void TestCleanup() { CleanupStatues(); } [ContextMenu("测试:生成第一轮雕像")] private void TestSpawnRound1() { SpawnStatuesForRound(1, CrystalStatue.StatueType.EvilFace); } [ContextMenu("测试:生成第二轮雕像")] private void TestSpawnRound2() { SpawnStatuesForRound(2, CrystalStatue.StatueType.EvilHands); } [ContextMenu("测试:生成第三轮雕像")] private void TestSpawnRound3() { SpawnStatuesForRound(3, CrystalStatue.StatueType.JealousHeart); } #endif #endregion }