Files
aibis-dream/Assets/Scripts/MiniGame/Peipei/Eye/EyeTarget.cs
T
bottlefishandCursor 29a1c7d7cb feat(peipei): 错色 Error overlay 淡入淡出驱动
自动绑定 sibling Error Sprite,并在 WrongColor 状态切换时同步 overlay alpha。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 16:14:10 +08:00

430 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using 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;
public Color _color;
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()
{
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 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?.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)
{
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)
{
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)
{
AudioManager.Instance.PlaySfx("event:/ActionFB/visualturn");
var tween = unifiedVisual?.TweenBlur(visualSettings.idleBlurAmount, duration);
tween?.SetEase(Ease.InOutSine).OnComplete(StopVisualTurnSfx);
}
public void BlurOut(float duration)
{
AudioManager.Instance.PlaySfx("event:/ActionFB/visualturn");
var tween = unifiedVisual?.TweenBlur(visualSettings.focusedBlurAmount, duration);
tween?.SetEase(Ease.InOutSine).OnComplete(StopVisualTurnSfx);
}
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;
}
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;
}
}
private static void StopVisualTurnSfx()
{
AudioManager.Instance.StopSfx("event:/ActionFB/visualturn");
}
}