Files
aibis-dream/Assets/Scripts/MiniGame/Peipei/Eye/EyeSystem.cs
T

511 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using Yarn.Unity;
using System.Linq;
using UnityEngine.UI;
using AibisDream.FixSystem;
using AibisDream.SaveSystem;
using Cinemachine;
using AibisDream.Framework;
using AibisDream.Kit;
using UnityEngine.ResourceManagement.AsyncOperations;
using Sequence = DG.Tweening.Sequence;
namespace AibisDream
{
public class EyeSystem : MonoBehaviour
{
private const string MemorySpritePath = "Sprite/Memory/{0}.png";
public BubbleSlotGroup bubbleSlotGroup;
[SerializeField] private List<EyeTarget> targets = new(); // 保存目标列表
public List<EyeTarget> Targets => targets; // 提供目标列表的公共访问
private EyeTarget currentTarget; // 当前选中的目标
public EyeTarget CurrentTarget => currentTarget; // 提供当前目标的公共访问
public RawImage eyeImage;
public Image memoryRender;
public GameObject eyeView;
public ViewCameraManager cameraManager;
private IEyeStateEffect eyeStateEffect;
private EyeData _eyeData = new();
/// <summary>获取当前 Eye 颜色阶段。</summary>
public EyeData.EyeColorState GetCurrentColorState() => _eyeData.currentState;
private Tween hsvShiftTween;
private MouseFollowAndZoom mouseFollowAndZoom;
/// <summary>
/// 眼睛 RawImage 的故障/色相/饱和度等效果依赖 AllIn1SpriteShader(或兼容)材质上的属性。
/// 若未在 Inspector 指定 MaterialUnity 会使用 Default UI MaterialUI/Default),不含 _HsvShift 等属性。
/// </summary>
private bool TryGetEyeImageMaterialForEffects(out Material material)
{
material = null;
if (eyeImage == null)
{
Debug.LogError("[EyeSystem] eyeImage 未赋值。", this);
return false;
}
material = eyeImage.material;
if (material == null || !material.HasProperty("_HsvShift"))
{
Debug.LogError(
"[EyeSystem] eyeImage 需要指定 AllIn1SpriteShader(或兼容)材质;当前为 " +
(material != null && material.shader != null ? material.shader.name : "null") +
"。请在场景中选中该 RawImage,指定项目内 EyeMaterials / AllIn1 材质,勿留空(否则会使用 Default UI Material)。",
this);
return false;
}
return true;
}
private void Awake()
{
Init();
}
public void Init()
{
FixSystemCenter.SystemDic.Register(this);
var virtualCam = transform.Find("Eye Camera").GetComponent<ICinemachineCamera>();
var virtualCamDeep = transform.Find("Eye DeepCamera").GetComponent<ICinemachineCamera>();
CameraKit.Instance.RegisterCamera(CameraEnum.Eye, virtualCam);
CameraKit.Instance.RegisterCamera(CameraEnum.EyeDeep, virtualCamDeep);
DeepRepairDataRegistry.RegisterData(_eyeData);
// 添加加载逻辑
_eyeData.LoadEvent += LoadData;
// 确保 ViewCamera 默认不激活
if (cameraManager != null)
{
cameraManager.gameObject.SetActive(false);
}
}
private void LoadData(EyeData eyedata)
{
SetEyeColorState(eyedata.currentState);
}
public void OnEnter()
{
// 先激活 ViewCamera
if (cameraManager != null)
{
cameraManager.gameObject.SetActive(true);
}
mouseFollowAndZoom.SetIsActive(true);
mouseFollowAndZoom.SetIsLock(false);
// 激活 ViewCamera 后再打开 EyeView
OpenEyeView();
// 进入视图时的逻辑
Debug.Log("EyeView entered.");
}
public void OpenEyeView()
{
eyeView.SetActive(true);
}
public void CloseEyeView()
{
eyeView.SetActive(false);
}
public void OnShow()
{
// 离开视图时的逻辑
Debug.Log("EyeView showed.");
}
public void OnExit()
{
if (currentTarget != null)
{
eyeStateEffect?.CleanupEffect(CurrentTarget);
}
mouseFollowAndZoom.SetIsActive(false);
currentTarget = null;
// 先关闭 EyeView
CloseEyeView();
// 再关闭 ViewCamera
if (cameraManager != null)
{
cameraManager.gameObject.SetActive(false);
}
// 离开视图时的逻辑
Debug.Log("EyeView exited.");
}
private void Start()
{
SetEyeColorState(_eyeData.currentState);
mouseFollowAndZoom = FindObjectOfType<MouseFollowAndZoom>();
}
public EyeTarget FindEyeTargetByName(string name)
{
return Targets.FirstOrDefault(target => target.gameObject.name == name);
}
public void SetTarget(EyeTarget newTarget)
{
if (newTarget == null)
{
Debug.LogError("Target is null in SetTarget");
return;
}
StartCoroutine(SetTargetCoroutine(newTarget.gameObject.name));
}
[YarnCommand("set_Eyetarget")]
public IEnumerator SetTargetCoroutine(string targetName, bool startDialogue = true)
{
mouseFollowAndZoom.SetIsLock(true);
EyeTarget target = FindEyeTargetByName(targetName);
if (target == null)
{
Debug.LogError("Invalid EyeTarget name: " + targetName);
yield break;
}
YarnVariableStorage.Instance.SetValue("$currentEyeTarget", target.name);
StartCoroutine(EyeEffectFadeOut());
cameraManager.MoveCameraTo(target.targetTransform ? target.targetTransform : target.transform, 1f);
if (currentTarget != null)
{
currentTarget.BlurIn(eyeStateEffect.TransitionDuration, false);
}
if (currentTarget == target)
{
DialogController.Instance.StartDialogNode("重复看同一个目标");
currentTarget = target;
mouseFollowAndZoom.SetIndicatorTarget(currentTarget);
currentTarget.BlurOut(eyeStateEffect.TransitionDuration, false);
yield return new WaitForSeconds(eyeStateEffect.TransitionDuration);
yield break;
}
currentTarget = target;
mouseFollowAndZoom.SetIndicatorTarget(currentTarget);
currentTarget.BlurOut(eyeStateEffect.TransitionDuration, false);
yield return new WaitForSeconds(eyeStateEffect.TransitionDuration);
if (startDialogue)
{
DialogController.Instance.StartDialogNode("IntoEyeView");
}
}
[YarnCommand("Set_MouseMovementLockState")]
public void SetMouseMovementLockState(bool isActive)
{
mouseFollowAndZoom.SetIsLock(isActive);
}
[YarnCommand("EyeEffect_FadeIn")]
public IEnumerator EyeEffectFadeIn()
{
if (currentTarget != null)
{
// AudioManager.RandomPlayInteraction("colorimagine");
AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine");
eyeStateEffect?.ApplyFocusedEffect(currentTarget);
}
yield return new WaitForSeconds(eyeStateEffect.TransitionDuration);
}
[YarnCommand("EyeEffect_FadeOut")]
public IEnumerator EyeEffectFadeOut()
{
if (currentTarget != null)
{
// AudioManager.RandomPlayInteraction("colorimagine");
AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine");
eyeStateEffect?.ApplyUnfocusedEffect(currentTarget);
}
yield return new WaitForSeconds(eyeStateEffect.TransitionDuration);
}
[YarnCommand("EyeEffect_Init")]
public void EyeEffectInit()
{
foreach (EyeTarget target in targets)
{
target.Init();
}
if (currentTarget != null)
{
eyeStateEffect?.InitializeEffect(currentTarget, cameraManager);
}
}
[YarnCommand("EyeEffect_Clean")]
public void EyeEffectClean()
{
if (currentTarget != null)
{
eyeStateEffect?.CleanupEffect(currentTarget);
}
}
[YarnCommand("set_EyeColorState")]
public void SetEyeColorStateForYarn(string state)
{
// Try to parse the string as an EyeColorState
if (!Enum.TryParse(state, true, out EyeData.EyeColorState eyeState))
{
throw new ArgumentException("Invalid eye state: " + state, nameof(state));
}
// Start the coroutine for setting the eye state
SetEyeColorState(eyeState);
}
private void SetEyeColorState(EyeData.EyeColorState state)
{
_eyeData.currentState = state;
switch (state)
{
case EyeData.EyeColorState.CanImagineColor:
eyeStateEffect = new CanImagineColorEffect();
break;
case EyeData.EyeColorState.CannotImagineColor:
eyeStateEffect = new CannotImagineColorEffect();
break;
case EyeData.EyeColorState.EyeDisorder:
eyeStateEffect = new EyeDisorderEffect();
break;
case EyeData.EyeColorState.CanSeeColor:
eyeStateEffect = new CanSeeColorEffect();
break;
case EyeData.EyeColorState.HaveChip:
eyeStateEffect = new HaveChip();
break;
default:
throw new ArgumentException("Unknown eye state: " + state.ToString(), nameof(state));
}
}
[YarnCommand("Set_Saturation")]
public IEnumerator Set_Saturation(float targetSaturation, float duration)
{
if (!TryGetEyeImageMaterialForEffects(out Material material))
{
yield break;
}
// 确保 targetSaturation 在 0 到 1 之间
targetSaturation = Mathf.Clamp01(targetSaturation);
Sequence saturationSequence = DOTween.Sequence();
// 同时启动材质的饱和度变化和 Volume 的weight变化
saturationSequence.Join(material.DOFloat(targetSaturation, "_HsvSaturation", duration));
// 获取 Tween 对象并添加到序列中
Tween saturationTween = ScreenEffectManager.Instance.TweenSaturation(targetSaturation, duration);
if (saturationTween != null)
{
saturationSequence.Join(saturationTween);
}
// 启动 Sequence 并等待完成
yield return saturationSequence.WaitForCompletion();
}
private Sequence glitchin;
[YarnCommand("EyeGlitch_in")]
public IEnumerator EyeGlitch_in()
{
if (!TryGetEyeImageMaterialForEffects(out Material material))
{
yield break;
}
glitchin = DOTween.Sequence();
// _HsvShift 从 0 ~ 360 来回变化
hsvShiftTween = DOTween
.To(() => material.GetFloat("_HsvShift"), x => material.SetFloat("_HsvShift", x), 360, 1f)
.SetLoops(-1, LoopType.Yoyo);
glitchin.Append(hsvShiftTween);
// _GlitchAmount 1 秒内从 0 ~ 8
glitchin.Insert(0,
DOTween.To(() => material.GetFloat("_GlitchAmount"), x => material.SetFloat("_GlitchAmount", x), 8,
1f));
// _WarpStrength 1 秒内从 0 ~ 0.015
glitchin.Insert(0,
DOTween.To(() => material.GetFloat("_WarpStrength"), x => material.SetFloat("_WarpStrength", x), 0.015f,
1f));
yield return new WaitForSeconds(1f);
}
[YarnCommand("EyeGlitch_out")]
public void EyeGlitch_out(float duration)
{
if (!TryGetEyeImageMaterialForEffects(out Material material))
{
return;
}
if (glitchin != null && glitchin.IsActive())
{
glitchin.Kill();
}
material.DOFloat(0, "_WarpStrength", duration);
material.DOFloat(0, "_GlitchAmount", duration);
material.DOFloat(0, "_HsvShift", duration);
// 确保之前的动画被停止
}
[YarnCommand("set_EyeColor")]
public IEnumerator SetEyeColor(string color, string memoryName = null)
{
if (!TryGetEyeImageMaterialForEffects(out Material material))
{
yield break;
}
if (memoryRender == null)
{
Debug.LogError("[EyeSystem] memoryRender 未赋值。", this);
yield break;
}
Material memoryMaterial = memoryRender.material;
memoryRender.sprite = null;
memoryMaterial.SetFloat("_FullDistortionFade", 0f);
memoryMaterial.SetFloat("_SqueezePower", 18f);
if (memoryName != null)
{
var memoryKey = string.Format(MemorySpritePath, memoryName);
var memoryHandle = ResourceSystem.LoadAsync<Sprite>(memoryKey);
yield return memoryHandle;
if (memoryHandle.Status != AsyncOperationStatus.Succeeded || memoryHandle.Result == null)
{
Debug.LogWarning("Memory not found: " + memoryKey);
yield break;
}
memoryRender.sprite = memoryHandle.Result;
// 使 memoryRender 可见
memoryRender.gameObject.SetActive(true);
// 创建一个新的 DOTween 序列
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(() =>
{
memoryRender.gameObject.SetActive(false);
// AudioManager.RandomPlayInteraction("water_drip");
}));
// 等待序列完成
yield return memorySequence.WaitForCompletion();
}
Sequence sequence = DOTween.Sequence();
// 添加一个 tween 来改变 _RoundWaveStrength 的值
sequence.Append(material.DOFloat(1, "_RoundWaveStrength", 2)).OnComplete(() => { EyeGlitch_out(0.5f); });
// 根据颜色改变 _ColorChangeTolerance 的值
switch (color.ToLower())
{
case "blue":
sequence.Join(material.DOFloat(0, "_ColorChangeTolerance", 2));
sequence.Join(material.DOFloat(1, "_ColorChangeTolerance3", 2));
sequence.Join(material.DOFloat(1, "_ColorChangeTolerance2", 2));
break;
case "red":
sequence.Join(material.DOFloat(0, "_ColorChangeTolerance3", 2));
sequence.Join(material.DOFloat(1, "_ColorChangeTolerance", 2));
sequence.Join(material.DOFloat(1, "_ColorChangeTolerance2", 2));
break;
case "green":
sequence.Join(material.DOFloat(0, "_ColorChangeTolerance2", 2));
sequence.Join(material.DOFloat(1, "_ColorChangeTolerance", 2));
sequence.Join(material.DOFloat(1, "_ColorChangeTolerance3", 2));
break;
case "All":
sequence.Join(material.DOFloat(1, "_ColorChangeTolerance2", 2));
sequence.Join(material.DOFloat(1, "_ColorChangeTolerance", 2));
sequence.Join(material.DOFloat(1, "_ColorChangeTolerance3", 2));
break;
default:
Debug.LogWarning("Unknown color: " + color);
break;
}
// 添加一个 tween 来将 _RoundWaveStrength 的值回复为 0
sequence.Append(material.DOFloat(0, "_RoundWaveStrength", 0.5f));
// 开始这个序列
sequence.Play();
// 等待序列完成
yield return sequence.WaitForCompletion();
}
[YarnCommand("EyeGetColor")]
public void GetColor()
{
SetEyeColorState(EyeData.EyeColorState.CanImagineColor);
// 对目标列表中的每个目标执行 ColorBack 方法
foreach (EyeTarget target in targets)
{
target.ColorBack();
}
// 切换到 CanImagineColorEffect 状态
}
}
public class EyeData : IData
{
public enum EyeColorState
{
CanImagineColor,
CannotImagineColor,
EyeDisorder,
CanSeeColor,
HaveChip
}
public EyeColorState currentState = EyeColorState.CannotImagineColor;
public event Action<EyeData> LoadEvent;
public IEnumerator Load()
{
LoadEvent?.Invoke(this);
yield break;
}
}
}