diff --git a/Assets/Scripts/Framework/AudioKit/AudioManager.cs b/Assets/Scripts/Framework/AudioKit/AudioManager.cs index 406df7674..49ac3deb7 100644 --- a/Assets/Scripts/Framework/AudioKit/AudioManager.cs +++ b/Assets/Scripts/Framework/AudioKit/AudioManager.cs @@ -388,7 +388,7 @@ namespace AibisDream.Kit } } - public void PlaySfx(string eventName, string audioKey = null) + public void PlaySfx(string eventName, string audioKey = null, float pitch = 1f) { var eventPath = FormatEventPath(eventName); var key = string.IsNullOrEmpty(audioKey) ? eventName : audioKey; @@ -405,6 +405,11 @@ namespace AibisDream.Kit AddSfx(key, newSfx); } + if (!Mathf.Approximately(pitch, 1f)) + { + newSfx.setPitch(Mathf.Max(0.01f, pitch)); + } + newSfx.start(); } diff --git a/Assets/Scripts/MiniGame/Peipei/Eye/EyeSystem.cs b/Assets/Scripts/MiniGame/Peipei/Eye/EyeSystem.cs index 60bcecb30..16db7b18e 100644 --- a/Assets/Scripts/MiniGame/Peipei/Eye/EyeSystem.cs +++ b/Assets/Scripts/MiniGame/Peipei/Eye/EyeSystem.cs @@ -50,7 +50,17 @@ namespace AibisDream public EyeColorState GetCurrentColorState() => _currentState; - public float GetEffectTransitionDuration() => visualSettings.GetDurationForState(_currentState); + /// Eye/UF 演出倍速(默认见 Visual Tuning → Presentation Speed)。 + public float PresentationSpeed => Mathf.Max(0.01f, visualSettings != null ? visualSettings.presentationSpeed : 1f); + + public float ScaleDuration(float duration) => duration / PresentationSpeed; + + public float GetEffectTransitionDuration() => ScaleDuration(visualSettings.GetDurationForState(_currentState)); + + private void PlayPresentationSfx(string eventName) + { + AudioManager.Instance.PlaySfx(eventName, pitch: PresentationSpeed); + } /// 仅「可想象色彩」上色时眨眼;无 autoBlink / 失焦眨眼。 private bool ShouldBlinkForImagine() @@ -85,7 +95,8 @@ namespace AibisDream visualSettings, () => eyeStateEffect?.ApplyFocusedEffect(target, this), visualSettings.imagineEffectAtBlinkOpen, - visualSettings.imagineBlinkGap); + visualSettings.imagineBlinkGap, + PresentationSpeed); } else { @@ -97,6 +108,7 @@ namespace AibisDream private IEnumerator RunBlurOut(EyeTarget target, float duration) { + duration = ScaleDuration(duration); if (target != null) { target.BlurOut(duration); @@ -279,12 +291,12 @@ namespace AibisDream if (duration > 0.01f) { - AudioManager.Instance.PlaySfx("event:/ActionFB/visualturn"); + PlayPresentationSfx("event:/ActionFB/visualturn"); } mouseFollowAndZoom.MoveFocusTo( focusTransform, - duration, + ScaleDuration(duration), focusMinBounds, focusMaxBounds, GetFocusViewportSize()); @@ -404,7 +416,10 @@ namespace AibisDream [YarnCommand("EyeBlink")] public void EyeBlink(float duration = 0f) { - EnsureViewportOverlay()?.PlayBlink(duration > 0f ? duration : null, restartAutoBlinkAfter: true); + EnsureViewportOverlay()?.PlayBlink( + duration > 0f ? duration : null, + restartAutoBlinkAfter: true, + presentationSpeed: PresentationSpeed); } [YarnCommand("set_Eyetarget")] @@ -444,9 +459,10 @@ namespace AibisDream } const float focusMoveDuration = 1f; + float scaledFocusMove = ScaleDuration(focusMoveDuration); FocusOnTarget(target, focusMoveDuration); - yield return WaitForFocusMovement(focusMoveDuration); + yield return WaitForFocusMovement(scaledFocusMove); currentTarget = target; mouseFollowAndZoom.SetIndicatorTarget(currentTarget); @@ -483,7 +499,7 @@ namespace AibisDream yield break; } - AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine"); + PlayPresentationSfx("event:/ActionFB/color_imagine"); yield return RunFocusedEffectWithPreBlink(currentTarget); } @@ -501,7 +517,7 @@ namespace AibisDream yield break; } - AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine"); + PlayPresentationSfx("event:/ActionFB/color_imagine"); yield return RunUnfocusedEffect(currentTarget); } @@ -550,6 +566,7 @@ namespace AibisDream public IEnumerator Set_Saturation(float targetSaturation, float duration) { targetSaturation = Mathf.Clamp01(targetSaturation); + duration = ScaleDuration(duration); Sequence saturationSequence = DOTween.Sequence(); if (!TryJoinTargetSaturation(saturationSequence, targetSaturation, duration)) @@ -577,13 +594,14 @@ namespace AibisDream Debug.LogWarning("[EyeSystem] 无可用 EyeTarget Glitch tween。", this); } - yield return new WaitForSeconds(visualSettings.glitchInDuration); + yield return new WaitForSeconds(ScaleDuration(visualSettings.glitchInDuration)); } [YarnCommand("EyeGlitch_out")] public void EyeGlitch_out(float duration) { - TryStopUnifiedGlitch(duration > 0f ? duration : visualSettings.glitchOutDuration); + float resolved = duration > 0f ? duration : visualSettings.glitchOutDuration; + TryStopUnifiedGlitch(ScaleDuration(resolved)); } [YarnCommand("set_EyeColor")] @@ -614,11 +632,17 @@ namespace AibisDream memoryRender.sprite = memoryHandle.Result; memoryRender.gameObject.SetActive(true); + float fadeIn = ScaleDuration(1.5f); + float hold = ScaleDuration(1.5f); + float squeeze = ScaleDuration(2f); + float fadeOut = ScaleDuration(0.5f); + float fadeOutAt = fadeIn + hold + squeeze; + Sequence memorySequence = DOTween.Sequence(); - memorySequence.Append(memoryMaterial.DOFloat(0.85f, "_FullDistortionFade", 1.5f)); - memorySequence.AppendInterval(1.5f); - memorySequence.Append(memoryMaterial.DOFloat(0f, "_SqueezePower", 2f)); - memorySequence.Insert(4.5f, memoryMaterial.DOFloat(0f, "_FullDistortionFade", 0.5f).OnComplete(() => + memorySequence.Append(memoryMaterial.DOFloat(0.85f, "_FullDistortionFade", fadeIn)); + memorySequence.AppendInterval(hold); + memorySequence.Append(memoryMaterial.DOFloat(0f, "_SqueezePower", squeeze)); + memorySequence.Insert(fadeOutAt, memoryMaterial.DOFloat(0f, "_FullDistortionFade", fadeOut).OnComplete(() => { memoryRender.gameObject.SetActive(false); })); @@ -628,7 +652,7 @@ namespace AibisDream Sequence sequence = DOTween.Sequence(); - Sequence waveIn = CreateTargetRoundWaveSequence(1f, visualSettings.roundWaveInDuration); + Sequence waveIn = CreateTargetRoundWaveSequence(1f, ScaleDuration(visualSettings.roundWaveInDuration)); if (waveIn != null) { sequence.Append(waveIn); @@ -636,7 +660,7 @@ namespace AibisDream sequence.AppendCallback(() => { EyeGlitch_out(visualSettings.glitchOutDuration); }); - Sequence waveOut = CreateTargetRoundWaveSequence(0f, visualSettings.roundWaveOutDuration); + Sequence waveOut = CreateTargetRoundWaveSequence(0f, ScaleDuration(visualSettings.roundWaveOutDuration)); if (waveOut != null) { sequence.Append(waveOut); @@ -666,6 +690,7 @@ namespace AibisDream public Tween TweenUnifiedUfWeights(float ascii, float dream, float memory, float duration) { + duration = ScaleDuration(duration); Sequence sequence = DOTween.Sequence(); bool hasTween = false; @@ -710,7 +735,7 @@ namespace AibisDream foreach (EyeTarget target in targets) { - Sequence targetGlitch = target.StartUnifiedGlitch(visualSettings.glitchInDuration); + Sequence targetGlitch = target.StartUnifiedGlitch(ScaleDuration(visualSettings.glitchInDuration)); if (targetGlitch == null) { continue; diff --git a/Assets/Scripts/MiniGame/Peipei/Eye/EyeViewportOverlay.cs b/Assets/Scripts/MiniGame/Peipei/Eye/EyeViewportOverlay.cs index 17a0956b1..3f38636d1 100644 --- a/Assets/Scripts/MiniGame/Peipei/Eye/EyeViewportOverlay.cs +++ b/Assets/Scripts/MiniGame/Peipei/Eye/EyeViewportOverlay.cs @@ -180,7 +180,10 @@ namespace AibisDream } } - public Tween PlayBlink(float? totalDuration = null, bool restartAutoBlinkAfter = false) + public Tween PlayBlink( + float? totalDuration = null, + bool restartAutoBlinkAfter = false, + float presentationSpeed = 1f) { if (instanceMaterial == null || activeSettings == null) { @@ -189,11 +192,12 @@ namespace AibisDream blinkTween?.Kill(); - float closeDuration = activeSettings.blinkCloseDuration; - float openDuration = activeSettings.blinkOpenDuration; + float durationScale = 1f / Mathf.Max(0.01f, presentationSpeed); + float closeDuration = activeSettings.blinkCloseDuration * durationScale; + float openDuration = activeSettings.blinkOpenDuration * durationScale; if (totalDuration.HasValue) { - float total = Mathf.Max(0.05f, totalDuration.Value); + float total = Mathf.Max(0.05f, totalDuration.Value) * durationScale; closeDuration = total * 0.42f; openDuration = total * 0.58f; } @@ -221,7 +225,8 @@ namespace AibisDream EyeVisualSettings settings, System.Action onEffectStart, float effectAtOpenRatio, - float betweenBlinkGap = 0f) + float betweenBlinkGap = 0f, + float presentationSpeed = 1f) { if (!ShouldPlayTransitionBlink(settings)) { @@ -234,11 +239,12 @@ namespace AibisDream bool effectStarted = false; blinkCount = Mathf.Max(1, blinkCount); effectAtOpenRatio = Mathf.Clamp01(effectAtOpenRatio); + float durationScale = 1f / Mathf.Max(0.01f, presentationSpeed); for (int i = 0; i < blinkCount; i++) { bool isLastBlink = i == blinkCount - 1; - Tween blink = PlayBlink(); + Tween blink = PlayBlink(presentationSpeed: presentationSpeed); if (blink == null) { if (isLastBlink && !effectStarted) @@ -252,7 +258,8 @@ namespace AibisDream if (isLastBlink) { - float effectDelay = settings.blinkCloseDuration + settings.blinkOpenDuration * effectAtOpenRatio; + float effectDelay = (settings.blinkCloseDuration + settings.blinkOpenDuration * effectAtOpenRatio) + * durationScale; yield return new WaitForSeconds(effectDelay); if (!effectStarted) { @@ -267,7 +274,7 @@ namespace AibisDream yield return blink.WaitForCompletion(); if (betweenBlinkGap > 0f) { - yield return new WaitForSeconds(betweenBlinkGap); + yield return new WaitForSeconds(betweenBlinkGap * durationScale); } } } diff --git a/Assets/Scripts/MiniGame/Peipei/Eye/EyeVisualSettings.cs b/Assets/Scripts/MiniGame/Peipei/Eye/EyeVisualSettings.cs index e7edfd6d1..c58acbd20 100644 --- a/Assets/Scripts/MiniGame/Peipei/Eye/EyeVisualSettings.cs +++ b/Assets/Scripts/MiniGame/Peipei/Eye/EyeVisualSettings.cs @@ -16,6 +16,10 @@ namespace AibisDream [Tooltip("Focused / imagined color state.")] [Range(0f, 1f)] public float colorRevealMax = 1f; + [Header("Presentation Speed")] + [Tooltip("Eye/UF 演出整体倍速(等待、Tween、眨眼、关联 SFX pitch)。2.5 = 快 2.5 倍。")] + [Min(0.01f)] public float presentationSpeed = 2.5f; + [Header("Transition Duration (seconds)")] public float imagineColorDuration = 1f; public float cannotImagineDuration = 1f; diff --git a/Assets/Scripts/MiniGame/Peipei/UF/UFSystem.cs b/Assets/Scripts/MiniGame/Peipei/UF/UFSystem.cs index c601e51dc..aa3eafe82 100644 --- a/Assets/Scripts/MiniGame/Peipei/UF/UFSystem.cs +++ b/Assets/Scripts/MiniGame/Peipei/UF/UFSystem.cs @@ -40,6 +40,16 @@ public class UFSystem : MonoBehaviour memory } + private float PresentationSpeed => eyeSystem != null ? eyeSystem.PresentationSpeed : 1f; + + private float ScaleDuration(float duration) => + eyeSystem != null ? eyeSystem.ScaleDuration(duration) : duration; + + private void PlayPresentationSfx(string eventName) + { + AudioManager.Instance.PlaySfx(eventName, pitch: PresentationSpeed); + } + private void Awake() { FixSystemCenter.SystemDic.Register(this); @@ -87,10 +97,11 @@ public class UFSystem : MonoBehaviour [YarnCommand("UF_spriteIn")] public IEnumerator UF_spriteIn(float duration = 1.5f) { + duration = ScaleDuration(duration); var target = ResolveSpriteTarget(); if (target != null) { - AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine"); + PlayPresentationSfx("event:/ActionFB/color_imagine"); target.ImageIn(duration); } @@ -100,10 +111,11 @@ public class UFSystem : MonoBehaviour [YarnCommand("UF_spriteOut")] public IEnumerator UF_spriteOut(float duration = 1.5f) { + duration = ScaleDuration(duration); var target = ResolveSpriteTarget(); if (target != null) { - AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine"); + PlayPresentationSfx("event:/ActionFB/color_imagine"); target.ImageOut(duration); } @@ -113,6 +125,7 @@ public class UFSystem : MonoBehaviour [YarnCommand("UF_AllspriteIn")] public IEnumerator UF_AllspriteIn(float duration = 1.5f) { + duration = ScaleDuration(duration); foreach (EyeTarget target in eyeSystem.Targets) { target.ImageIn(duration); @@ -124,6 +137,7 @@ public class UFSystem : MonoBehaviour [YarnCommand("UF_AllspriteOut")] public IEnumerator UF_AllspriteOut(float duration = 1.5f) { + duration = ScaleDuration(duration); foreach (EyeTarget target in eyeSystem.Targets) { target.ImageOut(duration); @@ -146,6 +160,7 @@ public class UFSystem : MonoBehaviour Debug.LogWarning("[UFSystem] UF_faceIn: face.sprite 为空(可能是 aseprite 重导入后子资源 ID 失效)。", this); } + duration = ScaleDuration(duration); face.gameObject.SetActive(true); face.DOFade(1f, duration); yield return new WaitForSeconds(duration); @@ -159,6 +174,7 @@ public class UFSystem : MonoBehaviour yield break; } + duration = ScaleDuration(duration); face.DOFade(0f, duration); yield return new WaitForSeconds(duration); face.gameObject.SetActive(false); @@ -167,7 +183,8 @@ public class UFSystem : MonoBehaviour [YarnCommand("UF_ImaginationEffectIn")] public IEnumerator UF_ImaginationEffectIn(float duration = 1.5f) { - AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine"); + duration = ScaleDuration(duration); + PlayPresentationSfx("event:/ActionFB/color_imagine"); ClearUnifiedUfSpriteWeights(); TweenWeight(imageVolume, 1f, duration); yield return new WaitForSeconds(0f); @@ -176,15 +193,17 @@ public class UFSystem : MonoBehaviour [YarnCommand("UF_ImaginationEffectOut")] public IEnumerator UF_ImaginationEffectOut(float duration = 1.5f) { + duration = ScaleDuration(duration); TweenWeight(imageVolume, 0f, duration); - AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine"); + PlayPresentationSfx("event:/ActionFB/color_imagine"); yield return new WaitForSeconds(0f); } [YarnCommand("UF_MemoryEffectIn")] public IEnumerator UF_MemoryEffectIn(float duration = 1.5f) { - AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine"); + duration = ScaleDuration(duration); + PlayPresentationSfx("event:/ActionFB/color_imagine"); ClearUnifiedUfSpriteWeights(); TweenWeight(finalVolume, 1f, duration); yield return new WaitForSeconds(0f); @@ -193,15 +212,17 @@ public class UFSystem : MonoBehaviour [YarnCommand("UF_MemoryEffectOut")] public IEnumerator UF_MemoryEffectOut(float duration = 1.5f) { + duration = ScaleDuration(duration); TweenWeight(finalVolume, 0f, duration); - AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine"); + PlayPresentationSfx("event:/ActionFB/color_imagine"); yield return new WaitForSeconds(0f); } [YarnCommand("UF_EyeTargetAscillIn")] public IEnumerator UF_EyeTargetAscillIn(float duration = 1.5f) { - AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine"); + duration = ScaleDuration(duration); + PlayPresentationSfx("event:/ActionFB/color_imagine"); ClearUnifiedUfSpriteWeights(); TweenWeight(imageAscillVolume, 1f, duration); yield return new WaitForSeconds(0f); @@ -210,8 +231,9 @@ public class UFSystem : MonoBehaviour [YarnCommand("UF_EyeTargetAscillOut")] public IEnumerator UF_EyeTargetAscillOut(float duration = 1.5f) { + duration = ScaleDuration(duration); TweenWeight(imageAscillVolume, 0f, duration); - AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine"); + PlayPresentationSfx("event:/ActionFB/color_imagine"); yield return new WaitForSeconds(0f); } @@ -251,6 +273,7 @@ public class UFSystem : MonoBehaviour public void UF_fightEffect() { ClearUnifiedUfSpriteWeights(); + float loopDuration = ScaleDuration(1f); scaleTween = DOTween.To(() => 0f, t => { if (imageVolume != null) @@ -267,7 +290,7 @@ public class UFSystem : MonoBehaviour { finalVolume.weight = Mathf.Lerp(1f, 0f, t); } - }, 1f, 1f) + }, 1f, loopDuration) .SetEase(Ease.InOutSine) .SetLoops(-1, LoopType.Yoyo); } @@ -285,15 +308,15 @@ public class UFSystem : MonoBehaviour while (isLoopImage) { eyeSystem.StartCoroutine(eyeSystem.SetTargetCoroutine(eyeSystem.Targets[index].name, false)); - yield return new WaitForSeconds(0.5f); + yield return new WaitForSeconds(ScaleDuration(0.5f)); StartCoroutine(UF_spriteIn(0.5f)); StartCoroutine(UF_ImaginationEffectIn(0.5f)); - eyeSystem.Targets[index].ImageIn(0.5f); - yield return new WaitForSeconds(0.5f); + eyeSystem.Targets[index].ImageIn(ScaleDuration(0.5f)); + yield return new WaitForSeconds(ScaleDuration(0.5f)); StartCoroutine(UF_ImaginationEffectOut(0.5f)); StartCoroutine(UF_MemoryEffectIn(0.5f)); - yield return new WaitForSeconds(1f); - eyeSystem.Targets[index].ImageOut(0.5f); + yield return new WaitForSeconds(ScaleDuration(1f)); + eyeSystem.Targets[index].ImageOut(ScaleDuration(0.5f)); StartCoroutine(UF_MemoryEffectOut(0.5f)); index++; if (index >= eyeSystem.Targets.Count - 2) @@ -385,7 +408,8 @@ public class UFSystem : MonoBehaviour yield break; } - AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine"); + duration = ScaleDuration(duration); + PlayPresentationSfx("event:/ActionFB/color_imagine"); ClearUnifiedUfSpriteWeights(); switch (state)