refactor(peipei-eye): 重构 Eye 上色为 unified 驱动并集中调参

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-30 12:54:23 +08:00
co-authored by Cursor
parent 4f6f5a1ae9
commit 07d330f6db
10 changed files with 1045 additions and 459 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8f92d49bad6ceaa4983976ea6bb47c46
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -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
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 193d982b27c7dd34cb2aa48c07b1df09
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+257 -291
View File
@@ -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<EyeTarget> targets = new(); // 保存目标列表
public List<EyeTarget> Targets => targets; // 提供目标列表的公共访问
private EyeTarget currentTarget; // 当前选中的目标
public EyeTarget CurrentTarget => currentTarget; // 提供当前目标的公共访问
public RawImage eyeImage;
[SerializeField] private List<EyeTarget> targets = new();
public List<EyeTarget> 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;
/// <summary>获取当前 Eye 颜色阶段。</summary>
public EyeColorState GetCurrentColorState() => _currentState;
public float GetEffectTransitionDuration() => visualSettings.GetDurationForState(_currentState);
private void OnValidate()
{
ApplyVisualSettingsNow(
previewIdleState: !Application.isPlaying,
replayFocusedEffect: Application.isPlaying && replayFocusedEffectOnSettingsChange);
}
/// <summary>
/// 将 Visual Tuning 推送到所有 EyeTarget。Edit 模式预览 idle;Play 模式可选重播当前目标效果。
/// </summary>
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;
/// <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();
@@ -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<Camera>();
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<Camera>();
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;
}
}
}
+229 -63
View File
@@ -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<SpriteRenderer>();
forwardMaterial = spriteRenderer.material;
forwardMaterial.SetFloat("_SourceGlowDissolveFade", burnRadiusMin);
var spriteRenderer = GetComponent<SpriteRenderer>();
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<SpriteRenderer>();
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();
}
}
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<EyeTargetVisual>();
}
if (unifiedVisual == null)
{
unifiedVisual = gameObject.AddComponent<EyeTargetVisual>();
}
unifiedVisual.Configure(spriteRenderer, imageSpriteRender);
unifiedVisual.ApplyTuning(visualSettings);
}
private void DisableLegacyChildRenderers()
{
foreach (var childRenderer in GetComponentsInChildren<SpriteRenderer>(true))
{
if (childRenderer.gameObject == gameObject)
{
continue;
}
if (imageSpriteRender != null && childRenderer == imageSpriteRender)
{
continue;
}
childRenderer.enabled = false;
}
}
/// <summary>
/// 禁用同组下旧版 overlay(如 posterNoColor / computernocolor),避免盖住 unified 效果。
/// </summary>
private void DisableLegacySiblingRenderers()
{
Transform groupRoot = transform.parent;
if (groupRoot == null)
{
return;
}
foreach (var renderer in groupRoot.GetComponentsInChildren<SpriteRenderer>(true))
{
if (renderer.gameObject == gameObject)
{
continue;
}
if (renderer.GetComponent<EyeTarget>() != null)
{
continue;
}
if (renderer.GetComponentInParent<EyeTarget>() != null)
{
continue;
}
renderer.enabled = false;
}
}
private static void StopVisualTurnSfx()
{
AudioManager.Instance.StopSfx("event:/ActionFB/visualturn");
}
}
@@ -0,0 +1,312 @@
using DG.Tweening;
using UnityEngine;
using AibisDream.Utility;
namespace AibisDream
{
/// <summary>
/// Drives the unified EyeUnifiedSprite path for Peipei eye targets.
/// </summary>
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<SpriteRenderer>();
}
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);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a0c7e3c9e6a546b49887860b3f26cf91
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,70 @@
using System;
using UnityEngine;
namespace AibisDream
{
/// <summary>
/// Central tuning for Peipei eye-module visuals. Edit on EyeManager (EyeSystem).
/// </summary>
[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
};
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2767162520353a0458684a571ce59532
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -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)
{
}
}
}