feat(huoshan): 扩展火山语言系统与表情管理
This commit is contained in:
@@ -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<LanguageParticleManager>(true);
|
||||
}
|
||||
|
||||
if (glitchController == null)
|
||||
{
|
||||
glitchController = GetComponentInChildren<SpriteNoiseGlitchController>(true);
|
||||
}
|
||||
|
||||
// 注册相机
|
||||
var virtualCam = transform.Find("Expression Camera")?.GetComponent<ICinemachineCamera>();
|
||||
if (virtualCam != null)
|
||||
@@ -112,6 +121,16 @@ namespace AibisDream
|
||||
StartSystem(phrasesList, targetSentence, completionNodeName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 若火山释放 log 界面已淡出,则先淡入再返回(start_expression 时调用)
|
||||
/// </summary>
|
||||
/// <param name="duration">淡入时长(秒)</param>
|
||||
public IEnumerator EnsureReleaseLogFadedIn(float duration = 1f)
|
||||
{
|
||||
if (particleManager == null) yield break;
|
||||
yield return particleManager.FadeInReleaseLogIfNeeded(duration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 等待表达流程就绪(开场表现 + 火山表达panel 播完)
|
||||
/// </summary>
|
||||
@@ -194,6 +213,33 @@ namespace AibisDream
|
||||
spriteRenderer.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Glitch 噪波过渡:从当前强度平滑过渡到 to,不瞬移(类似 DOTween)。
|
||||
/// </summary>
|
||||
public void TransitionGlitch(float to, float duration = 0f)
|
||||
{
|
||||
if (glitchController == null) return;
|
||||
glitchController.TransitionTo(to, duration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Glitch 噪波过渡并等待完成:从当前强度平滑过渡到 to。
|
||||
/// </summary>
|
||||
public IEnumerator TransitionGlitchAndWait(float to, float duration = 0f)
|
||||
{
|
||||
if (glitchController == null) yield break;
|
||||
yield return glitchController.StartCoroutine(glitchController.TransitionToAndWait(to, duration));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Glitch 噪波过渡并等待完成:从当前强度平滑过渡到 to(from 忽略,保持丝滑连续)。
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 若火山释放 log 界面已淡出,则淡入显示(start_expression 时调用,确保流程开始前界面可见)
|
||||
/// </summary>
|
||||
/// <param name="duration">淡入时长(秒)</param>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复 SpriteRenderer 显示(用于重新开始时恢复火山释放 log 界面)
|
||||
/// </summary>
|
||||
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<CandidateParticle> 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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新启动表达系统(会重置并使用新配置,相当于 close + open + start)
|
||||
/// <<restart_expression "我好怕|怎么办|不行" "我能做到" "ExpressionCompleted">>
|
||||
/// </summary>
|
||||
/// <param name="anxietyPhrasesStr">干扰短句(笑话等),用 | 分隔</param>
|
||||
/// <param name="targetSentence">目标句子</param>
|
||||
/// <param name="completionNode">完成时触发的对话节点(可选)</param>
|
||||
[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<UnityEngine.MonoBehaviour>();
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 淡入 ExpressionManager 的 Sprite 图片
|
||||
/// <<expression_sprite_fade_in>>
|
||||
@@ -167,6 +129,37 @@ namespace AibisDream.MiniGame.Language
|
||||
}
|
||||
yield return ExpressionManager.StartCoroutine(ExpressionManager.FadeOutSpriteOverlay(duration));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Glitch 噪波过渡,等待完成后再继续下一步。
|
||||
/// <<glitch_transition 0.95 2>> -- 从 0 到 0.95,2 秒
|
||||
/// <<glitch_transition 0.95>> -- 立即到 0.95(duration 默认 0)
|
||||
/// <<glitch_transition 0.3 0.45 1>> -- 从 0.3 到 0.45,1 秒
|
||||
/// </summary>
|
||||
[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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Glitch 噪波过渡(指定起止值),等待完成后再继续下一步。
|
||||
/// </summary>
|
||||
[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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,25 +95,6 @@
|
||||
|
||||
---
|
||||
|
||||
### 5. 重新启动表达系统 `restart_expression`
|
||||
|
||||
关闭当前系统并使用新配置重新启动,相当于 `close_expression` + `open_expression` + `start_expression`。
|
||||
|
||||
**语法:**
|
||||
```yarn
|
||||
<<restart_expression "焦虑短句1|焦虑短句2|焦虑短句3" "目标句子" "完成对话节点">>
|
||||
```
|
||||
|
||||
**参数说明:** 与 `open_expression` 相同
|
||||
|
||||
**示例:**
|
||||
```yarn
|
||||
// 切换到新的配置
|
||||
<<restart_expression "害怕|恐惧|退缩" "勇往直前" "NextStage">>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 完整使用流程示例
|
||||
|
||||
```yarn
|
||||
@@ -175,8 +156,8 @@ title: Stage2
|
||||
|
||||
旁白:第二阶段:建立信心
|
||||
|
||||
// 重新启动,使用新配置
|
||||
<<restart_expression "做不到|太难了|放弃" "我能做到" "Stage3">>
|
||||
// 切换新配置(视图已打开时复用 start_expression)
|
||||
<<start_expression "做不到|太难了|放弃" "我能做到" "Stage3">>
|
||||
|
||||
===
|
||||
|
||||
@@ -185,8 +166,8 @@ title: Stage3
|
||||
|
||||
旁白:最终阶段:突破自我
|
||||
|
||||
// 再次重新启动
|
||||
<<restart_expression "不可能|不行|失败" "成功突破" "GameComplete">>
|
||||
// 再次切换配置
|
||||
<<start_expression "不可能|不行|失败" "成功突破" "GameComplete">>
|
||||
|
||||
===
|
||||
|
||||
|
||||
Reference in New Issue
Block a user