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)