using System.Collections; using UnityEngine; using DG.Tweening; using Yarn.Unity; using AibisDream.Framework; using Cinemachine; using UnityEngine.Rendering; using AibisDream.Kit; using UnityEngine.ResourceManagement.AsyncOperations; namespace AibisDream.FixSystem { public class MemoryProcess : MonoBehaviour { private const string MemorySpritePath = "Sprite/Memory/{0}.png"; private const float FadeMaterialStartValue = -15f; private const float DefaultFadeDuration = 1f; private const float SearchStartDelay = 1f; private const float ProjectorMoveDuration = 2f; [SerializeField] private BubbleSlotGroup bubbleSlotGroup; public BubbleSlotGroup BubbleSlotGroup => bubbleSlotGroup; [SerializeField] private GameObject memoryView; [SerializeField] private GameObject projector; [SerializeField] private SpriteRenderer memoryFinishedSpriteRenderer; // 用于显示记忆处理结束的表现 [SerializeField] private SpriteRenderer memoryFinishedImageNoColor; // 用于显示记忆处理结束的表现 [SerializeField] private Volume mainEffect; [SerializeField] private Volume memoryClarityVolume; [SerializeField] private Volume memoryFrequencyVolume; [SerializeField] private Volume memoryProcessVolume; [SerializeField] private MemorySlider frequencySlider; // 频率调节滑动条 [SerializeField] private MemorySlider claritySlider; // 清晰度调节滑动条 [SerializeField] private CanvasGroup playBackground; [SerializeField] private GameObject memoryGroup; [SerializeField] private CinemachineVirtualCamera memoryCamera; private bool isProcessing = false; // 新增变量来追踪是否正在处理记忆 private bool isPlayingFaderSound = false; // 追踪音效是否正在播放 private PunchTape _activePunchTape; [SerializeField] private MemoryPunchTapeSlot punchTapeSlot; [SerializeField] private Material fadeMaterial; public void OpenMemoryView() { memoryGroup.SetActive(true); memoryView.gameObject.SetActive(true); } public IEnumerator DropMemoryProjector() { DG.Tweening.Sequence zoomInSequence = DOTween.Sequence(); zoomInSequence.Append(projector.transform.DOLocalMoveY(-5, ProjectorMoveDuration).SetEase(Ease.OutElastic, 0.5f)); yield return zoomInSequence.WaitForCompletion(); } public void PullMemoryProjector() { DG.Tweening.Sequence zoomOutSequence = DOTween.Sequence(); zoomOutSequence.Append(projector.transform.DOLocalMoveY(0, ProjectorMoveDuration).SetEase(Ease.OutElastic, 0.5f)); } public void CloseMemoryView() { memoryView.gameObject.SetActive(false); memoryGroup.SetActive(false); } public void OnEnter() { OpenMemoryView(); PrepareMemoryView(); } public void OnShow() { Debug.Log("memoryView showed."); PrepareMemoryView(); } private void PrepareMemoryView() { EnsurePunchTapeSlotReference(); PunchTapeManager.Instance.OpenFavoritesPanel(); playBackground.gameObject.SetActive(false); playBackground.alpha = 0; } public void OnExit() { // 停止拉条音频 if (isPlayingFaderSound) { AudioManager.Instance.StopSfx("event:/ActionFB/mem_fader"); isPlayingFaderSound = false; } PunchTapeManager.Instance.CloseFavoritesPanel(); CloseMemoryView(); // 离开视图时的逻辑 Debug.Log("MemoryView exited."); if (frequencySlider != null) { frequencySlider.SetInteractable(false); frequencySlider.LockSlider(); } if (claritySlider != null) { claritySlider.SetInteractable(false); claritySlider.LockSlider(); } } private void Awake() { InitSystem(); } private void EnsurePunchTapeSlotReference() { if (punchTapeSlot != null) return; punchTapeSlot = MemoryPunchTapeSlot.ActiveInstance; if (punchTapeSlot == null) { Debug.LogWarning( "[MemoryProcess] 未配置 MemoryPunchTapeSlot:请在 Inspector 将 punchTapeSlot 赋值为场景中的插槽,或确保存在 MemoryPunchTapeSlot。", this); } } private void InitSystem() { FixSystemCenter.SystemDic.Register(this); if (memoryGroup != null) memoryGroup.SetActive(false); if (memoryCamera != null) CameraKit.Instance.RegisterCamera(CameraEnum.Memory, memoryCamera); } private void Start() { frequencySlider.OnFound += CheckAllFound; claritySlider.OnFound += CheckAllFound; Init(); } private void CheckAllFound() { if (frequencySlider.IsFound && claritySlider.IsFound) OnSearchComplete(); } private float GetRandomNumber() { // 随机决定选择哪个区间 if (UnityEngine.Random.value < 0.5f) // 50% 概率选择第一个区间 { return UnityEngine.Random.Range(0.5f, 2f); } else // 50% 概率选择第二个区间 { return UnityEngine.Random.Range(4f, 5.5f); } } private void OnSearchComplete() { Debug.Log("Memory search completed."); frequencySlider.SetInteractable(false); claritySlider.SetInteractable(false); // 停止拉条音频 if (isPlayingFaderSound) { AudioManager.Instance.StopSfx("event:/ActionFB/mem_fader"); isPlayingFaderSound = false; } AudioManager.Instance.SetSfxParam("event:/Amb/amb_mem_tuning", "is_mem_tuning", 0); StartCoroutine(PlayMemory()); } public void TweenWeight(Volume postProcessingVolume, float targetWeight, float duration) { // 动态调整权重 DOTween.To(() => postProcessingVolume.weight, x => postProcessingVolume.weight = x, targetWeight, duration); } public void Init() { isProcessing = false; // 停止拉条音频 if (isPlayingFaderSound) { AudioManager.Instance.StopSfx("event:/ActionFB/mem_fader"); isPlayingFaderSound = false; } if (frequencySlider != null) frequencySlider.Init(memoryFrequencyVolume); if (claritySlider != null) claritySlider.Init(memoryClarityVolume); ResetPresentationState(); } /// /// 单条记忆播放结束后的复位:不调用 (避免再次锁条并触发打开 Timeline), /// 仅禁用拖动;完整 仅在退出 执行。 /// private void ResetAfterMemoryFinished() { isProcessing = false; if (isPlayingFaderSound) { AudioManager.Instance.StopSfx("event:/ActionFB/mem_fader"); isPlayingFaderSound = false; } if (frequencySlider != null) frequencySlider.SetInteractable(false); if (claritySlider != null) claritySlider.SetInteractable(false); ResetPresentationState(); } private void ResetPresentationState() { if (fadeMaterial != null) fadeMaterial.SetFloat("_DirectionalDistortionFade", FadeMaterialStartValue); memoryFinishedSpriteRenderer.color = Color.black; memoryProcessVolume.weight = 0; _activePunchTape = null; playBackground.gameObject.SetActive(false); playBackground.alpha = 0; } [YarnCommand("MemoryFinished")] public IEnumerator MemoryFinished() { yield return playBackground.DOFade(0f, DefaultFadeDuration).WaitForCompletion(); playBackground.gameObject.SetActive(false); PunchTapeManager.Instance.OpenFavoritesPanel(); ResetAfterMemoryFinished(); EnsurePunchTapeSlotReference(); if (punchTapeSlot != null && punchTapeSlot.punchTape != null) { punchTapeSlot.punchTape.used = true; punchTapeSlot.ReleaseSlot(); } } [YarnCommand("ColorFadeOut")] public IEnumerator ColorFadeOut() { if (fadeMaterial == null) yield break; fadeMaterial.SetFloat("_DirectionalDistortionFade", FadeMaterialStartValue); Tween tween = fadeMaterial.DOFloat(0, "_DirectionalDistortionFade", 3); yield return tween.WaitForCompletion(); } [YarnCommand("PlayMemory")] public IEnumerator PlayMemory(bool useYarn = false, string memName = "") { memoryFinishedSpriteRenderer.color = Color.white; PunchTapeManager.Instance.CloseFavoritesPanel(); if (useYarn) { if (fadeMaterial != null) fadeMaterial.SetFloat("_DirectionalDistortionFade", FadeMaterialStartValue); var memoryKey = string.Format(MemorySpritePath, memName); var memoryHandle = ResourceSystem.LoadAsync(memoryKey); yield return memoryHandle; Sprite memSprite = memoryHandle.Status == AsyncOperationStatus.Succeeded ? memoryHandle.Result : null; memoryFinishedSpriteRenderer.sprite = memSprite; memoryFinishedImageNoColor.sprite = memSprite; if (memSprite == null) { Debug.LogError("Memory not found: " + memoryKey); } } else { EnsurePunchTapeSlotReference(); if (punchTapeSlot == null || punchTapeSlot.punchTape == null) { Debug.LogError("[MemoryProcess] PlayMemory:未配置插槽或打孔带数据缺失。", this); yield break; } } playBackground.gameObject.SetActive(true); playBackground.alpha = 0; AudioManager.Instance.PlaySfx("event:/ActionFB/mem_play"); yield return playBackground.DOFade(1f, DefaultFadeDuration).WaitForCompletion(); if (!useYarn) { DialogController.Instance.StartDialogNode( LocalizationKit.GetL10NParamKey(punchTapeSlot.punchTape.ClueName)); } } [YarnCommand("search_memory")] public IEnumerator SearchMemory(PunchTape punchTape, bool isSkipDialogue = false) { if (isPlayingFaderSound) { AudioManager.Instance.StopSfx("event:/ActionFB/mem_fader"); isPlayingFaderSound = false; } frequencySlider.TargetValue = GetRandomNumber(); claritySlider.TargetValue = GetRandomNumber(); PunchTapeManager.Instance.CloseFavoritesPanel(); if (punchTape == null) { Debug.Log("no punchTape"); yield break; } _activePunchTape = punchTape; if (isProcessing) { Debug.LogWarning("Already processing a memory. Please wait until the process is finished."); yield break; } var searchMemoryKey = string.Format(MemorySpritePath, _activePunchTape.MemoryIndex); var searchMemoryHandle = ResourceSystem.LoadAsync(searchMemoryKey); yield return searchMemoryHandle; Sprite memorySprite = searchMemoryHandle.Status == AsyncOperationStatus.Succeeded ? searchMemoryHandle.Result : null; memoryFinishedSpriteRenderer.sprite = memorySprite; memoryFinishedImageNoColor.sprite = memorySprite; if (memorySprite == null) { Debug.LogError("Memory not found: " + searchMemoryKey); } memoryProcessVolume.weight = 1; AudioManager.Instance.PlaySfx("event:/Scriptal/mem_load"); yield return new WaitForSeconds(SearchStartDelay); AudioManager.Instance.SetSfxParam("event:/Amb/amb_mem_tuning", "is_mem_tuning", 1); memoryFinishedSpriteRenderer.color = Color.white; memoryProcessVolume.weight = 0; isProcessing = true; frequencySlider.PrepareForSearch(); claritySlider.PrepareForSearch(); bool freqUnlocked = false; bool clarityUnlocked = false; frequencySlider.UnlockSlider(() => freqUnlocked = true); claritySlider.UnlockSlider(() => clarityUnlocked = true); yield return new WaitUntil(() => freqUnlocked && clarityUnlocked); frequencySlider.SetInteractable(true); claritySlider.SetInteractable(true); } public bool IsProcessing() { return isProcessing; } } }