diff --git a/Assets/Scripts/MiniGame/Peipei/Eye/Editor.meta b/Assets/Scripts/MiniGame/Peipei/Eye/Editor.meta new file mode 100644 index 000000000..835d62f13 --- /dev/null +++ b/Assets/Scripts/MiniGame/Peipei/Eye/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8f92d49bad6ceaa4983976ea6bb47c46 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/MiniGame/Peipei/Eye/Editor/EyeSystemEditor.cs b/Assets/Scripts/MiniGame/Peipei/Eye/Editor/EyeSystemEditor.cs new file mode 100644 index 000000000..268783fef --- /dev/null +++ b/Assets/Scripts/MiniGame/Peipei/Eye/Editor/EyeSystemEditor.cs @@ -0,0 +1,77 @@ +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +namespace AibisDream +{ + [CustomEditor(typeof(EyeSystem))] + public class EyeSystemEditor : Editor + { + public override void OnInspectorGUI() + { + serializedObject.Update(); + + DrawPropertiesExcluding(serializedObject, "m_Script", "visualSettings", "replayFocusedEffectOnSettingsChange"); + + SerializedProperty visualSettings = serializedObject.FindProperty("visualSettings"); + SerializedProperty replayOnChange = serializedObject.FindProperty("replayFocusedEffectOnSettingsChange"); + + if (visualSettings != null) + { + EditorGUILayout.Space(6f); + EditorGUILayout.LabelField("Visual Tuning", EditorStyles.boldLabel); + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(visualSettings, includeChildren: true); + bool visualChanged = EditorGUI.EndChangeCheck(); + + EditorGUILayout.Space(4f); + EditorGUILayout.PropertyField(replayOnChange); + + EditorGUILayout.HelpBox( + "Blur / Reveal 扫过 / Wrong Color / HSV:改完即写入材质。\n" + + "时长 / colorReveal 范围:Play 下需勾选「自动重播」或点「重播当前目标效果」。\n" + + "Edit 模式:改参数后会自动把所有目标重置为 idle(灰+糊)预览。", + MessageType.Info); + + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("立即应用(Idle 预览)")) + { + serializedObject.ApplyModifiedProperties(); + GetEyeSystem().ApplyVisualSettingsNow(previewIdleState: true); + } + + if (GUILayout.Button("重播当前目标效果")) + { + serializedObject.ApplyModifiedProperties(); + GetEyeSystem().ApplyVisualSettingsNow(replayFocusedEffect: true); + } + EditorGUILayout.EndHorizontal(); + + if (visualChanged) + { + serializedObject.ApplyModifiedProperties(); + var system = GetEyeSystem(); + system.ApplyVisualSettingsNow( + previewIdleState: !Application.isPlaying, + replayFocusedEffect: Application.isPlaying && replayOnChange.boolValue); + return; + } + } + else + { + EditorGUILayout.HelpBox( + "visualSettings 未找到。请确认 EyeSystem.cs 已编译通过。", + MessageType.Warning); + } + + serializedObject.ApplyModifiedProperties(); + } + + private EyeSystem GetEyeSystem() + { + return (EyeSystem)target; + } + } +} +#endif diff --git a/Assets/Scripts/MiniGame/Peipei/Eye/Editor/EyeSystemEditor.cs.meta b/Assets/Scripts/MiniGame/Peipei/Eye/Editor/EyeSystemEditor.cs.meta new file mode 100644 index 000000000..b9b2b3f64 --- /dev/null +++ b/Assets/Scripts/MiniGame/Peipei/Eye/Editor/EyeSystemEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 193d982b27c7dd34cb2aa48c07b1df09 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/MiniGame/Peipei/Eye/EyeSystem.cs b/Assets/Scripts/MiniGame/Peipei/Eye/EyeSystem.cs index 72850042d..1d4a112f4 100644 --- a/Assets/Scripts/MiniGame/Peipei/Eye/EyeSystem.cs +++ b/Assets/Scripts/MiniGame/Peipei/Eye/EyeSystem.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using UnityEngine; @@ -19,20 +19,82 @@ namespace AibisDream { private const string MemorySpritePath = "Sprite/Memory/{0}.png"; - [SerializeField] private List targets = new(); // 保存目标列表 - public List Targets => targets; // 提供目标列表的公共访问 - private EyeTarget currentTarget; // 当前选中的目标 - public EyeTarget CurrentTarget => currentTarget; // 提供当前目标的公共访问 - public RawImage eyeImage; + [SerializeField] private List targets = new(); + public List Targets => targets; + + private EyeTarget currentTarget; + public EyeTarget CurrentTarget => currentTarget; + + [Header("Memory Overlay (UI)")] public Image memoryRender; public GameObject eyeView; - public ViewCameraManager cameraManager; + + [Header("Focus Pan Bounds")] + [SerializeField] private Vector2 focusMinBounds = new(30.2f, -5f); + [SerializeField] private Vector2 focusMaxBounds = new(50.2f, 5f); + + [Header("Visual Tuning")] + [SerializeField] private EyeVisualSettings visualSettings = new(); + + [Tooltip("Play 模式下改 Visual Tuning 后,自动对当前目标重播一次 Focused 效果(如 ColorIn)。")] + [SerializeField] private bool replayFocusedEffectOnSettingsChange = true; + + public EyeVisualSettings VisualSettings => visualSettings; + private IEyeStateEffect eyeStateEffect; private EyeColorState _currentState = EyeColorState.CannotImagineColor; + private MouseFollowAndZoom mouseFollowAndZoom; + private Sequence glitchin; - /// 获取当前 Eye 颜色阶段。 public EyeColorState GetCurrentColorState() => _currentState; + public float GetEffectTransitionDuration() => visualSettings.GetDurationForState(_currentState); + + private void OnValidate() + { + ApplyVisualSettingsNow( + previewIdleState: !Application.isPlaying, + replayFocusedEffect: Application.isPlaying && replayFocusedEffectOnSettingsChange); + } + + /// + /// 将 Visual Tuning 推送到所有 EyeTarget。Edit 模式预览 idle;Play 模式可选重播当前目标效果。 + /// + public void ApplyVisualSettingsNow(bool previewIdleState = false, bool replayFocusedEffect = false) + { + if (targets == null) + { + return; + } + + foreach (EyeTarget target in targets) + { + if (target == null) + { + continue; + } + + target.BindVisualSettings(visualSettings); + if (previewIdleState) + { + target.ApplyIdlePreviewState(); + } + } + + if (!replayFocusedEffect || !Application.isPlaying || currentTarget == null || eyeStateEffect == null) + { + return; + } + + currentTarget.KillVisualTweens(); + eyeStateEffect.ApplyFocusedEffect(currentTarget, this); + } + + private void ApplyVisualSettingsToTargets() + { + ApplyVisualSettingsNow(); + } + public enum EyeColorState { CanImagineColor, @@ -42,37 +104,6 @@ namespace AibisDream HaveChip } - private Tween hsvShiftTween; - private MouseFollowAndZoom mouseFollowAndZoom; - private RenderTexture runtimeEyeRenderTexture; - - /// - /// 眼睛 RawImage 的故障/色相/饱和度等效果依赖 AllIn1SpriteShader(或兼容)材质上的属性。 - /// 若未在 Inspector 指定 Material,Unity 会使用 Default UI Material(UI/Default),不含 _HsvShift 等属性。 - /// - 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(); @@ -95,96 +126,47 @@ namespace AibisDream return true; } - private bool EnsureEyeViewRenderTarget() + private Vector2 GetFocusViewportSize() { - if (eyeImage == null) + var focusCamera = Camera.main; + if (focusCamera == null || !focusCamera.orthographic) { - Debug.LogError("[EyeSystem] eyeImage 未赋值,无法显示视觉模块画面。", this); - return false; + return Vector2.zero; } - if (cameraManager == null) - { - Debug.LogError("[EyeSystem] cameraManager 未赋值,无法渲染视觉模块画面。", this); - return false; - } - - var viewCamera = cameraManager.GetComponent(); - if (viewCamera == null) - { - Debug.LogError("[EyeSystem] cameraManager 上未找到 Camera 组件,无法渲染视觉模块画面。", cameraManager); - return false; - } - - viewCamera.allowHDR = false; - viewCamera.allowMSAA = false; - - var renderTexture = viewCamera.targetTexture; - if (renderTexture == null) - { - renderTexture = CreateRuntimeEyeRenderTexture(); - viewCamera.targetTexture = renderTexture; - } - - if (!renderTexture.IsCreated()) - { - renderTexture.Create(); - } - - if (eyeImage.texture != renderTexture) - { - eyeImage.texture = renderTexture; - } - - return true; + float height = focusCamera.orthographicSize * 2f; + return new Vector2(height * focusCamera.aspect, height); } - private RenderTexture CreateRuntimeEyeRenderTexture() + private static Transform GetFocusTransform(EyeTarget target) { - var width = Mathf.Clamp(Screen.width, 1, 2048); - var height = Mathf.Clamp(Screen.height, 1, 2048); - - runtimeEyeRenderTexture = new RenderTexture(width, height, 24, RenderTextureFormat.ARGB32) + if (target == null) { - name = "Runtime Eye View RenderTexture", - antiAliasing = 1, - useMipMap = false, - autoGenerateMips = false - }; - runtimeEyeRenderTexture.Create(); - return runtimeEyeRenderTexture; + return null; + } + + return target.targetTransform ? target.targetTransform : target.transform; } - private IEnumerator PrimeEyeViewRender() + public void FocusOnTarget(EyeTarget target, float duration) { - yield return null; - ForceRenderEyeView(); - yield return new WaitForEndOfFrame(); - ForceRenderEyeView(); - } - - private void ForceRenderEyeView() - { - if (cameraManager == null || !cameraManager.gameObject.activeInHierarchy) + Transform focusTransform = GetFocusTransform(target); + if (focusTransform == null || !EnsureMouseFollowAndZoom()) { return; } - var viewCamera = cameraManager.GetComponent(); - if (viewCamera != null && viewCamera.enabled && viewCamera.targetTexture != null) - { - viewCamera.Render(); - } + mouseFollowAndZoom.MoveFocusTo( + focusTransform, + duration, + focusMinBounds, + focusMaxBounds, + GetFocusViewportSize()); } public void Init() { FixSystemCenter.SystemDic.Register(this); - - if (cameraManager != null) - { - cameraManager.gameObject.SetActive(false); - } } public EyeSnapshotDto CaptureEyeSnapshot() @@ -212,38 +194,28 @@ namespace AibisDream return; } - // 先激活 ViewCamera - if (cameraManager != null) - { - cameraManager.gameObject.SetActive(true); - } - - EnsureEyeViewRenderTarget(); - mouseFollowAndZoom.SetIsActive(true); mouseFollowAndZoom.SetIsLock(false); - // 激活 ViewCamera 后再打开 EyeView - OpenEyeView(); - ForceRenderEyeView(); - StartCoroutine(PrimeEyeViewRender()); - // 进入视图时的逻辑 - Debug.Log("EyeView entered."); + mouseFollowAndZoom.ResetPanOrigin(); + ApplyVisualSettingsToTargets(); + InitializeAllTargets(); } - public void OpenEyeView() + private void InitializeAllTargets() { - eyeView.SetActive(true); - } + foreach (EyeTarget target in targets) + { + target.Init(); + } - public void CloseEyeView() - { - eyeView.SetActive(false); + if (currentTarget != null) + { + eyeStateEffect?.InitializeEffect(currentTarget, this); + } } public void OnShow() { - // 离开视图时的逻辑 - Debug.Log("EyeView showed."); } public void OnExit() @@ -259,31 +231,12 @@ namespace AibisDream } currentTarget = null; - // 先关闭 EyeView - CloseEyeView(); - // 再关闭 ViewCamera - if (cameraManager != null) - { - cameraManager.gameObject.SetActive(false); - } - // 离开视图时的逻辑 - Debug.Log("EyeView exited."); - } - - private void OnDestroy() - { - if (runtimeEyeRenderTexture != null) - { - runtimeEyeRenderTexture.Release(); - Destroy(runtimeEyeRenderTexture); - runtimeEyeRenderTexture = null; - } } private void Start() { + ApplyVisualSettingsToTargets(); SetEyeColorState(_currentState); - EnsureMouseFollowAndZoom(); } @@ -320,13 +273,13 @@ namespace AibisDream } YarnVariableStorage.Instance.SetValue("$currentEyeTarget", target.name); - StartCoroutine(EyeEffectFadeOut()); + StartCoroutine(EyeEffect_FadeOut()); - cameraManager.MoveCameraTo(target.targetTransform ? target.targetTransform : target.transform, 1f); + FocusOnTarget(target, 1f); if (currentTarget != null) { - currentTarget.BlurIn(eyeStateEffect.TransitionDuration, false); + currentTarget.BlurIn(visualSettings.targetSwitchDuration); } if (currentTarget == target) @@ -334,16 +287,16 @@ namespace AibisDream DialogController.Instance.StartDialogNode("重复看同一个目标"); currentTarget = target; mouseFollowAndZoom.SetIndicatorTarget(currentTarget); - currentTarget.BlurOut(eyeStateEffect.TransitionDuration, false); - yield return new WaitForSeconds(eyeStateEffect.TransitionDuration); + currentTarget.BlurOut(visualSettings.targetSwitchDuration); + yield return new WaitForSeconds(visualSettings.targetSwitchDuration); yield break; } currentTarget = target; mouseFollowAndZoom.SetIndicatorTarget(currentTarget); - currentTarget.BlurOut(eyeStateEffect.TransitionDuration, false); + currentTarget.BlurOut(visualSettings.targetSwitchDuration); - yield return new WaitForSeconds(eyeStateEffect.TransitionDuration); + yield return new WaitForSeconds(visualSettings.targetSwitchDuration); if (startDialogue) { @@ -363,44 +316,34 @@ namespace AibisDream } [YarnCommand("EyeEffect_FadeIn")] - public IEnumerator EyeEffectFadeIn() + public IEnumerator EyeEffect_FadeIn() { if (currentTarget != null) { - // AudioManager.RandomPlayInteraction("colorimagine"); AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine"); - - eyeStateEffect?.ApplyFocusedEffect(currentTarget); + eyeStateEffect?.ApplyFocusedEffect(currentTarget, this); } - yield return new WaitForSeconds(eyeStateEffect.TransitionDuration); + yield return new WaitForSeconds(GetEffectTransitionDuration()); } [YarnCommand("EyeEffect_FadeOut")] - public IEnumerator EyeEffectFadeOut() + public IEnumerator EyeEffect_FadeOut() { if (currentTarget != null) { - // AudioManager.RandomPlayInteraction("colorimagine"); AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine"); - eyeStateEffect?.ApplyUnfocusedEffect(currentTarget); + eyeStateEffect?.ApplyUnfocusedEffect(currentTarget, this); } - yield return new WaitForSeconds(eyeStateEffect.TransitionDuration); + yield return new WaitForSeconds(GetEffectTransitionDuration()); } [YarnCommand("EyeEffect_Init")] public void EyeEffectInit() { - foreach (EyeTarget target in targets) - { - target.Init(); - } - - if (currentTarget != null) - { - eyeStateEffect?.InitializeEffect(currentTarget, cameraManager); - } + ApplyVisualSettingsToTargets(); + InitializeAllTargets(); } [YarnCommand("EyeEffect_Clean")] @@ -415,127 +358,71 @@ namespace AibisDream [YarnCommand("set_EyeColorState")] public void SetEyeColorStateForYarn(string state) { - // Try to parse the string as an EyeColorState if (!Enum.TryParse(state, true, out EyeColorState eyeState)) { throw new ArgumentException("Invalid eye state: " + state, nameof(state)); } - // Start the coroutine for setting the eye state SetEyeColorState(eyeState); } private void SetEyeColorState(EyeColorState state) { _currentState = state; - switch (state) + eyeStateEffect = state switch { - case EyeColorState.CanImagineColor: - eyeStateEffect = new CanImagineColorEffect(); - break; - case EyeColorState.CannotImagineColor: - eyeStateEffect = new CannotImagineColorEffect(); - break; - case EyeColorState.EyeDisorder: - eyeStateEffect = new EyeDisorderEffect(); - break; - case EyeColorState.CanSeeColor: - eyeStateEffect = new CanSeeColorEffect(); - break; - case EyeColorState.HaveChip: - eyeStateEffect = new HaveChip(); - break; - default: - throw new ArgumentException("Unknown eye state: " + state.ToString(), nameof(state)); - } + EyeColorState.CanImagineColor => new CanImagineColorEffect(), + EyeColorState.CannotImagineColor => new CannotImagineColorEffect(), + EyeColorState.EyeDisorder => new EyeDisorderEffect(), + EyeColorState.CanSeeColor => new CanSeeColorEffect(), + EyeColorState.HaveChip => new HaveChip(), + _ => throw new ArgumentException("Unknown eye state: " + state, 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(); + if (!TryJoinTargetSaturation(saturationSequence, targetSaturation, duration)) + { + Debug.LogWarning("[EyeSystem] 无可用 EyeTarget 饱和度 tween。", this); + yield break; + } - // 同时启动材质的饱和度变化和 Volume 的weight变化 - saturationSequence.Join(material.DOFloat(targetSaturation, "_HsvSaturation", duration)); - - // 获取 Tween 对象并添加到序列中 - Tween saturationTween = ScreenEffectManager.Instance.TweenSaturation(targetSaturation, duration); + Tween saturationTween = ScreenEffectManager.Instance != null + ? ScreenEffectManager.Instance.TweenSaturation(targetSaturation, duration) + : null; 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)) + if (!TryStartUnifiedGlitch()) { - yield break; + Debug.LogWarning("[EyeSystem] 无可用 EyeTarget Glitch tween。", this); } - 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); + yield return new WaitForSeconds(visualSettings.glitchInDuration); } [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); - // 确保之前的动画被停止 + TryStopUnifiedGlitch(duration > 0f ? duration : visualSettings.glitchOutDuration); } [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); @@ -559,63 +446,37 @@ namespace AibisDream } 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()) + + Sequence waveIn = CreateTargetRoundWaveSequence(1f, visualSettings.roundWaveInDuration); + if (waveIn != null) { - 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; + sequence.Append(waveIn); } - // 添加一个 tween 来将 _RoundWaveStrength 的值回复为 0 - sequence.Append(material.DOFloat(0, "_RoundWaveStrength", 0.5f)); + sequence.AppendCallback(() => { EyeGlitch_out(visualSettings.glitchOutDuration); }); + + Sequence waveOut = CreateTargetRoundWaveSequence(0f, visualSettings.roundWaveOutDuration); + if (waveOut != null) + { + sequence.Append(waveOut); + } - // 开始这个序列 sequence.Play(); - - // 等待序列完成 yield return sequence.WaitForCompletion(); } @@ -623,13 +484,118 @@ namespace AibisDream public void GetColor() { SetEyeColorState(EyeColorState.CanImagineColor); - // 对目标列表中的每个目标执行 ColorBack 方法 foreach (EyeTarget target in targets) { target.ColorBack(); } + } - // 切换到 CanImagineColorEffect 状态 + public void SetUnifiedUfWeights(float ascii, float dream, float memory) + { + foreach (EyeTarget target in targets) + { + target.SetUfWeights(ascii, dream, memory); + } + } + + public Tween TweenUnifiedUfWeights(float ascii, float dream, float memory, float duration) + { + Sequence sequence = DOTween.Sequence(); + bool hasTween = false; + + foreach (EyeTarget target in targets) + { + Tween tween = target.TweenUfWeights(ascii, dream, memory, duration); + if (tween == null) + { + continue; + } + + sequence.Join(tween); + hasTween = true; + } + + return hasTween ? sequence : null; + } + + private bool TryJoinTargetSaturation(Sequence sequence, float saturation, float duration) + { + bool hasTween = false; + foreach (EyeTarget target in targets) + { + Tween tween = target.TweenSaturation(saturation, duration); + if (tween == null) + { + continue; + } + + sequence.Join(tween); + hasTween = true; + } + + return hasTween; + } + + private bool TryStartUnifiedGlitch() + { + glitchin?.Kill(); + glitchin = DOTween.Sequence(); + bool hasTween = false; + + foreach (EyeTarget target in targets) + { + Sequence targetGlitch = target.StartUnifiedGlitch(visualSettings.glitchInDuration); + if (targetGlitch == null) + { + continue; + } + + glitchin.Join(targetGlitch); + hasTween = true; + } + + return hasTween; + } + + private bool TryStopUnifiedGlitch(float duration) + { + bool hasTarget = false; + if (glitchin != null && glitchin.IsActive()) + { + glitchin.Kill(); + hasTarget = true; + } + + foreach (EyeTarget target in targets) + { + if (!target.TryGetUnifiedVisual(out _)) + { + continue; + } + + target.StopUnifiedGlitch(duration); + hasTarget = true; + } + + return hasTarget; + } + + private Sequence CreateTargetRoundWaveSequence(float value, float duration) + { + Sequence sequence = DOTween.Sequence(); + bool hasTween = false; + + foreach (EyeTarget target in targets) + { + Tween tween = target.TweenRoundWave(value, duration); + if (tween != null) + { + sequence.Join(tween); + hasTween = true; + } + } + + return hasTween ? sequence : null; } } } diff --git a/Assets/Scripts/MiniGame/Peipei/Eye/EyeTarget.cs b/Assets/Scripts/MiniGame/Peipei/Eye/EyeTarget.cs index 77d2b3eaf..50ea55d0f 100644 --- a/Assets/Scripts/MiniGame/Peipei/Eye/EyeTarget.cs +++ b/Assets/Scripts/MiniGame/Peipei/Eye/EyeTarget.cs @@ -1,149 +1,315 @@ -using UnityEngine; -using DG.Tweening; -using AibisDream.Utility; +using AibisDream; using AibisDream.Kit; +using AibisDream.Utility; +using DG.Tweening; +using UnityEngine; public class EyeTarget : MonoBehaviour { - public Transform targetTransform; // EyeTarget的位置 - [SerializeField] private float burnRadiusMin = 0f; // 对应_BurnRadius的最小值 + public Transform targetTransform; - [SerializeField] private float burnRadiusMax = 1f; // 对应_BurnRadius的最大值 - - private Material forwardMaterial; - - [SerializeField] private SpriteRenderer backSpriteRenderer; - - [SerializeField] private SpriteRenderer wrongColorSpriteRenderer; + [Header("Optional overlay sprite for UF imagination")] [SerializeField] private SpriteRenderer imageSpriteRender; - private Material backMaterial; - private Material wrongColorMaterial; + + [SerializeField] private Shader unifiedSpriteShader; + [SerializeField] private EyeTargetVisual unifiedVisual; public Color _color; + private EyeVisualSettings visualSettings = new(); + private void Awake() { - // 获取此对象的材质 - SpriteRenderer spriteRenderer = GetComponent(); - forwardMaterial = spriteRenderer.material; - forwardMaterial.SetFloat("_SourceGlowDissolveFade", burnRadiusMin); + var spriteRenderer = GetComponent(); + if (spriteRenderer == null) + { + Debug.LogError($"[EyeTarget] {name} 缺少 SpriteRenderer。", this); + return; + } - backMaterial = backSpriteRenderer.material; - wrongColorMaterial = wrongColorSpriteRenderer.material; - ; + EnsureUnifiedVisual(spriteRenderer); + DisableLegacyChildRenderers(); + DisableLegacySiblingRenderers(); + } + + public void BindVisualSettings(EyeVisualSettings settings) + { + visualSettings = settings ?? new EyeVisualSettings(); + RefreshMaterialTuning(); + } + + public void RefreshMaterialTuning() + { + EnsureVisualReady(); + unifiedVisual?.ApplyTuning(visualSettings); + } + + public void ApplyIdlePreviewState() + { + EnsureVisualReady(); + Init(); + } + + public void KillVisualTweens() + { + unifiedVisual?.KillActiveTweens(); + } + + private void EnsureVisualReady() + { + var spriteRenderer = GetComponent(); + if (spriteRenderer == null) + { + return; + } + + if (unifiedVisual == null || !unifiedVisual.IsReady) + { + EnsureUnifiedVisual(spriteRenderer); + } } public void Init() { - SetToMinBurnRadius(); - SetToMaxBlur(false); + SetToMinColorReveal(); + SetToMaxBlur(); SetToNoWrongColor(); SetNoImage(); } public void ImageIn(float duration) { - imageSpriteRender.DOFade(1, duration); + unifiedVisual?.TweenImageAlpha(1f, duration); } public void ImageOut(float duration) { - imageSpriteRender.DOFade(0, duration); + unifiedVisual?.TweenImageAlpha(0f, duration); } public void SetNoImage() { - imageSpriteRender.SetAlpha(0); + unifiedVisual?.SetImageAlpha(0f); } - public void SetToMinBurnRadius() + public void SetToMinColorReveal() { - forwardMaterial.SetFloat("_SourceGlowDissolveFade", burnRadiusMin); + unifiedVisual?.SetColorReveal(visualSettings.colorRevealMin); } - public void SetToMaxBurnRadius() + public void SetToMaxColorReveal() { - forwardMaterial.SetFloat("_SourceGlowDissolveFade", burnRadiusMax); + unifiedVisual?.SetColorReveal(visualSettings.colorRevealMax); } - public void SetToMaxBlur(bool isForwardMaterial = true) + public void SetToMaxBlur() { - Material targetMaterial = isForwardMaterial ? forwardMaterial : backMaterial; - targetMaterial.SetFloat("_GaussianBlurFade", 1f); + unifiedVisual?.SetBlur(visualSettings.idleBlurAmount); } - public void SetToMinBlur(bool isForwardMaterial = true) + public void SetToMinBlur() { - Material targetMaterial = isForwardMaterial ? forwardMaterial : backMaterial; - targetMaterial.SetFloat("_GaussianBlurFade", 0f); + unifiedVisual?.SetBlur(visualSettings.focusedBlurAmount); } public void SetToNoWrongColor() { - wrongColorMaterial.SetFloat("_Alpha", 0f); + unifiedVisual?.SetWrongColor(0f); } public void SetToWrongColor() { - wrongColorMaterial.SetFloat("_Alpha", 1f); + unifiedVisual?.SetWrongColor(1f); } public void FadeOut(float duration) { - // 使用DoTween库来改变_BurnRadius,使目标褪色 - forwardMaterial.DOFloat(burnRadiusMin, "_SourceGlowDissolveFade", duration); - forwardMaterial.DOFloat(1f, "_GaussianBlurFade", duration).SetEase(Ease.InSine); - forwardMaterial.DOFloat(1f, "_UVDistortFade", duration / 2).SetEase(Ease.InSine).SetLoops(2, LoopType.Yoyo); - ; + unifiedVisual?.TweenColorReveal(visualSettings.colorRevealMin, duration)?.SetEase(Ease.InSine); + unifiedVisual?.TweenBlur(visualSettings.idleBlurAmount, duration)?.SetEase(Ease.InSine); + unifiedVisual?.PulseDistortion(visualSettings.colorPulseDistortion, duration); } public void ColorIn(float duration) { - forwardMaterial.DOFloat(burnRadiusMax, "_SourceGlowDissolveFade", duration).SetEase(Ease.InOutSine); - forwardMaterial.DOFloat(0f, "_GaussianBlurFade", duration).SetEase(Ease.InOutSine); - forwardMaterial.DOFloat(1f, "_UVDistortFade", duration / 2).SetEase(Ease.InOutSine).SetLoops(2, LoopType.Yoyo); - ; + unifiedVisual?.TweenColorReveal(visualSettings.colorRevealMax, duration)?.SetEase(Ease.InOutSine); + unifiedVisual?.TweenBlur(visualSettings.focusedBlurAmount, duration)?.SetEase(Ease.InOutSine); + unifiedVisual?.PulseDistortion(visualSettings.colorPulseDistortion, duration); } public void WrongColorIn(float duration) { - wrongColorMaterial.DOFloat(1f, "_Alpha", duration).SetEase(Ease.InOutSine); + unifiedVisual?.TweenWrongColor(1f, duration)?.SetEase(Ease.InOutSine); } public void WrongColorOut(float duration) { - wrongColorMaterial.DOFloat(0f, "_Alpha", duration).SetEase(Ease.InOutSine); + unifiedVisual?.TweenWrongColor(0f, duration)?.SetEase(Ease.InOutSine); } - public void BlurIn(float duration, bool isForwardMaterial = true) + public void BlurIn(float duration) { - // AudioManager.PlayLoopAudio("visualturn"); AudioManager.Instance.PlaySfx("event:/ActionFB/visualturn"); - Material targetMaterial = isForwardMaterial ? forwardMaterial : backMaterial; - targetMaterial.DOFloat(1f, "_GaussianBlurFade", duration).SetEase(Ease.InOutSine) - .OnComplete(() => { AudioManager.Instance.StopSfx("event:/ActionFB/visualturn"); }); + var tween = unifiedVisual?.TweenBlur(visualSettings.idleBlurAmount, duration); + tween?.SetEase(Ease.InOutSine).OnComplete(StopVisualTurnSfx); } - public void BlurOut(float duration, bool isForwardMaterial = true) + public void BlurOut(float duration) { - // AudioManager.PlayLoopAudio("visualturn"); AudioManager.Instance.PlaySfx("event:/ActionFB/visualturn"); - Material targetMaterial = isForwardMaterial ? forwardMaterial : backMaterial; - targetMaterial.DOFloat(0f, "_GaussianBlurFade", duration).SetEase(Ease.InOutSine) - .OnComplete(() => { AudioManager.Instance.StopSfx("event:/ActionFB/visualturn"); }); + var tween = unifiedVisual?.TweenBlur(visualSettings.focusedBlurAmount, duration); + tween?.SetEase(Ease.InOutSine).OnComplete(StopVisualTurnSfx); } public void ColorBack() { - SetToMaxBurnRadius(); + SetToMaxColorReveal(); SetToNoWrongColor(); SetToMinBlur(); } public void ColorLost() { - SetToMinBurnRadius(); - //SetToNoWrongColor(); + SetToMinColorReveal(); SetToMaxBlur(); } -} \ No newline at end of file + + public bool TryGetUnifiedVisual(out EyeTargetVisual visual) + { + visual = unifiedVisual; + return visual != null && visual.IsReady; + } + + public void SetSaturation(float saturation) + { + unifiedVisual?.SetSaturation(saturation); + } + + public Tween TweenSaturation(float saturation, float duration) + { + return unifiedVisual != null ? unifiedVisual.TweenSaturation(saturation, duration) : null; + } + + public DG.Tweening.Sequence StartUnifiedGlitch(float duration = 1f) + { + return unifiedVisual != null ? unifiedVisual.StartGlitch(duration) : null; + } + + public void StopUnifiedGlitch(float duration) + { + unifiedVisual?.StopGlitch(duration); + } + + public Tween TweenRoundWave(float value, float duration) + { + return unifiedVisual != null ? unifiedVisual.TweenRoundWave(value, duration) : null; + } + + public void SetUfWeights(float ascii, float dream, float memory) + { + unifiedVisual?.SetUfWeights(ascii, dream, memory); + } + + public Tween TweenUfWeights(float ascii, float dream, float memory, float duration) + { + return unifiedVisual != null ? unifiedVisual.TweenUfWeights(ascii, dream, memory, duration) : null; + } + + private void EnsureUnifiedVisual(SpriteRenderer spriteRenderer) + { + Shader shader = unifiedSpriteShader != null + ? unifiedSpriteShader + : Shader.Find("AIBIS/EyeUnifiedSprite"); + if (shader == null) + { + Debug.LogError($"[EyeTarget] 找不到 AIBIS/EyeUnifiedSprite shader:{name}", this); + return; + } + + Material currentMaterial = spriteRenderer.material; + bool usesUnifiedShader = currentMaterial != null + && currentMaterial.shader != null + && currentMaterial.shader.name == shader.name; + if (currentMaterial == null || !usesUnifiedShader || !currentMaterial.HasProperty("_BlurAmount")) + { + Texture mainTex = currentMaterial != null && currentMaterial.HasProperty("_MainTex") + ? currentMaterial.GetTexture("_MainTex") + : null; + spriteRenderer.material = new Material(shader) + { + name = $"{gameObject.name}_EyeUnified_Runtime" + }; + if (mainTex != null) + { + spriteRenderer.material.SetTexture("_MainTex", mainTex); + } + } + + if (unifiedVisual == null) + { + unifiedVisual = GetComponent(); + } + + if (unifiedVisual == null) + { + unifiedVisual = gameObject.AddComponent(); + } + + unifiedVisual.Configure(spriteRenderer, imageSpriteRender); + unifiedVisual.ApplyTuning(visualSettings); + } + + private void DisableLegacyChildRenderers() + { + foreach (var childRenderer in GetComponentsInChildren(true)) + { + if (childRenderer.gameObject == gameObject) + { + continue; + } + + if (imageSpriteRender != null && childRenderer == imageSpriteRender) + { + continue; + } + + childRenderer.enabled = false; + } + } + + /// + /// 禁用同组下旧版 overlay(如 posterNoColor / computernocolor),避免盖住 unified 效果。 + /// + private void DisableLegacySiblingRenderers() + { + Transform groupRoot = transform.parent; + if (groupRoot == null) + { + return; + } + + foreach (var renderer in groupRoot.GetComponentsInChildren(true)) + { + if (renderer.gameObject == gameObject) + { + continue; + } + + if (renderer.GetComponent() != null) + { + continue; + } + + if (renderer.GetComponentInParent() != null) + { + continue; + } + + renderer.enabled = false; + } + } + + private static void StopVisualTurnSfx() + { + AudioManager.Instance.StopSfx("event:/ActionFB/visualturn"); + } +} diff --git a/Assets/Scripts/MiniGame/Peipei/Eye/EyeTargetVisual.cs b/Assets/Scripts/MiniGame/Peipei/Eye/EyeTargetVisual.cs new file mode 100644 index 000000000..015227ad0 --- /dev/null +++ b/Assets/Scripts/MiniGame/Peipei/Eye/EyeTargetVisual.cs @@ -0,0 +1,312 @@ +using DG.Tweening; +using UnityEngine; +using AibisDream.Utility; + +namespace AibisDream +{ + /// + /// Drives the unified EyeUnifiedSprite path for Peipei eye targets. + /// + public class EyeTargetVisual : MonoBehaviour + { + private static readonly int ColorRevealId = Shader.PropertyToID("_ColorReveal"); + private static readonly int GrayAmountId = Shader.PropertyToID("_GrayAmount"); + private static readonly int BlurAmountId = Shader.PropertyToID("_BlurAmount"); + private static readonly int BlurSizeId = Shader.PropertyToID("_BlurSize"); + private static readonly int DistortAmountId = Shader.PropertyToID("_DistortAmount"); + private static readonly int WrongColorAmountId = Shader.PropertyToID("_WrongColorAmount"); + private static readonly int SpriteFadeId = Shader.PropertyToID("_SpriteFade"); + private static readonly int AsciiAmountId = Shader.PropertyToID("_AsciiAmount"); + private static readonly int DreamAmountId = Shader.PropertyToID("_DreamAmount"); + private static readonly int MemoryAmountId = Shader.PropertyToID("_MemoryAmount"); + private static readonly int ScanlineAmountId = Shader.PropertyToID("_ScanlineAmount"); + private static readonly int GlitchAmountId = Shader.PropertyToID("_GlitchAmount"); + private static readonly int HsvShiftId = Shader.PropertyToID("_HsvShift"); + private static readonly int HsvSaturationId = Shader.PropertyToID("_HsvSaturation"); + private static readonly int RoundWaveStrengthId = Shader.PropertyToID("_RoundWaveStrength"); + + private static readonly int RevealWidthId = Shader.PropertyToID("_RevealWidth"); + private static readonly int RevealRotationId = Shader.PropertyToID("_RevealRotation"); + private static readonly int RevealNoiseId = Shader.PropertyToID("_RevealNoise"); + private static readonly int WrongColorId = Shader.PropertyToID("_WrongColor"); + + [SerializeField] private SpriteRenderer spriteRenderer; + [SerializeField] private SpriteRenderer imageSpriteRenderer; + [SerializeField] private bool driveImageLayer = true; + + private Material material; + private float activeBlurSize = 0.008f; + + public bool IsReady => material != null && material.HasProperty(ColorRevealId); + public bool CanDriveImageLayer => driveImageLayer && imageSpriteRenderer != null; + public Material Material => material; + + private void Awake() + { + EnsureMaterial(); + } + + public bool EnsureMaterial() + { + if (spriteRenderer == null) + { + spriteRenderer = GetComponent(); + } + + if (spriteRenderer == null) + { + return false; + } + + material = spriteRenderer.material; + return IsReady; + } + + public void Configure(SpriteRenderer mainRenderer, SpriteRenderer imageRenderer) + { + spriteRenderer = mainRenderer; + imageSpriteRenderer = imageRenderer; + EnsureMaterial(); + } + + public void ApplyTuning(EyeVisualSettings settings) + { + if (settings == null) + { + return; + } + + activeBlurSize = settings.blurSize; + + if (!EnsureMaterial()) + { + return; + } + + material.SetFloat(RevealWidthId, settings.revealWidth); + material.SetFloat(RevealRotationId, settings.revealRotation); + material.SetFloat(RevealNoiseId, settings.revealNoise); + material.SetColor(WrongColorId, settings.wrongColor); + SetFloatRaw(HsvSaturationId, settings.hsvSaturation); + SyncBlurSizeToMaterial(); + } + + public void SyncBlurSizeToMaterial() + { + if (!EnsureMaterial() || !material.HasProperty(BlurSizeId)) + { + return; + } + + float blur = material.GetFloat(BlurAmountId); + material.SetFloat(BlurSizeId, blur > 0.01f ? activeBlurSize : 0f); + } + + public void KillActiveTweens() + { + if (material != null) + { + material.DOKill(); + } + + if (driveImageLayer && imageSpriteRenderer != null) + { + imageSpriteRenderer.DOKill(); + } + } + + public void ResetVisual(float reveal) + { + if (!EnsureMaterial()) + { + return; + } + + SetFloat(ColorRevealId, reveal); + SetFloat(GrayAmountId, 1f - reveal); + SetFloat(BlurAmountId, 1f); + if (material.HasProperty(BlurSizeId)) + { + material.SetFloat(BlurSizeId, activeBlurSize); + } + SetFloat(DistortAmountId, 0f); + SetFloat(WrongColorAmountId, 0f); + SetFloat(SpriteFadeId, 1f); + SetFloat(AsciiAmountId, 0f); + SetFloat(DreamAmountId, 0f); + SetFloat(MemoryAmountId, 0f); + SetFloat(ScanlineAmountId, 0f); + SetFloat(GlitchAmountId, 0f); + SetFloat(HsvShiftId, 0f); + SetFloat(HsvSaturationId, 1f); + SetFloat(RoundWaveStrengthId, 0f); + SetImageAlpha(0f); + } + + public void SetColorReveal(float value) + { + SetFloat(ColorRevealId, value); + SetFloat(GrayAmountId, 1f - value); + } + + public Tween TweenColorReveal(float value, float duration) + { + if (!EnsureMaterial()) + { + return null; + } + + value = Mathf.Clamp01(value); + Sequence sequence = DOTween.Sequence(); + sequence.Join(material.DOFloat(value, ColorRevealId, duration)); + sequence.Join(material.DOFloat(1f - value, GrayAmountId, duration)); + return sequence; + } + + public void SetBlur(float value) + { + SetFloat(BlurAmountId, value); + if (EnsureMaterial() && material.HasProperty(BlurSizeId)) + { + material.SetFloat(BlurSizeId, value > 0.01f ? activeBlurSize : 0f); + } + } + + public Tween TweenBlur(float value, float duration) + { + return TweenFloat(BlurAmountId, value, duration); + } + + public void SetWrongColor(float value) + { + SetFloat(WrongColorAmountId, value); + } + + public Tween TweenWrongColor(float value, float duration) + { + return TweenFloat(WrongColorAmountId, value, duration); + } + + public Tween PulseDistortion(float amount, float duration) + { + if (!EnsureMaterial()) + { + return null; + } + + return material.DOFloat(amount, DistortAmountId, Mathf.Max(0.01f, duration * 0.5f)) + .SetEase(Ease.InOutSine) + .SetLoops(2, LoopType.Yoyo); + } + + public void SetImageAlpha(float alpha) + { + if (!driveImageLayer || imageSpriteRenderer == null) + { + return; + } + + imageSpriteRenderer.SetAlpha(alpha); + } + + public Tween TweenImageAlpha(float alpha, float duration) + { + if (!driveImageLayer || imageSpriteRenderer == null) + { + return null; + } + + return imageSpriteRenderer.DOFade(alpha, duration); + } + + public void SetUfWeights(float ascii, float dream, float memory) + { + SetFloat(AsciiAmountId, ascii); + SetFloat(DreamAmountId, dream); + SetFloat(MemoryAmountId, memory); + SetFloat(ScanlineAmountId, Mathf.Max(ascii, memory)); + } + + public Tween TweenUfWeights(float ascii, float dream, float memory, float duration) + { + if (!EnsureMaterial()) + { + return null; + } + + Sequence sequence = DOTween.Sequence(); + sequence.Join(material.DOFloat(Mathf.Clamp01(ascii), AsciiAmountId, duration)); + sequence.Join(material.DOFloat(Mathf.Clamp01(dream), DreamAmountId, duration)); + sequence.Join(material.DOFloat(Mathf.Clamp01(memory), MemoryAmountId, duration)); + sequence.Join(material.DOFloat(Mathf.Clamp01(Mathf.Max(ascii, memory)), ScanlineAmountId, duration)); + return sequence; + } + + public void SetSaturation(float saturation) + { + SetFloatRaw(HsvSaturationId, Mathf.Clamp(saturation, 0f, 2f)); + } + + public Tween TweenSaturation(float saturation, float duration) + { + return TweenFloat(HsvSaturationId, Mathf.Clamp(saturation, 0f, 2f), duration); + } + + public Sequence StartGlitch(float duration = 1f) + { + if (!EnsureMaterial()) + { + return null; + } + + duration = Mathf.Max(0.01f, duration); + Sequence sequence = DOTween.Sequence(); + sequence.Join(material.DOFloat(1f, GlitchAmountId, duration)); + sequence.Join(material.DOFloat(0.02f, DistortAmountId, duration)); + sequence.Join(material.DOFloat(360f, HsvShiftId, duration).SetLoops(-1, LoopType.Yoyo)); + return sequence; + } + + public void StopGlitch(float duration) + { + TweenFloat(GlitchAmountId, 0f, duration); + TweenFloat(DistortAmountId, 0f, duration); + TweenFloat(HsvShiftId, 0f, duration); + } + + public Tween TweenRoundWave(float value, float duration) + { + return TweenFloat(RoundWaveStrengthId, value, duration); + } + + private Tween TweenFloat(int propertyId, float value, float duration) + { + if (!EnsureMaterial() || !material.HasProperty(propertyId)) + { + return null; + } + + return material.DOFloat(value, propertyId, duration); + } + + private void SetFloat(int propertyId, float value) + { + if (!EnsureMaterial() || !material.HasProperty(propertyId)) + { + return; + } + + material.SetFloat(propertyId, Mathf.Clamp01(value)); + } + + private void SetFloatRaw(int propertyId, float value) + { + if (!EnsureMaterial() || !material.HasProperty(propertyId)) + { + return; + } + + material.SetFloat(propertyId, value); + } + } +} diff --git a/Assets/Scripts/MiniGame/Peipei/Eye/EyeTargetVisual.cs.meta b/Assets/Scripts/MiniGame/Peipei/Eye/EyeTargetVisual.cs.meta new file mode 100644 index 000000000..cbc990186 --- /dev/null +++ b/Assets/Scripts/MiniGame/Peipei/Eye/EyeTargetVisual.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a0c7e3c9e6a546b49887860b3f26cf91 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/MiniGame/Peipei/Eye/EyeVisualSettings.cs b/Assets/Scripts/MiniGame/Peipei/Eye/EyeVisualSettings.cs new file mode 100644 index 000000000..29dea88d3 --- /dev/null +++ b/Assets/Scripts/MiniGame/Peipei/Eye/EyeVisualSettings.cs @@ -0,0 +1,70 @@ +using System; +using UnityEngine; + +namespace AibisDream +{ + /// + /// Central tuning for Peipei eye-module visuals. Edit on EyeManager (EyeSystem). + /// + [Serializable] + public class EyeVisualSettings + { + [Header("Color Reveal")] + [Tooltip("Unfocused / gray state (0 = gray, 1 = full color).")] + [Range(0f, 1f)] public float colorRevealMin; + + [Tooltip("Focused / imagined color state.")] + [Range(0f, 1f)] public float colorRevealMax = 1f; + + [Header("Transition Duration (seconds)")] + public float imagineColorDuration = 1f; + public float cannotImagineDuration = 1f; + public float eyeDisorderDuration = 2f; + public float canSeeColorDuration = 1f; + public float targetSwitchDuration = 1f; + + [Header("Blur")] + [Tooltip("Blur when unfocused or module idle.")] + [Range(0f, 1f)] public float idleBlurAmount = 1f; + + [Tooltip("Blur when focused and sharp.")] + [Range(0f, 1f)] public float focusedBlurAmount; + + [Tooltip("Shader _BlurSize when blur is active.")] + [Range(0f, 0.02f)] public float blurSize = 0.008f; + + [Header("Color Sweep (shader)")] + [Tooltip("Width of the directional color sweep during ColorIn/FadeOut.")] + [Range(0.001f, 1f)] public float revealWidth = 0.18f; + + [Tooltip("Sweep direction in radians (0 = left-to-right).")] + [Range(0f, 6.28318f)] public float revealRotation; + + [Range(0f, 1f)] public float revealNoise = 0.08f; + + [Header("Distortion Pulse")] + [Tooltip("Peak _DistortAmount during ColorIn / FadeOut.")] + [Range(0f, 0.08f)] public float colorPulseDistortion = 0.035f; + + [Header("Wrong Color (Eye Disorder)")] + public Color wrongColor = new(1f, 0.16f, 0.08f, 1f); + + [Header("HSV")] + [Range(0f, 2f)] public float hsvSaturation = 1f; + + [Header("Glitch / Memory Wave")] + public float glitchInDuration = 1f; + public float roundWaveInDuration = 2f; + public float roundWaveOutDuration = 0.5f; + public float glitchOutDuration = 0.5f; + + public float GetDurationForState(EyeSystem.EyeColorState state) => state switch + { + EyeSystem.EyeColorState.CanImagineColor => imagineColorDuration, + EyeSystem.EyeColorState.CannotImagineColor => cannotImagineDuration, + EyeSystem.EyeColorState.EyeDisorder => eyeDisorderDuration, + EyeSystem.EyeColorState.CanSeeColor => canSeeColorDuration, + _ => imagineColorDuration + }; + } +} diff --git a/Assets/Scripts/MiniGame/Peipei/Eye/EyeVisualSettings.cs.meta b/Assets/Scripts/MiniGame/Peipei/Eye/EyeVisualSettings.cs.meta new file mode 100644 index 000000000..12e9e6c41 --- /dev/null +++ b/Assets/Scripts/MiniGame/Peipei/Eye/EyeVisualSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2767162520353a0458684a571ce59532 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/MiniGame/Peipei/Eye/IEyeStateEffect.cs b/Assets/Scripts/MiniGame/Peipei/Eye/IEyeStateEffect.cs index e24526f5f..a64378d79 100644 --- a/Assets/Scripts/MiniGame/Peipei/Eye/IEyeStateEffect.cs +++ b/Assets/Scripts/MiniGame/Peipei/Eye/IEyeStateEffect.cs @@ -1,179 +1,133 @@ +using AibisDream; + public interface IEyeStateEffect { - float TransitionDuration { get; } - void InitializeEffect(EyeTarget target, ViewCameraManager cameraManager); + void InitializeEffect(EyeTarget target, EyeSystem eyeSystem); void CleanupEffect(EyeTarget target); - void ApplyFocusedEffect(EyeTarget target); - void ApplyUnfocusedEffect(EyeTarget target); + void ApplyFocusedEffect(EyeTarget target, EyeSystem eyeSystem); + void ApplyUnfocusedEffect(EyeTarget target, EyeSystem eyeSystem); } public class CanImagineColorEffect : IEyeStateEffect { - public float TransitionDuration => 1f; - - public void InitializeEffect(EyeTarget target, ViewCameraManager cameraManager) + public void InitializeEffect(EyeTarget target, EyeSystem eyeSystem) { target.SetToNoWrongColor(); - target.SetToMaxBurnRadius(); + target.SetToMaxColorReveal(); target.SetToMinBlur(); - if (target.targetTransform) - { - cameraManager.SetCameraPosition(target.targetTransform); - } - else - { - cameraManager.SetCameraPosition(target.transform); - } + eyeSystem?.FocusOnTarget(target, 0f); } public void CleanupEffect(EyeTarget target) { - target.SetToMinBurnRadius(); + target.SetToMinColorReveal(); target.SetToMaxBlur(); - // Add cleanup logic here } - public void ApplyFocusedEffect(EyeTarget target) + public void ApplyFocusedEffect(EyeTarget target, EyeSystem eyeSystem) { - target.ColorIn(TransitionDuration); + target.ColorIn(eyeSystem.GetEffectTransitionDuration()); } - public void ApplyUnfocusedEffect(EyeTarget target) + public void ApplyUnfocusedEffect(EyeTarget target, EyeSystem eyeSystem) { - target.FadeOut(TransitionDuration); + target.FadeOut(eyeSystem.GetEffectTransitionDuration()); } } public class CannotImagineColorEffect : IEyeStateEffect { - public float TransitionDuration { get; } = 1f; - - public void InitializeEffect(EyeTarget target, ViewCameraManager cameraManager) + public void InitializeEffect(EyeTarget target, EyeSystem eyeSystem) { - target.SetToMinBlur(false); - target.SetToMinBurnRadius(); + target.SetToMinBlur(); + target.SetToMinColorReveal(); target.SetToNoWrongColor(); - if (target.targetTransform) - { - cameraManager.SetCameraPosition(target.targetTransform); - } - else - { - cameraManager.SetCameraPosition(target.transform); - } + eyeSystem?.FocusOnTarget(target, 0f); } public void CleanupEffect(EyeTarget target) { - // Add cleanup logic here - target.SetToMaxBlur(false); + target.SetToMaxBlur(); } - public void ApplyFocusedEffect(EyeTarget target) + public void ApplyFocusedEffect(EyeTarget target, EyeSystem eyeSystem) { - target.BlurOut(TransitionDuration, false); + target.BlurOut(eyeSystem.GetEffectTransitionDuration()); } - public void ApplyUnfocusedEffect(EyeTarget target) + public void ApplyUnfocusedEffect(EyeTarget target, EyeSystem eyeSystem) { - target.BlurIn(TransitionDuration, false); + target.BlurIn(eyeSystem.GetEffectTransitionDuration()); } } public class EyeDisorderEffect : IEyeStateEffect { - public float TransitionDuration { get; } = 2f; - - public void InitializeEffect(EyeTarget target, ViewCameraManager cameraManager) + public void InitializeEffect(EyeTarget target, EyeSystem eyeSystem) { - target.SetToMinBurnRadius(); - // Add initialization logic here - if (target.targetTransform) - { - cameraManager.SetCameraPosition(target.targetTransform); - } - else - { - cameraManager.SetCameraPosition(target.transform); - } - + target.SetToMinColorReveal(); + eyeSystem?.FocusOnTarget(target, 0f); target.SetToWrongColor(); - target.SetToMinBlur(false); - } - - public void CleanupEffect(EyeTarget target) - { - // Add cleanup logic here - target.SetToNoWrongColor(); - } - - public void ApplyFocusedEffect(EyeTarget target) - { - target.WrongColorIn(TransitionDuration); - } - - public void ApplyUnfocusedEffect(EyeTarget target) - { - target.WrongColorOut(TransitionDuration); - } -} - - -public class CanSeeColorEffect : IEyeStateEffect -{ - public float TransitionDuration { get; } = 1f; - - public void InitializeEffect(EyeTarget target, ViewCameraManager cameraManager) - { - target.SetToNoWrongColor(); - target.SetToMaxBurnRadius(); - if (target.targetTransform) - { - cameraManager.SetCameraPosition(target.targetTransform); - } - else - { - cameraManager.SetCameraPosition(target.transform); - } - target.SetToMinBlur(); } public void CleanupEffect(EyeTarget target) { - // Add cleanup logic here + target.SetToNoWrongColor(); + } + + public void ApplyFocusedEffect(EyeTarget target, EyeSystem eyeSystem) + { + target.WrongColorIn(eyeSystem.GetEffectTransitionDuration()); + } + + public void ApplyUnfocusedEffect(EyeTarget target, EyeSystem eyeSystem) + { + target.WrongColorOut(eyeSystem.GetEffectTransitionDuration()); + } +} + +public class CanSeeColorEffect : IEyeStateEffect +{ + public void InitializeEffect(EyeTarget target, EyeSystem eyeSystem) + { + target.SetToNoWrongColor(); + target.SetToMaxColorReveal(); + eyeSystem?.FocusOnTarget(target, 0f); + target.SetToMinBlur(); + } + + public void CleanupEffect(EyeTarget target) + { target.SetToMaxBlur(); } - public void ApplyFocusedEffect(EyeTarget target) + public void ApplyFocusedEffect(EyeTarget target, EyeSystem eyeSystem) { - target.BlurOut(TransitionDuration); + target.BlurOut(eyeSystem.GetEffectTransitionDuration()); } - public void ApplyUnfocusedEffect(EyeTarget target) + public void ApplyUnfocusedEffect(EyeTarget target, EyeSystem eyeSystem) { - target.BlurIn(TransitionDuration); + target.BlurIn(eyeSystem.GetEffectTransitionDuration()); } } public class HaveChip : IEyeStateEffect { - public float TransitionDuration { get; } = 1f; - - public void InitializeEffect(EyeTarget target, ViewCameraManager cameraManager) + public void InitializeEffect(EyeTarget target, EyeSystem eyeSystem) { } public void CleanupEffect(EyeTarget target) { - // Add cleanup logic here } - public void ApplyFocusedEffect(EyeTarget target) + public void ApplyFocusedEffect(EyeTarget target, EyeSystem eyeSystem) { } - public void ApplyUnfocusedEffect(EyeTarget target) + public void ApplyUnfocusedEffect(EyeTarget target, EyeSystem eyeSystem) { } -} \ No newline at end of file +}