diff --git a/Assets/Scripts/MiniGame/HuoShan/Language/ExpressionManager.cs b/Assets/Scripts/MiniGame/HuoShan/Language/ExpressionManager.cs index dc3d74b1c..4259c39de 100644 --- a/Assets/Scripts/MiniGame/HuoShan/Language/ExpressionManager.cs +++ b/Assets/Scripts/MiniGame/HuoShan/Language/ExpressionManager.cs @@ -31,6 +31,10 @@ namespace AibisDream [Header("Sprite 淡入淡出")] [SerializeField] private SpriteRenderer spriteRenderer; + [Header("Glitch 噪波效果")] + [Tooltip("噪波故障效果控制器,可选;置于 Expression View 子物体上")] + [SerializeField] private SpriteNoiseGlitchController glitchController; + void Start() { // 注册到系统字典 @@ -53,6 +57,11 @@ namespace AibisDream particleManager = GetComponentInChildren(true); } + if (glitchController == null) + { + glitchController = GetComponentInChildren(true); + } + // 注册相机 var virtualCam = transform.Find("Expression Camera")?.GetComponent(); if (virtualCam != null) @@ -112,6 +121,16 @@ namespace AibisDream StartSystem(phrasesList, targetSentence, completionNodeName); } + /// + /// 若火山释放 log 界面已淡出,则先淡入再返回(start_expression 时调用) + /// + /// 淡入时长(秒) + public IEnumerator EnsureReleaseLogFadedIn(float duration = 1f) + { + if (particleManager == null) yield break; + yield return particleManager.FadeInReleaseLogIfNeeded(duration); + } + /// /// 等待表达流程就绪(开场表现 + 火山表达panel 播完) /// @@ -194,6 +213,33 @@ namespace AibisDream spriteRenderer.gameObject.SetActive(false); } + /// + /// Glitch 噪波过渡:从当前强度平滑过渡到 to,不瞬移(类似 DOTween)。 + /// + public void TransitionGlitch(float to, float duration = 0f) + { + if (glitchController == null) return; + glitchController.TransitionTo(to, duration); + } + + /// + /// Glitch 噪波过渡并等待完成:从当前强度平滑过渡到 to。 + /// + public IEnumerator TransitionGlitchAndWait(float to, float duration = 0f) + { + if (glitchController == null) yield break; + yield return glitchController.StartCoroutine(glitchController.TransitionToAndWait(to, duration)); + } + + /// + /// Glitch 噪波过渡并等待完成:从当前强度平滑过渡到 to(from 忽略,保持丝滑连续)。 + /// + public IEnumerator TransitionGlitchAndWait(float from, float to, float duration) + { + if (glitchController == null) yield break; + yield return glitchController.StartCoroutine(glitchController.TransitionToAndWait(to, duration)); + } + private void OnDestroy() { CameraKit.Instance?.UnRegisterCamera(CameraEnum.Expression); diff --git a/Assets/Scripts/MiniGame/HuoShan/Language/LanguageParticleManager.cs b/Assets/Scripts/MiniGame/HuoShan/Language/LanguageParticleManager.cs index eab5ea5ed..707add50f 100644 --- a/Assets/Scripts/MiniGame/HuoShan/Language/LanguageParticleManager.cs +++ b/Assets/Scripts/MiniGame/HuoShan/Language/LanguageParticleManager.cs @@ -117,7 +117,7 @@ namespace AibisDream.MiniGame.Language [SerializeField] private GameObject languageDeepPanel1; [SerializeField] private GameObject languageDeepPanel2; [SerializeField] private Button focusSequenceButton; - [Tooltip("火山释放log界面,结束时会对其 SpriteRenderer 做淡出")] + [Tooltip("火山释放log界面,触发 focus 时对其 SpriteRenderer 做淡出,重新开始时恢复")] [SerializeField] private SpriteRenderer releaseLogSpriteRenderer; [Tooltip("开场表达panel Timeline 名称(DirectorName 或 DirectorName/AddressableKey),播完才算表达流程完成")] [SerializeField] private string expressionPanelTimelineName = "火山表达模块/火山表达panel"; @@ -974,6 +974,15 @@ namespace AibisDream.MiniGame.Language interferenceLogicSuspended = true; SetStatusUIVisibility(false, statusFadeOutDuration); + // 两个 panel、confirm button、火山释放 log 界面在 focus 触发时淡出 + FadeOutUIElement(languageDeepPanel1, focusFadeDuration); + FadeOutUIElement(languageDeepPanel2, focusFadeDuration); + if (focusSequenceButton != null) + { + FadeOutUIElement(focusSequenceButton.gameObject, focusFadeDuration); + } + FadeOutSpriteRenderer(releaseLogSpriteRenderer, focusFadeDuration); + if (connectionRenderer != null) { connectionRenderer.NonTargetAlphaScale = 0f; @@ -1234,15 +1243,6 @@ namespace AibisDream.MiniGame.Language } completionPhase = CompletionPhase.Finished; - - // languageDeepPanel1、languageDeepPanel2、button、火山释放log界面 一起淡出 - FadeOutUIElement(languageDeepPanel1, focusFadeDuration); - FadeOutUIElement(languageDeepPanel2, focusFadeDuration); - if (focusSequenceButton != null) - { - FadeOutUIElement(focusSequenceButton.gameObject, focusFadeDuration); - } - FadeOutSpriteRenderer(releaseLogSpriteRenderer, focusFadeDuration); } private Vector3 GetDynamicArrangementTarget(TargetFocusVisual visual, float arrangementProgress, float localTime) @@ -1330,6 +1330,39 @@ namespace AibisDream.MiniGame.Language }); } + /// + /// 若火山释放 log 界面已淡出,则淡入显示(start_expression 时调用,确保流程开始前界面可见) + /// + /// 淡入时长(秒) + public IEnumerator FadeInReleaseLogIfNeeded(float duration = 1f) + { + if (releaseLogSpriteRenderer == null) yield break; + if (releaseLogSpriteRenderer.gameObject.activeSelf && releaseLogSpriteRenderer.color.a > 0.9f) + yield break; // 已显示,跳过 + + DOTween.Kill(releaseLogSpriteRenderer); + releaseLogSpriteRenderer.enabled = true; + releaseLogSpriteRenderer.gameObject.SetActive(true); + Color c = releaseLogSpriteRenderer.color; + c.a = 0f; + releaseLogSpriteRenderer.color = c; + yield return releaseLogSpriteRenderer.DOFade(1f, duration).SetEase(Ease.OutQuad).WaitForCompletion(); + } + + /// + /// 恢复 SpriteRenderer 显示(用于重新开始时恢复火山释放 log 界面) + /// + private void RestoreSpriteRenderer(SpriteRenderer sr) + { + if (sr == null) return; + DOTween.Kill(sr); + sr.enabled = true; + sr.gameObject.SetActive(true); + Color c = sr.color; + c.a = 1f; + sr.color = c; + } + private Vector3 ComputeCentroid(List particles) { if (particles == null || particles.Count == 0) @@ -1448,6 +1481,9 @@ namespace AibisDream.MiniGame.Language if (languageDeepPanel2 != null) languageDeepPanel2.SetActive(false); + // 恢复火山释放 log 界面 SpriteRenderer(重新开始时恢复) + RestoreSpriteRenderer(releaseLogSpriteRenderer); + if (connectionRenderer != null) { connectionRenderer.NonTargetAlphaScale = lineAlphaMultiplier; diff --git a/Assets/Scripts/MiniGame/HuoShan/Language/LanguageYarnCommand.cs b/Assets/Scripts/MiniGame/HuoShan/Language/LanguageYarnCommand.cs index ed2387c9d..fcd26c6b1 100644 --- a/Assets/Scripts/MiniGame/HuoShan/Language/LanguageYarnCommand.cs +++ b/Assets/Scripts/MiniGame/HuoShan/Language/LanguageYarnCommand.cs @@ -40,6 +40,8 @@ namespace AibisDream.MiniGame.Language } } + // 若火山释放 log 界面已淡出,先淡入再开始流程 + yield return ExpressionManager.EnsureReleaseLogFadedIn(1f); ExpressionManager.StartSystem(phrases, targetSentence, completionNode); yield return ExpressionManager.WaitUntilExpressionFlowReady(); } @@ -94,46 +96,6 @@ namespace AibisDream.MiniGame.Language yield return ExpressionManager.StartCoroutine(ExpressionManager.ResolveFocusAndWait()); } - /// - /// 重新启动表达系统(会重置并使用新配置,相当于 close + open + start) - /// <> - /// - /// 干扰短句(笑话等),用 | 分隔 - /// 目标句子 - /// 完成时触发的对话节点(可选) - [YarnCommand("restart_expression")] - public static void RestartExpression(string anxietyPhrasesStr, string targetSentence, string completionNode = "") - { - if (ExpressionManager == null) - { - UnityEngine.Debug.LogError("ExpressionManager 未找到!"); - return; - } - - // 停止当前系统 - ExpressionManager.CloseView(); - - // 等一帧后重新启动 - UnityEngine.MonoBehaviour coroutineRunner = UnityEngine.Object.FindObjectOfType(); - if (coroutineRunner != null) - { - coroutineRunner.StartCoroutine(RestartExpressionCoroutine(anxietyPhrasesStr, targetSentence, completionNode)); - } - else - { - // 如果找不到 MonoBehaviour,直接启动 - ExpressionManager.OpenView(); - StartExpression(anxietyPhrasesStr, targetSentence, completionNode); - } - } - - private static IEnumerator RestartExpressionCoroutine(string anxietyPhrasesStr, string targetSentence, string completionNode) - { - yield return null; // 等一帧 - ExpressionManager.OpenView(); - StartExpression(anxietyPhrasesStr, targetSentence, completionNode); - } - /// /// 淡入 ExpressionManager 的 Sprite 图片 /// <> @@ -167,6 +129,37 @@ namespace AibisDream.MiniGame.Language } yield return ExpressionManager.StartCoroutine(ExpressionManager.FadeOutSpriteOverlay(duration)); } + + /// + /// Glitch 噪波过渡,等待完成后再继续下一步。 + /// <> -- 从 0 到 0.95,2 秒 + /// <> -- 立即到 0.95(duration 默认 0) + /// <> -- 从 0.3 到 0.45,1 秒 + /// + [YarnCommand("glitch_transition")] + public static IEnumerator GlitchTransition(float to, float duration = 0f) + { + if (ExpressionManager == null) + { + UnityEngine.Debug.LogError("ExpressionManager 未找到!"); + yield break; + } + yield return ExpressionManager.StartCoroutine(ExpressionManager.TransitionGlitchAndWait(to, duration)); + } + + /// + /// Glitch 噪波过渡(指定起止值),等待完成后再继续下一步。 + /// + [YarnCommand("glitch_transition")] + public static IEnumerator GlitchTransition(float from, float to, float duration) + { + if (ExpressionManager == null) + { + UnityEngine.Debug.LogError("ExpressionManager 未找到!"); + yield break; + } + yield return ExpressionManager.StartCoroutine(ExpressionManager.TransitionGlitchAndWait(from, to, duration)); + } } } diff --git a/Assets/Scripts/MiniGame/HuoShan/Language/README_语言系统使用说明.md b/Assets/Scripts/MiniGame/HuoShan/Language/README_语言系统使用说明.md index ab59aa2d2..947b6cc97 100644 --- a/Assets/Scripts/MiniGame/HuoShan/Language/README_语言系统使用说明.md +++ b/Assets/Scripts/MiniGame/HuoShan/Language/README_语言系统使用说明.md @@ -95,25 +95,6 @@ --- -### 5. 重新启动表达系统 `restart_expression` - -关闭当前系统并使用新配置重新启动,相当于 `close_expression` + `open_expression` + `start_expression`。 - -**语法:** -```yarn -<> -``` - -**参数说明:** 与 `open_expression` 相同 - -**示例:** -```yarn -// 切换到新的配置 -<> -``` - ---- - ## 完整使用流程示例 ```yarn @@ -175,8 +156,8 @@ title: Stage2 旁白:第二阶段:建立信心 -// 重新启动,使用新配置 -<> +// 切换新配置(视图已打开时复用 start_expression) +<> === @@ -185,8 +166,8 @@ title: Stage3 旁白:最终阶段:突破自我 -// 再次重新启动 -<> +// 再次切换配置 +<> ===