768 lines
23 KiB
C#
768 lines
23 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using DG.Tweening;
|
|
using Yarn.Unity;
|
|
using System.Linq;
|
|
using UnityEngine.UI;
|
|
using AibisDream.FixSystem;
|
|
using AibisDream.Framework;
|
|
using AibisDream.Kit;
|
|
using AibisDream.SaveSystem;
|
|
using UnityEngine.ResourceManagement.AsyncOperations;
|
|
using Sequence = DG.Tweening.Sequence;
|
|
|
|
namespace AibisDream
|
|
{
|
|
public class EyeSystem : MonoBehaviour
|
|
{
|
|
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;
|
|
|
|
[Header("Memory Overlay (UI)")]
|
|
public Image memoryRender;
|
|
public GameObject eyeView;
|
|
|
|
[Header("Focus Pan Bounds")]
|
|
[SerializeField] private Vector2 focusMinBounds = new(30.2f, -4.5f);
|
|
[SerializeField] private Vector2 focusMaxBounds = new(50.2f, 5f);
|
|
|
|
[Header("Visual Tuning")]
|
|
[SerializeField] private EyeVisualSettings visualSettings = new();
|
|
|
|
[SerializeField] private EyeViewportOverlay viewportOverlay;
|
|
|
|
[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;
|
|
|
|
public EyeColorState GetCurrentColorState() => _currentState;
|
|
|
|
public float GetEffectTransitionDuration() => visualSettings.GetDurationForState(_currentState);
|
|
|
|
/// <summary>仅「可想象色彩」上色时眨眼;无 autoBlink / 失焦眨眼。</summary>
|
|
private bool ShouldBlinkForImagine()
|
|
{
|
|
return _currentState == EyeColorState.CanImagineColor;
|
|
}
|
|
|
|
private IEnumerator WaitForFocusMovement(float moveDuration)
|
|
{
|
|
if (!EnsureMouseFollowAndZoom())
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
yield return mouseFollowAndZoom.WaitForFocusMove(moveDuration);
|
|
}
|
|
|
|
private IEnumerator RunFocusedEffectWithPreBlink(EyeTarget target)
|
|
{
|
|
if (EnsureMouseFollowAndZoom())
|
|
{
|
|
yield return mouseFollowAndZoom.WaitForFocusMove();
|
|
}
|
|
|
|
float duration = GetEffectTransitionDuration();
|
|
EyeViewportOverlay overlay = EnsureViewportOverlay();
|
|
|
|
if (overlay != null && Application.isPlaying && ShouldBlinkForImagine())
|
|
{
|
|
yield return overlay.PlayPreEffectBlinkThen(
|
|
2,
|
|
visualSettings,
|
|
() => eyeStateEffect?.ApplyFocusedEffect(target, this),
|
|
visualSettings.imagineEffectAtBlinkOpen,
|
|
visualSettings.imagineBlinkGap);
|
|
}
|
|
else
|
|
{
|
|
eyeStateEffect?.ApplyFocusedEffect(target, this);
|
|
}
|
|
|
|
yield return new WaitForSeconds(duration);
|
|
}
|
|
|
|
private IEnumerator RunBlurOut(EyeTarget target, float duration)
|
|
{
|
|
if (target != null)
|
|
{
|
|
target.BlurOut(duration);
|
|
}
|
|
|
|
yield return new WaitForSeconds(duration);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 换目标时的失焦:只做效果,不眨眼(眨眼仅在想象上色 FadeIn)。
|
|
/// </summary>
|
|
private void ApplyUnfocusedEffectSilent(EyeTarget target)
|
|
{
|
|
if (target == null || eyeStateEffect == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_currentState == EyeColorState.CanImagineColor
|
|
&& target.IsAtUnfocusedColorState(visualSettings))
|
|
{
|
|
return;
|
|
}
|
|
|
|
eyeStateEffect.ApplyUnfocusedEffect(target, this);
|
|
}
|
|
|
|
private IEnumerator RunUnfocusedEffect(EyeTarget target)
|
|
{
|
|
if (target == null || eyeStateEffect == null)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
eyeStateEffect.ApplyUnfocusedEffect(target, this);
|
|
yield return new WaitForSeconds(GetEffectTransitionDuration());
|
|
}
|
|
|
|
private void OnValidate()
|
|
{
|
|
ApplyVisualSettingsNow(
|
|
previewIdleState: !Application.isPlaying,
|
|
replayFocusedEffect: Application.isPlaying && replayFocusedEffectOnSettingsChange,
|
|
touchViewportOverlay: false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 将 Visual Tuning 推送到所有 EyeTarget。Edit 模式预览 idle;Play 模式可选重播当前目标效果。
|
|
/// </summary>
|
|
public void ApplyVisualSettingsNow(
|
|
bool previewIdleState = false,
|
|
bool replayFocusedEffect = false,
|
|
bool touchViewportOverlay = true)
|
|
{
|
|
if (targets == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (EyeTarget target in targets)
|
|
{
|
|
if (target == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
target.BindVisualSettings(visualSettings);
|
|
if (previewIdleState)
|
|
{
|
|
target.ApplyIdlePreviewState();
|
|
}
|
|
}
|
|
|
|
if (touchViewportOverlay && Application.isPlaying)
|
|
{
|
|
EnsureViewportOverlay()?.ApplySettings(visualSettings);
|
|
}
|
|
|
|
if (!replayFocusedEffect || !Application.isPlaying || currentTarget == null || eyeStateEffect == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
currentTarget.KillVisualTweens();
|
|
eyeStateEffect.ApplyFocusedEffect(currentTarget, this);
|
|
}
|
|
|
|
private void ApplyVisualSettingsToTargets()
|
|
{
|
|
ApplyVisualSettingsNow();
|
|
}
|
|
|
|
public enum EyeColorState
|
|
{
|
|
CanImagineColor,
|
|
CannotImagineColor,
|
|
EyeDisorder,
|
|
CanSeeColor,
|
|
HaveChip
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
Init();
|
|
}
|
|
|
|
private EyeViewportOverlay EnsureViewportOverlay()
|
|
{
|
|
if (viewportOverlay != null)
|
|
{
|
|
return viewportOverlay;
|
|
}
|
|
|
|
viewportOverlay = GetComponentInChildren<EyeViewportOverlay>(true);
|
|
if (viewportOverlay == null)
|
|
{
|
|
viewportOverlay = gameObject.AddComponent<EyeViewportOverlay>();
|
|
}
|
|
|
|
return viewportOverlay;
|
|
}
|
|
|
|
private bool EnsureMouseFollowAndZoom()
|
|
{
|
|
if (mouseFollowAndZoom != null)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
mouseFollowAndZoom = FindObjectOfType<MouseFollowAndZoom>(true);
|
|
if (mouseFollowAndZoom == null)
|
|
{
|
|
Debug.LogError("[EyeSystem] MouseFollowAndZoom 未找到,无法进入视觉模块。", this);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private Vector2 GetFocusViewportSize()
|
|
{
|
|
if (EnsureMouseFollowAndZoom())
|
|
{
|
|
Vector2 viewportSize = mouseFollowAndZoom.GetViewportWorldSize();
|
|
if (viewportSize.sqrMagnitude > 0f)
|
|
{
|
|
return viewportSize;
|
|
}
|
|
}
|
|
|
|
Camera focusCamera = CameraKit.Instance != null
|
|
? CameraKit.Instance.GetCurrentCamera()
|
|
: Camera.main;
|
|
if (focusCamera == null || !focusCamera.orthographic)
|
|
{
|
|
return Vector2.zero;
|
|
}
|
|
|
|
float height = focusCamera.orthographicSize * 2f;
|
|
return new Vector2(height * focusCamera.aspect, height);
|
|
}
|
|
|
|
private static Transform GetFocusTransform(EyeTarget target)
|
|
{
|
|
if (target == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return target.targetTransform ? target.targetTransform : target.transform;
|
|
}
|
|
|
|
public void FocusOnTarget(EyeTarget target, float duration)
|
|
{
|
|
Transform focusTransform = GetFocusTransform(target);
|
|
if (focusTransform == null || !EnsureMouseFollowAndZoom())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (duration > 0.01f)
|
|
{
|
|
AudioManager.Instance.PlaySfx("event:/ActionFB/visualturn");
|
|
}
|
|
|
|
mouseFollowAndZoom.MoveFocusTo(
|
|
focusTransform,
|
|
duration,
|
|
focusMinBounds,
|
|
focusMaxBounds,
|
|
GetFocusViewportSize());
|
|
}
|
|
|
|
public void Init()
|
|
{
|
|
FixSystemCenter.SystemDic.Register(this);
|
|
}
|
|
|
|
public EyeSnapshotDto CaptureEyeSnapshot()
|
|
{
|
|
return new EyeSnapshotDto { eyeColorState = _currentState.ToString() };
|
|
}
|
|
|
|
public void ApplyEyeSnapshot(EyeSnapshotDto dto)
|
|
{
|
|
if (dto == null || string.IsNullOrEmpty(dto.eyeColorState))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Enum.TryParse(dto.eyeColorState, true, out EyeColorState state))
|
|
{
|
|
SetEyeColorState(state);
|
|
}
|
|
}
|
|
|
|
public void OnEnter()
|
|
{
|
|
if (!EnsureMouseFollowAndZoom())
|
|
{
|
|
return;
|
|
}
|
|
|
|
mouseFollowAndZoom.SetIsActive(true);
|
|
mouseFollowAndZoom.SetIsLock(false);
|
|
mouseFollowAndZoom.ResetPanOrigin();
|
|
ApplyVisualSettingsToTargets();
|
|
InitializeAllTargets();
|
|
EnsureViewportOverlay()?.EnterModule(visualSettings);
|
|
}
|
|
|
|
/// <summary>
|
|
/// UF 等密集演出:抑制非显式眨眼(含想象过渡眨眼);Yarn EyeBlink 仍可用。
|
|
/// </summary>
|
|
public void SetNonExplicitBlinkSuppressed(bool suppressed)
|
|
{
|
|
EnsureViewportOverlay()?.SetNonExplicitBlinkSuppressed(suppressed);
|
|
}
|
|
|
|
private void InitializeAllTargets()
|
|
{
|
|
foreach (EyeTarget target in targets)
|
|
{
|
|
target.Init();
|
|
}
|
|
|
|
if (currentTarget != null)
|
|
{
|
|
eyeStateEffect?.InitializeEffect(currentTarget, this);
|
|
}
|
|
}
|
|
|
|
public void OnShow()
|
|
{
|
|
}
|
|
|
|
public void OnExit()
|
|
{
|
|
EnsureViewportOverlay()?.ExitModule();
|
|
|
|
if (currentTarget != null)
|
|
{
|
|
eyeStateEffect?.CleanupEffect(CurrentTarget);
|
|
}
|
|
|
|
if (EnsureMouseFollowAndZoom())
|
|
{
|
|
mouseFollowAndZoom.SetIsActive(false);
|
|
}
|
|
|
|
currentTarget = null;
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
ApplyVisualSettingsToTargets();
|
|
if (targets != null)
|
|
{
|
|
foreach (EyeTarget target in targets)
|
|
{
|
|
target?.Init();
|
|
}
|
|
}
|
|
|
|
SetEyeColorState(_currentState);
|
|
EnsureMouseFollowAndZoom();
|
|
}
|
|
|
|
public EyeTarget FindEyeTargetByName(string name)
|
|
{
|
|
return Targets.FirstOrDefault(target => target.gameObject.name == name);
|
|
}
|
|
|
|
public void SetTarget(EyeTarget newTarget)
|
|
{
|
|
if (newTarget == null)
|
|
{
|
|
Debug.LogError("Target is null in SetTarget");
|
|
return;
|
|
}
|
|
|
|
StartCoroutine(SetTargetCoroutine(newTarget.gameObject.name));
|
|
}
|
|
|
|
[YarnCommand("EyeBlink")]
|
|
public void EyeBlink(float duration = 0f)
|
|
{
|
|
EnsureViewportOverlay()?.PlayBlink(duration > 0f ? duration : null, restartAutoBlinkAfter: true);
|
|
}
|
|
|
|
[YarnCommand("set_Eyetarget")]
|
|
public IEnumerator SetTargetCoroutine(string targetName, bool startDialogue = true)
|
|
{
|
|
if (!EnsureMouseFollowAndZoom())
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
mouseFollowAndZoom.SetIsLock(true);
|
|
EyeTarget target = FindEyeTargetByName(targetName);
|
|
if (target == null)
|
|
{
|
|
Debug.LogError("Invalid EyeTarget name: " + targetName);
|
|
yield break;
|
|
}
|
|
|
|
YarnVariableStorage.Instance.SetValue("$currentEyeTarget", target.name);
|
|
|
|
if (currentTarget == target)
|
|
{
|
|
mouseFollowAndZoom.SetIndicatorTarget(currentTarget);
|
|
if (startDialogue)
|
|
{
|
|
DialogController.Instance.StartDialogNode("重复看同一个目标");
|
|
yield return RunBlurOut(currentTarget, visualSettings.targetSwitchDuration);
|
|
}
|
|
|
|
yield break;
|
|
}
|
|
|
|
EyeTarget leavingTarget = currentTarget;
|
|
if (leavingTarget != null)
|
|
{
|
|
ApplyUnfocusedEffectSilent(leavingTarget);
|
|
}
|
|
|
|
const float focusMoveDuration = 1f;
|
|
FocusOnTarget(target, focusMoveDuration);
|
|
|
|
yield return WaitForFocusMovement(focusMoveDuration);
|
|
|
|
currentTarget = target;
|
|
mouseFollowAndZoom.SetIndicatorTarget(currentTarget);
|
|
yield return RunBlurOut(currentTarget, visualSettings.targetSwitchDuration);
|
|
|
|
if (startDialogue)
|
|
{
|
|
DialogController.Instance.StartDialogNode("IntoEyeView");
|
|
}
|
|
}
|
|
|
|
[YarnCommand("Set_MouseMovementLockState")]
|
|
public void SetMouseMovementLockState(bool isActive)
|
|
{
|
|
if (!EnsureMouseFollowAndZoom())
|
|
{
|
|
return;
|
|
}
|
|
|
|
mouseFollowAndZoom.SetIsLock(isActive);
|
|
}
|
|
|
|
[YarnCommand("EyeEffect_FadeIn")]
|
|
public IEnumerator EyeEffect_FadeIn()
|
|
{
|
|
if (currentTarget == null)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
if (_currentState == EyeColorState.CanImagineColor
|
|
&& currentTarget.IsAtFocusedColorState(visualSettings))
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine");
|
|
yield return RunFocusedEffectWithPreBlink(currentTarget);
|
|
}
|
|
|
|
[YarnCommand("EyeEffect_FadeOut")]
|
|
public IEnumerator EyeEffect_FadeOut()
|
|
{
|
|
if (currentTarget == null)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
if (_currentState == EyeColorState.CanImagineColor
|
|
&& currentTarget.IsAtUnfocusedColorState(visualSettings))
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
AudioManager.Instance.PlaySfx("event:/ActionFB/color_imagine");
|
|
yield return RunUnfocusedEffect(currentTarget);
|
|
}
|
|
|
|
[YarnCommand("EyeEffect_Init")]
|
|
public void EyeEffectInit()
|
|
{
|
|
ApplyVisualSettingsToTargets();
|
|
InitializeAllTargets();
|
|
}
|
|
|
|
[YarnCommand("EyeEffect_Clean")]
|
|
public void EyeEffectClean()
|
|
{
|
|
if (currentTarget != null)
|
|
{
|
|
eyeStateEffect?.CleanupEffect(currentTarget);
|
|
}
|
|
}
|
|
|
|
[YarnCommand("set_EyeColorState")]
|
|
public void SetEyeColorStateForYarn(string state)
|
|
{
|
|
if (!Enum.TryParse(state, true, out EyeColorState eyeState))
|
|
{
|
|
throw new ArgumentException("Invalid eye state: " + state, nameof(state));
|
|
}
|
|
|
|
SetEyeColorState(eyeState);
|
|
}
|
|
|
|
private void SetEyeColorState(EyeColorState state)
|
|
{
|
|
_currentState = state;
|
|
eyeStateEffect = state switch
|
|
{
|
|
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)
|
|
{
|
|
targetSaturation = Mathf.Clamp01(targetSaturation);
|
|
|
|
Sequence saturationSequence = DOTween.Sequence();
|
|
if (!TryJoinTargetSaturation(saturationSequence, targetSaturation, duration))
|
|
{
|
|
Debug.LogWarning("[EyeSystem] 无可用 EyeTarget 饱和度 tween。", this);
|
|
yield break;
|
|
}
|
|
|
|
Tween saturationTween = ScreenEffectManager.Instance != null
|
|
? ScreenEffectManager.Instance.TweenSaturation(targetSaturation, duration)
|
|
: null;
|
|
if (saturationTween != null)
|
|
{
|
|
saturationSequence.Join(saturationTween);
|
|
}
|
|
|
|
yield return saturationSequence.WaitForCompletion();
|
|
}
|
|
|
|
[YarnCommand("EyeGlitch_in")]
|
|
public IEnumerator EyeGlitch_in()
|
|
{
|
|
if (!TryStartUnifiedGlitch())
|
|
{
|
|
Debug.LogWarning("[EyeSystem] 无可用 EyeTarget Glitch tween。", this);
|
|
}
|
|
|
|
yield return new WaitForSeconds(visualSettings.glitchInDuration);
|
|
}
|
|
|
|
[YarnCommand("EyeGlitch_out")]
|
|
public void EyeGlitch_out(float duration)
|
|
{
|
|
TryStopUnifiedGlitch(duration > 0f ? duration : visualSettings.glitchOutDuration);
|
|
}
|
|
|
|
[YarnCommand("set_EyeColor")]
|
|
public IEnumerator SetEyeColor(string color, string memoryName = null)
|
|
{
|
|
if (memoryRender == null)
|
|
{
|
|
Debug.LogError("[EyeSystem] memoryRender 未赋值。", this);
|
|
yield break;
|
|
}
|
|
|
|
Material memoryMaterial = memoryRender.material;
|
|
memoryRender.sprite = null;
|
|
memoryMaterial.SetFloat("_FullDistortionFade", 0f);
|
|
memoryMaterial.SetFloat("_SqueezePower", 18f);
|
|
|
|
if (memoryName != null)
|
|
{
|
|
var memoryKey = string.Format(MemorySpritePath, memoryName);
|
|
var memoryHandle = ResourceSystem.LoadAsync<Sprite>(memoryKey);
|
|
yield return memoryHandle;
|
|
if (memoryHandle.Status != AsyncOperationStatus.Succeeded || memoryHandle.Result == null)
|
|
{
|
|
Debug.LogWarning("Memory not found: " + memoryKey);
|
|
yield break;
|
|
}
|
|
|
|
memoryRender.sprite = memoryHandle.Result;
|
|
memoryRender.gameObject.SetActive(true);
|
|
|
|
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);
|
|
}));
|
|
|
|
yield return memorySequence.WaitForCompletion();
|
|
}
|
|
|
|
Sequence sequence = DOTween.Sequence();
|
|
|
|
Sequence waveIn = CreateTargetRoundWaveSequence(1f, visualSettings.roundWaveInDuration);
|
|
if (waveIn != null)
|
|
{
|
|
sequence.Append(waveIn);
|
|
}
|
|
|
|
sequence.AppendCallback(() => { EyeGlitch_out(visualSettings.glitchOutDuration); });
|
|
|
|
Sequence waveOut = CreateTargetRoundWaveSequence(0f, visualSettings.roundWaveOutDuration);
|
|
if (waveOut != null)
|
|
{
|
|
sequence.Append(waveOut);
|
|
}
|
|
|
|
sequence.Play();
|
|
yield return sequence.WaitForCompletion();
|
|
}
|
|
|
|
[YarnCommand("EyeGetColor")]
|
|
public void GetColor()
|
|
{
|
|
SetEyeColorState(EyeColorState.CanImagineColor);
|
|
foreach (EyeTarget target in targets)
|
|
{
|
|
target.ColorBack();
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|