456 lines
12 KiB
C#
456 lines
12 KiB
C#
using System;
|
||
using AibisDream;
|
||
using AibisDream.Kit;
|
||
using AibisDream.Utility;
|
||
using DG.Tweening;
|
||
using UnityEngine;
|
||
|
||
public class EyeTarget : MonoBehaviour
|
||
{
|
||
private static readonly int AlphaId = Shader.PropertyToID("_Alpha");
|
||
|
||
public Transform targetTransform;
|
||
|
||
[Header("Optional overlay sprite for UF imagination")]
|
||
[SerializeField] private SpriteRenderer imageSpriteRender;
|
||
|
||
[Header("Wrong-color overlay (e.g. plantError); auto-resolved from sibling if unset")]
|
||
[SerializeField] private SpriteRenderer wrongColorSpriteRenderer;
|
||
|
||
[SerializeField] private Shader unifiedSpriteShader;
|
||
[SerializeField] private EyeTargetVisual unifiedVisual;
|
||
|
||
[Header("Indicator RGB (imagined color for debug overlay)")]
|
||
public Color _color;
|
||
|
||
public Color GetIndicatorColor()
|
||
{
|
||
return new Color(
|
||
RoundIndicatorChannel(_color.r),
|
||
RoundIndicatorChannel(_color.g),
|
||
RoundIndicatorChannel(_color.b),
|
||
_color.a);
|
||
}
|
||
|
||
private static float RoundIndicatorChannel(float value)
|
||
{
|
||
return Mathf.Round(value * 10f) / 10f;
|
||
}
|
||
|
||
private EyeVisualSettings visualSettings = new();
|
||
private Material wrongColorMaterial;
|
||
|
||
private void Awake()
|
||
{
|
||
var spriteRenderer = GetComponent<SpriteRenderer>();
|
||
if (spriteRenderer == null)
|
||
{
|
||
Debug.LogError($"[EyeTarget] {name} 缺少 SpriteRenderer。", this);
|
||
return;
|
||
}
|
||
|
||
EnsureWrongColorOverlay();
|
||
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();
|
||
wrongColorMaterial?.DOKill();
|
||
}
|
||
|
||
private void EnsureVisualReady()
|
||
{
|
||
var spriteRenderer = GetComponent<SpriteRenderer>();
|
||
if (spriteRenderer == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (unifiedVisual == null || !unifiedVisual.IsReady)
|
||
{
|
||
EnsureUnifiedVisual(spriteRenderer);
|
||
}
|
||
}
|
||
|
||
public void Init()
|
||
{
|
||
unifiedVisual?.ClearTransientEffects(visualSettings);
|
||
SetToMinColorReveal();
|
||
SetToMaxBlur();
|
||
SetToNoWrongColor();
|
||
SetNoImage();
|
||
}
|
||
|
||
public void ImageIn(float duration)
|
||
{
|
||
unifiedVisual?.TweenImageAlpha(1f, duration);
|
||
}
|
||
|
||
public void ImageOut(float duration)
|
||
{
|
||
unifiedVisual?.TweenImageAlpha(0f, duration);
|
||
}
|
||
|
||
public void SetNoImage()
|
||
{
|
||
unifiedVisual?.SetImageAlpha(0f);
|
||
}
|
||
|
||
public void SetToMinColorReveal()
|
||
{
|
||
unifiedVisual?.SetColorReveal(visualSettings.colorRevealMin);
|
||
}
|
||
|
||
public void SetToMaxColorReveal()
|
||
{
|
||
unifiedVisual?.SetColorReveal(visualSettings.colorRevealMax);
|
||
}
|
||
|
||
public bool IsAtFocusedColorState(EyeVisualSettings settings = null)
|
||
{
|
||
EyeVisualSettings tuning = settings ?? visualSettings;
|
||
return unifiedVisual != null
|
||
&& unifiedVisual.IsAtColorReveal(tuning.colorRevealMax);
|
||
}
|
||
|
||
public bool IsAtUnfocusedColorState(EyeVisualSettings settings = null)
|
||
{
|
||
EyeVisualSettings tuning = settings ?? visualSettings;
|
||
return unifiedVisual != null
|
||
&& unifiedVisual.IsAtColorReveal(tuning.colorRevealMin);
|
||
}
|
||
|
||
public void SetToMaxBlur()
|
||
{
|
||
unifiedVisual?.SetBlur(visualSettings.idleBlurAmount);
|
||
}
|
||
|
||
public void SetToMinBlur()
|
||
{
|
||
unifiedVisual?.SetBlur(visualSettings.focusedBlurAmount);
|
||
}
|
||
|
||
public void SetToNoWrongColor()
|
||
{
|
||
unifiedVisual?.SetWrongColor(0f);
|
||
SetWrongColorOverlayAlpha(0f);
|
||
}
|
||
|
||
public void SetToWrongColor()
|
||
{
|
||
unifiedVisual?.SetWrongColor(1f);
|
||
SetWrongColorOverlayAlpha(1f);
|
||
}
|
||
|
||
public void FadeOut(float duration)
|
||
{
|
||
unifiedVisual?.KillActiveTweens();
|
||
unifiedVisual?.PlayColorSweepTransition(visualSettings, duration, colorIn: false);
|
||
}
|
||
|
||
public void ColorIn(float duration)
|
||
{
|
||
unifiedVisual?.KillActiveTweens();
|
||
unifiedVisual?.PlayColorSweepTransition(visualSettings, duration, colorIn: true);
|
||
}
|
||
|
||
public void WrongColorIn(float duration)
|
||
{
|
||
unifiedVisual?.TweenWrongColor(1f, duration)?.SetEase(Ease.InOutSine);
|
||
TweenWrongColorOverlay(1f, duration);
|
||
}
|
||
|
||
public void WrongColorOut(float duration)
|
||
{
|
||
unifiedVisual?.TweenWrongColor(0f, duration)?.SetEase(Ease.InOutSine);
|
||
TweenWrongColorOverlay(0f, duration);
|
||
}
|
||
|
||
public void BlurIn(float duration)
|
||
{
|
||
var tween = unifiedVisual?.TweenBlur(visualSettings.idleBlurAmount, duration);
|
||
tween?.SetEase(Ease.InOutSine);
|
||
}
|
||
|
||
public void BlurOut(float duration)
|
||
{
|
||
unifiedVisual?.TweenBlurFocusSettle(visualSettings, duration);
|
||
}
|
||
|
||
public void ColorBack()
|
||
{
|
||
SetToMaxColorReveal();
|
||
SetToNoWrongColor();
|
||
SetToMinBlur();
|
||
}
|
||
|
||
public void ColorLost()
|
||
{
|
||
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;
|
||
}
|
||
|
||
if (!shader.isSupported)
|
||
{
|
||
Debug.LogError($"[EyeTarget] AIBIS/EyeUnifiedSprite 在当前平台不受支持:{name}", this);
|
||
return;
|
||
}
|
||
|
||
Material currentMaterial = Application.isPlaying
|
||
? spriteRenderer.material
|
||
: spriteRenderer.sharedMaterial;
|
||
|
||
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;
|
||
var runtimeMaterial = new Material(shader)
|
||
{
|
||
name = $"{gameObject.name}_EyeUnified_Runtime"
|
||
};
|
||
if (mainTex != null)
|
||
{
|
||
runtimeMaterial.SetTexture("_MainTex", mainTex);
|
||
}
|
||
|
||
if (Application.isPlaying)
|
||
{
|
||
spriteRenderer.material = runtimeMaterial;
|
||
}
|
||
else
|
||
{
|
||
spriteRenderer.sharedMaterial = runtimeMaterial;
|
||
}
|
||
}
|
||
|
||
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 EnsureWrongColorOverlay()
|
||
{
|
||
if (wrongColorSpriteRenderer == null && transform.parent != null)
|
||
{
|
||
string errorName = $"{gameObject.name}Error";
|
||
foreach (var renderer in transform.parent.GetComponentsInChildren<SpriteRenderer>(true))
|
||
{
|
||
if (string.Equals(renderer.gameObject.name, errorName, StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
wrongColorSpriteRenderer = renderer;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (wrongColorSpriteRenderer == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
wrongColorMaterial = Application.isPlaying
|
||
? wrongColorSpriteRenderer.material
|
||
: wrongColorSpriteRenderer.sharedMaterial;
|
||
wrongColorSpriteRenderer.enabled = true;
|
||
SetWrongColorOverlayAlpha(0f);
|
||
}
|
||
|
||
private void SetWrongColorOverlayAlpha(float alpha)
|
||
{
|
||
if (wrongColorSpriteRenderer == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
alpha = Mathf.Clamp01(alpha);
|
||
if (alpha > 0f)
|
||
{
|
||
wrongColorSpriteRenderer.gameObject.SetActive(true);
|
||
wrongColorSpriteRenderer.enabled = true;
|
||
}
|
||
|
||
if (wrongColorMaterial != null && wrongColorMaterial.HasProperty(AlphaId))
|
||
{
|
||
wrongColorMaterial.SetFloat(AlphaId, alpha);
|
||
}
|
||
|
||
if (alpha <= 0f)
|
||
{
|
||
wrongColorSpriteRenderer.gameObject.SetActive(false);
|
||
}
|
||
}
|
||
|
||
private void TweenWrongColorOverlay(float alpha, float duration)
|
||
{
|
||
if (wrongColorSpriteRenderer == null || wrongColorMaterial == null || !wrongColorMaterial.HasProperty(AlphaId))
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (alpha > 0f)
|
||
{
|
||
wrongColorSpriteRenderer.gameObject.SetActive(true);
|
||
wrongColorSpriteRenderer.enabled = true;
|
||
}
|
||
|
||
wrongColorMaterial.DOKill();
|
||
wrongColorMaterial
|
||
.DOFloat(alpha, AlphaId, duration)
|
||
.SetEase(Ease.InOutSine)
|
||
.OnComplete(() =>
|
||
{
|
||
if (alpha <= 0f && wrongColorSpriteRenderer != null)
|
||
{
|
||
wrongColorSpriteRenderer.gameObject.SetActive(false);
|
||
}
|
||
});
|
||
}
|
||
|
||
private static bool IsWrongColorOverlayRenderer(SpriteRenderer renderer)
|
||
{
|
||
return renderer != null
|
||
&& renderer.gameObject.name.EndsWith("Error", StringComparison.OrdinalIgnoreCase);
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
if (IsWrongColorOverlayRenderer(renderer))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
renderer.enabled = false;
|
||
}
|
||
}
|
||
}
|