387 lines
14 KiB
C#
387 lines
14 KiB
C#
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();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 单条记忆播放结束后的复位:不调用 <see cref="MemorySlider.Init"/>(避免再次锁条并触发打开 Timeline),
|
|
/// 仅禁用拖动;完整 <see cref="MemorySlider.LockSlider"/> 仅在退出 <see cref="MemoryState"/> 时 <see cref="OnExit"/> 执行。
|
|
/// </summary>
|
|
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<Sprite>(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<Sprite>(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;
|
|
}
|
|
}
|
|
} |