using System; using System.Collections; using UnityEngine; using AibisDream; using AibisDream.FixSystem; using UnityEngine.Rendering; using Yarn.Unity; using DG.Tweening; using VolFx; using AibisDream.Kit; public class UFSystem : MonoBehaviour { private GameObject _UFCover; private GameObject _UAudioule; private EyeSystem eyeSystem; public GameObject UFPanel; public SpriteRenderer face; private bool isLoopImage; [Header("Global UF Cover")] [SerializeField] private Volume FullAscillVolume; [Header("Target Post-Processing Volumes")] [SerializeField] private Volume imageAscillVolume; [SerializeField] private Volume imageVolume; [SerializeField] private Volume finalVolume; private AsciiVol ascii; private Tween scaleTween; public enum UFState { UF, imagination, 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); eyeSystem = FindObjectOfType(); ClearUnifiedUfSpriteWeights(); } public void TweenWeight(Volume postProcessingVolume, float targetWeight, float duration) { if (postProcessingVolume == null) { return; } DOTween.To(() => postProcessingVolume.weight, x => postProcessingVolume.weight = x, targetWeight, duration); } private void ClearUnifiedUfSpriteWeights() { eyeSystem?.SetUnifiedUfWeights(0f, 0f, 0f); } private EyeTarget ResolveSpriteTarget() { if (eyeSystem == null) { return null; } if (eyeSystem.CurrentTarget != null) { return eyeSystem.CurrentTarget; } if (YarnVariableStorage.Instance != null && YarnVariableStorage.Instance.TryGetValue("$currentEyeTarget", out string targetName) && !string.IsNullOrEmpty(targetName)) { return eyeSystem.FindEyeTargetByName(targetName); } return null; } [YarnCommand("UF_spriteIn")] public IEnumerator UF_spriteIn(float duration = 1.5f) { duration = ScaleDuration(duration); var target = ResolveSpriteTarget(); if (target != null) { PlayPresentationSfx("event:/ActionFB/color_imagine"); target.ImageIn(duration); } yield return new WaitForSeconds(duration); } [YarnCommand("UF_spriteOut")] public IEnumerator UF_spriteOut(float duration = 1.5f) { duration = ScaleDuration(duration); var target = ResolveSpriteTarget(); if (target != null) { PlayPresentationSfx("event:/ActionFB/color_imagine"); target.ImageOut(duration); } yield return new WaitForSeconds(duration); } [YarnCommand("UF_AllspriteIn")] public IEnumerator UF_AllspriteIn(float duration = 1.5f) { duration = ScaleDuration(duration); foreach (EyeTarget target in eyeSystem.Targets) { target.ImageIn(duration); } yield return new WaitForSeconds(duration); } [YarnCommand("UF_AllspriteOut")] public IEnumerator UF_AllspriteOut(float duration = 1.5f) { duration = ScaleDuration(duration); foreach (EyeTarget target in eyeSystem.Targets) { target.ImageOut(duration); } yield return new WaitForSeconds(duration); } [YarnCommand("UF_faceIn")] public IEnumerator UF_faceIn(float duration = 1.5f) { if (face == null) { Debug.LogWarning("[UFSystem] UF_faceIn: face SpriteRenderer 未绑定。", this); yield break; } if (face.sprite == null) { 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); } [YarnCommand("UF_faceOut")] public IEnumerator UF_faceOut(float duration = 1.5f) { if (face == null) { yield break; } duration = ScaleDuration(duration); face.DOFade(0f, duration); yield return new WaitForSeconds(duration); face.gameObject.SetActive(false); } [YarnCommand("UF_ImaginationEffectIn")] public IEnumerator UF_ImaginationEffectIn(float duration = 1.5f) { duration = ScaleDuration(duration); PlayPresentationSfx("event:/ActionFB/color_imagine"); ClearUnifiedUfSpriteWeights(); TweenWeight(imageVolume, 1f, duration); yield return new WaitForSeconds(0f); } [YarnCommand("UF_ImaginationEffectOut")] public IEnumerator UF_ImaginationEffectOut(float duration = 1.5f) { duration = ScaleDuration(duration); TweenWeight(imageVolume, 0f, duration); PlayPresentationSfx("event:/ActionFB/color_imagine"); yield return new WaitForSeconds(0f); } [YarnCommand("UF_MemoryEffectIn")] public IEnumerator UF_MemoryEffectIn(float duration = 1.5f) { duration = ScaleDuration(duration); PlayPresentationSfx("event:/ActionFB/color_imagine"); ClearUnifiedUfSpriteWeights(); TweenWeight(finalVolume, 1f, duration); yield return new WaitForSeconds(0f); } [YarnCommand("UF_MemoryEffectOut")] public IEnumerator UF_MemoryEffectOut(float duration = 1.5f) { duration = ScaleDuration(duration); TweenWeight(finalVolume, 0f, duration); PlayPresentationSfx("event:/ActionFB/color_imagine"); yield return new WaitForSeconds(0f); } [YarnCommand("UF_EyeTargetAscillIn")] public IEnumerator UF_EyeTargetAscillIn(float duration = 1.5f) { duration = ScaleDuration(duration); PlayPresentationSfx("event:/ActionFB/color_imagine"); ClearUnifiedUfSpriteWeights(); TweenWeight(imageAscillVolume, 1f, duration); yield return new WaitForSeconds(0f); } [YarnCommand("UF_EyeTargetAscillOut")] public IEnumerator UF_EyeTargetAscillOut(float duration = 1.5f) { duration = ScaleDuration(duration); TweenWeight(imageAscillVolume, 0f, duration); PlayPresentationSfx("event:/ActionFB/color_imagine"); yield return new WaitForSeconds(0f); } [YarnCommand("UF_SetBorkenValue")] public void UF_Borken(int value) { if (FullAscillVolume == null) { return; } if (!FullAscillVolume.gameObject.activeInHierarchy) { FullAscillVolume.gameObject.SetActive(true); } if (FullAscillVolume.profile.TryGet(out ascii)) { ascii.m_Depth.value = value; ascii.m_Ascii.value = Color.red; } } [YarnCommand("StartUFEffect_loop")] public void UFImageLoop() { StartCoroutine(UFImageLoopProcess()); } [YarnCommand("StopUFEffect_loop")] public void StopUFImageLoop() { isLoopImage = false; } [YarnCommand("UF_fightEffect")] public void UF_fightEffect() { ClearUnifiedUfSpriteWeights(); float loopDuration = ScaleDuration(1f); scaleTween = DOTween.To(() => 0f, t => { if (imageVolume != null) { imageVolume.weight = Mathf.Lerp(0f, 1f, t); } if (imageAscillVolume != null) { imageAscillVolume.weight = Mathf.Lerp(0f, 1f, t); } if (finalVolume != null) { finalVolume.weight = Mathf.Lerp(1f, 0f, t); } }, 1f, loopDuration) .SetEase(Ease.InOutSine) .SetLoops(-1, LoopType.Yoyo); } [YarnCommand("UF_StopfightEffect")] public void UF_StopfightEffect() { scaleTween?.Kill(); } public IEnumerator UFImageLoopProcess() { int index = 0; isLoopImage = true; while (isLoopImage) { eyeSystem.StartCoroutine(eyeSystem.SetTargetCoroutine(eyeSystem.Targets[index].name, false)); yield return new WaitForSeconds(ScaleDuration(0.5f)); StartCoroutine(UF_spriteIn(0.5f)); StartCoroutine(UF_ImaginationEffectIn(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(ScaleDuration(1f)); eyeSystem.Targets[index].ImageOut(ScaleDuration(0.5f)); StartCoroutine(UF_MemoryEffectOut(0.5f)); index++; if (index >= eyeSystem.Targets.Count - 2) { index = 0; } } } public void OpenUFView() { ClearUnifiedUfSpriteWeights(); // 先于 EyeSystem.OnEnter:UF 段 SwitchState / sprite 极密,禁止 autoBlink 与过渡眨眼 eyeSystem?.SetNonExplicitBlinkSuppressed(true); if (FullAscillVolume != null && !FullAscillVolume.gameObject.activeInHierarchy) { FullAscillVolume.gameObject.SetActive(true); } if (imageAscillVolume != null) { imageAscillVolume.weight = 1f; } if (imageVolume != null) { imageVolume.weight = 0f; } if (finalVolume != null) { finalVolume.weight = 0f; } } public void CloseUFView() { if (FullAscillVolume != null && FullAscillVolume.gameObject.activeInHierarchy) { FullAscillVolume.gameObject.SetActive(false); } if (imageAscillVolume != null) { imageAscillVolume.weight = 1f; } if (imageVolume != null) { imageVolume.weight = 0f; } if (finalVolume != null) { finalVolume.weight = 0f; } ClearUnifiedUfSpriteWeights(); eyeSystem?.SetNonExplicitBlinkSuppressed(false); } public void OpenCover() { var bodyModuleSystem = FixSystemCenter.SystemDic.Get(); _UFCover = bodyModuleSystem.FindBodyModuleByName("UF").transform.Find("Cover").gameObject; if (_UFCover.activeInHierarchy) { _UFCover.SetActive(false); } } public void RemoveUF() { var bodyModuleSystem = FixSystemCenter.SystemDic.Get(); _UAudioule = bodyModuleSystem.FindBodyModuleByName("UF").gameObject; if (_UAudioule.activeInHierarchy) { _UAudioule.SetActive(false); } } [YarnCommand("UF_SwitchState")] public IEnumerator SwitchState(string stateName, float duration) { if (!Enum.TryParse(stateName, true, out UFState state)) { Debug.LogError($"Invalid state name: {stateName}"); yield break; } duration = ScaleDuration(duration); PlayPresentationSfx("event:/ActionFB/color_imagine"); ClearUnifiedUfSpriteWeights(); switch (state) { case UFState.UF: TweenWeight(imageAscillVolume, 1f, duration); TweenWeight(imageVolume, 0f, duration); TweenWeight(finalVolume, 0f, duration); break; case UFState.imagination: TweenWeight(imageAscillVolume, 0f, duration); TweenWeight(imageVolume, 1f, duration); TweenWeight(finalVolume, 0f, duration); break; case UFState.memory: TweenWeight(imageAscillVolume, 0f, duration); TweenWeight(imageVolume, 0f, duration); TweenWeight(finalVolume, 1f, duration); break; default: Debug.LogError($"Unhandled state: {state}"); yield break; } yield return new WaitForSeconds(duration); } }