440 lines
12 KiB
C#
440 lines
12 KiB
C#
using System;
|
||
using System.Collections;
|
||
using UnityEngine;
|
||
using AibisDream;
|
||
using AibisDream.FixSystem;
|
||
using UnityEngine.Rendering;
|
||
using Yarn.Unity;
|
||
using DG.Tweening;
|
||
using VolFx;
|
||
using AibisDream.Kit;
|
||
|
||
public class UFSystem : MonoBehaviour
|
||
{
|
||
private GameObject _UFCover;
|
||
private GameObject _UAudioule;
|
||
|
||
private EyeSystem eyeSystem;
|
||
|
||
public GameObject UFPanel;
|
||
|
||
public SpriteRenderer face;
|
||
|
||
private bool isLoopImage;
|
||
|
||
[Header("Global UF Cover")]
|
||
[SerializeField] private Volume FullAscillVolume;
|
||
|
||
[Header("Target Post-Processing Volumes")]
|
||
[SerializeField] private Volume imageAscillVolume;
|
||
[SerializeField] private Volume imageVolume;
|
||
[SerializeField] private Volume finalVolume;
|
||
|
||
private AsciiVol ascii;
|
||
private Tween scaleTween;
|
||
|
||
public enum UFState
|
||
{
|
||
UF,
|
||
imagination,
|
||
memory
|
||
}
|
||
|
||
private float PresentationSpeed => eyeSystem != null ? eyeSystem.PresentationSpeed : 1f;
|
||
|
||
private float ScaleDuration(float duration) =>
|
||
eyeSystem != null ? eyeSystem.ScaleDuration(duration) : duration;
|
||
|
||
private void PlayPresentationSfx(string eventName)
|
||
{
|
||
AudioManager.Instance.PlaySfx(eventName, pitch: PresentationSpeed);
|
||
}
|
||
|
||
private void Awake()
|
||
{
|
||
FixSystemCenter.SystemDic.Register(this);
|
||
eyeSystem = FindObjectOfType<EyeSystem>();
|
||
ClearUnifiedUfSpriteWeights();
|
||
}
|
||
|
||
public void TweenWeight(Volume postProcessingVolume, float targetWeight, float duration)
|
||
{
|
||
if (postProcessingVolume == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
DOTween.To(() => postProcessingVolume.weight, x => postProcessingVolume.weight = x, targetWeight, duration);
|
||
}
|
||
|
||
private void ClearUnifiedUfSpriteWeights()
|
||
{
|
||
eyeSystem?.SetUnifiedUfWeights(0f, 0f, 0f);
|
||
}
|
||
|
||
private EyeTarget ResolveSpriteTarget()
|
||
{
|
||
if (eyeSystem == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
if (eyeSystem.CurrentTarget != null)
|
||
{
|
||
return eyeSystem.CurrentTarget;
|
||
}
|
||
|
||
if (YarnVariableStorage.Instance != null
|
||
&& YarnVariableStorage.Instance.TryGetValue("$currentEyeTarget", out string targetName)
|
||
&& !string.IsNullOrEmpty(targetName))
|
||
{
|
||
return eyeSystem.FindEyeTargetByName(targetName);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
[YarnCommand("UF_spriteIn")]
|
||
public IEnumerator UF_spriteIn(float duration = 1.5f)
|
||
{
|
||
duration = ScaleDuration(duration);
|
||
var target = ResolveSpriteTarget();
|
||
if (target != null)
|
||
{
|
||
PlayPresentationSfx("event:/ActionFB/color_imagine");
|
||
target.ImageIn(duration);
|
||
}
|
||
|
||
yield return new WaitForSeconds(duration);
|
||
}
|
||
|
||
[YarnCommand("UF_spriteOut")]
|
||
public IEnumerator UF_spriteOut(float duration = 1.5f)
|
||
{
|
||
duration = ScaleDuration(duration);
|
||
var target = ResolveSpriteTarget();
|
||
if (target != null)
|
||
{
|
||
PlayPresentationSfx("event:/ActionFB/color_imagine");
|
||
target.ImageOut(duration);
|
||
}
|
||
|
||
yield return new WaitForSeconds(duration);
|
||
}
|
||
|
||
[YarnCommand("UF_AllspriteIn")]
|
||
public IEnumerator UF_AllspriteIn(float duration = 1.5f)
|
||
{
|
||
duration = ScaleDuration(duration);
|
||
foreach (EyeTarget target in eyeSystem.Targets)
|
||
{
|
||
target.ImageIn(duration);
|
||
}
|
||
|
||
yield return new WaitForSeconds(duration);
|
||
}
|
||
|
||
[YarnCommand("UF_AllspriteOut")]
|
||
public IEnumerator UF_AllspriteOut(float duration = 1.5f)
|
||
{
|
||
duration = ScaleDuration(duration);
|
||
foreach (EyeTarget target in eyeSystem.Targets)
|
||
{
|
||
target.ImageOut(duration);
|
||
}
|
||
|
||
yield return new WaitForSeconds(duration);
|
||
}
|
||
|
||
[YarnCommand("UF_faceIn")]
|
||
public IEnumerator UF_faceIn(float duration = 1.5f)
|
||
{
|
||
if (face == null)
|
||
{
|
||
Debug.LogWarning("[UFSystem] UF_faceIn: face SpriteRenderer 未绑定。", this);
|
||
yield break;
|
||
}
|
||
|
||
if (face.sprite == null)
|
||
{
|
||
Debug.LogWarning("[UFSystem] UF_faceIn: face.sprite 为空(可能是 aseprite 重导入后子资源 ID 失效)。", this);
|
||
}
|
||
|
||
duration = ScaleDuration(duration);
|
||
face.gameObject.SetActive(true);
|
||
face.DOFade(1f, duration);
|
||
yield return new WaitForSeconds(duration);
|
||
}
|
||
|
||
[YarnCommand("UF_faceOut")]
|
||
public IEnumerator UF_faceOut(float duration = 1.5f)
|
||
{
|
||
if (face == null)
|
||
{
|
||
yield break;
|
||
}
|
||
|
||
duration = ScaleDuration(duration);
|
||
face.DOFade(0f, duration);
|
||
yield return new WaitForSeconds(duration);
|
||
face.gameObject.SetActive(false);
|
||
}
|
||
|
||
[YarnCommand("UF_ImaginationEffectIn")]
|
||
public IEnumerator UF_ImaginationEffectIn(float duration = 1.5f)
|
||
{
|
||
duration = ScaleDuration(duration);
|
||
PlayPresentationSfx("event:/ActionFB/color_imagine");
|
||
ClearUnifiedUfSpriteWeights();
|
||
TweenWeight(imageVolume, 1f, duration);
|
||
yield return new WaitForSeconds(0f);
|
||
}
|
||
|
||
[YarnCommand("UF_ImaginationEffectOut")]
|
||
public IEnumerator UF_ImaginationEffectOut(float duration = 1.5f)
|
||
{
|
||
duration = ScaleDuration(duration);
|
||
TweenWeight(imageVolume, 0f, duration);
|
||
PlayPresentationSfx("event:/ActionFB/color_imagine");
|
||
yield return new WaitForSeconds(0f);
|
||
}
|
||
|
||
[YarnCommand("UF_MemoryEffectIn")]
|
||
public IEnumerator UF_MemoryEffectIn(float duration = 1.5f)
|
||
{
|
||
duration = ScaleDuration(duration);
|
||
PlayPresentationSfx("event:/ActionFB/color_imagine");
|
||
ClearUnifiedUfSpriteWeights();
|
||
TweenWeight(finalVolume, 1f, duration);
|
||
yield return new WaitForSeconds(0f);
|
||
}
|
||
|
||
[YarnCommand("UF_MemoryEffectOut")]
|
||
public IEnumerator UF_MemoryEffectOut(float duration = 1.5f)
|
||
{
|
||
duration = ScaleDuration(duration);
|
||
TweenWeight(finalVolume, 0f, duration);
|
||
PlayPresentationSfx("event:/ActionFB/color_imagine");
|
||
yield return new WaitForSeconds(0f);
|
||
}
|
||
|
||
[YarnCommand("UF_EyeTargetAscillIn")]
|
||
public IEnumerator UF_EyeTargetAscillIn(float duration = 1.5f)
|
||
{
|
||
duration = ScaleDuration(duration);
|
||
PlayPresentationSfx("event:/ActionFB/color_imagine");
|
||
ClearUnifiedUfSpriteWeights();
|
||
TweenWeight(imageAscillVolume, 1f, duration);
|
||
yield return new WaitForSeconds(0f);
|
||
}
|
||
|
||
[YarnCommand("UF_EyeTargetAscillOut")]
|
||
public IEnumerator UF_EyeTargetAscillOut(float duration = 1.5f)
|
||
{
|
||
duration = ScaleDuration(duration);
|
||
TweenWeight(imageAscillVolume, 0f, duration);
|
||
PlayPresentationSfx("event:/ActionFB/color_imagine");
|
||
yield return new WaitForSeconds(0f);
|
||
}
|
||
|
||
[YarnCommand("UF_SetBorkenValue")]
|
||
public void UF_Borken(int value)
|
||
{
|
||
if (FullAscillVolume == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (!FullAscillVolume.gameObject.activeInHierarchy)
|
||
{
|
||
FullAscillVolume.gameObject.SetActive(true);
|
||
}
|
||
|
||
if (FullAscillVolume.profile.TryGet(out ascii))
|
||
{
|
||
ascii.m_Depth.value = value;
|
||
ascii.m_Ascii.value = Color.red;
|
||
}
|
||
}
|
||
|
||
[YarnCommand("StartUFEffect_loop")]
|
||
public void UFImageLoop()
|
||
{
|
||
StartCoroutine(UFImageLoopProcess());
|
||
}
|
||
|
||
[YarnCommand("StopUFEffect_loop")]
|
||
public void StopUFImageLoop()
|
||
{
|
||
isLoopImage = false;
|
||
}
|
||
|
||
[YarnCommand("UF_fightEffect")]
|
||
public void UF_fightEffect()
|
||
{
|
||
ClearUnifiedUfSpriteWeights();
|
||
float loopDuration = ScaleDuration(1f);
|
||
scaleTween = DOTween.To(() => 0f, t =>
|
||
{
|
||
if (imageVolume != null)
|
||
{
|
||
imageVolume.weight = Mathf.Lerp(0f, 1f, t);
|
||
}
|
||
|
||
if (imageAscillVolume != null)
|
||
{
|
||
imageAscillVolume.weight = Mathf.Lerp(0f, 1f, t);
|
||
}
|
||
|
||
if (finalVolume != null)
|
||
{
|
||
finalVolume.weight = Mathf.Lerp(1f, 0f, t);
|
||
}
|
||
}, 1f, loopDuration)
|
||
.SetEase(Ease.InOutSine)
|
||
.SetLoops(-1, LoopType.Yoyo);
|
||
}
|
||
|
||
[YarnCommand("UF_StopfightEffect")]
|
||
public void UF_StopfightEffect()
|
||
{
|
||
scaleTween?.Kill();
|
||
}
|
||
|
||
public IEnumerator UFImageLoopProcess()
|
||
{
|
||
int index = 0;
|
||
isLoopImage = true;
|
||
while (isLoopImage)
|
||
{
|
||
eyeSystem.StartCoroutine(eyeSystem.SetTargetCoroutine(eyeSystem.Targets[index].name, false));
|
||
yield return new WaitForSeconds(ScaleDuration(0.5f));
|
||
StartCoroutine(UF_spriteIn(0.5f));
|
||
StartCoroutine(UF_ImaginationEffectIn(0.5f));
|
||
eyeSystem.Targets[index].ImageIn(ScaleDuration(0.5f));
|
||
yield return new WaitForSeconds(ScaleDuration(0.5f));
|
||
StartCoroutine(UF_ImaginationEffectOut(0.5f));
|
||
StartCoroutine(UF_MemoryEffectIn(0.5f));
|
||
yield return new WaitForSeconds(ScaleDuration(1f));
|
||
eyeSystem.Targets[index].ImageOut(ScaleDuration(0.5f));
|
||
StartCoroutine(UF_MemoryEffectOut(0.5f));
|
||
index++;
|
||
if (index >= eyeSystem.Targets.Count - 2)
|
||
{
|
||
index = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
public void OpenUFView()
|
||
{
|
||
ClearUnifiedUfSpriteWeights();
|
||
// 先于 EyeSystem.OnEnter:UF 段 SwitchState / sprite 极密,禁止 autoBlink 与过渡眨眼
|
||
eyeSystem?.SetNonExplicitBlinkSuppressed(true);
|
||
|
||
if (FullAscillVolume != null && !FullAscillVolume.gameObject.activeInHierarchy)
|
||
{
|
||
FullAscillVolume.gameObject.SetActive(true);
|
||
}
|
||
|
||
if (imageAscillVolume != null)
|
||
{
|
||
imageAscillVolume.weight = 1f;
|
||
}
|
||
|
||
if (imageVolume != null)
|
||
{
|
||
imageVolume.weight = 0f;
|
||
}
|
||
|
||
if (finalVolume != null)
|
||
{
|
||
finalVolume.weight = 0f;
|
||
}
|
||
}
|
||
|
||
public void CloseUFView()
|
||
{
|
||
if (FullAscillVolume != null && FullAscillVolume.gameObject.activeInHierarchy)
|
||
{
|
||
FullAscillVolume.gameObject.SetActive(false);
|
||
}
|
||
|
||
if (imageAscillVolume != null)
|
||
{
|
||
imageAscillVolume.weight = 1f;
|
||
}
|
||
|
||
if (imageVolume != null)
|
||
{
|
||
imageVolume.weight = 0f;
|
||
}
|
||
|
||
if (finalVolume != null)
|
||
{
|
||
finalVolume.weight = 0f;
|
||
}
|
||
|
||
ClearUnifiedUfSpriteWeights();
|
||
eyeSystem?.SetNonExplicitBlinkSuppressed(false);
|
||
}
|
||
|
||
public void OpenCover()
|
||
{
|
||
var bodyModuleSystem = FixSystemCenter.SystemDic.Get<BodyModuleSystem>();
|
||
_UFCover = bodyModuleSystem.FindBodyModuleByName("UF").transform.Find("Cover").gameObject;
|
||
if (_UFCover.activeInHierarchy)
|
||
{
|
||
_UFCover.SetActive(false);
|
||
}
|
||
}
|
||
|
||
public void RemoveUF()
|
||
{
|
||
var bodyModuleSystem = FixSystemCenter.SystemDic.Get<BodyModuleSystem>();
|
||
_UAudioule = bodyModuleSystem.FindBodyModuleByName("UF").gameObject;
|
||
if (_UAudioule.activeInHierarchy)
|
||
{
|
||
_UAudioule.SetActive(false);
|
||
}
|
||
}
|
||
|
||
[YarnCommand("UF_SwitchState")]
|
||
public IEnumerator SwitchState(string stateName, float duration)
|
||
{
|
||
if (!Enum.TryParse(stateName, true, out UFState state))
|
||
{
|
||
Debug.LogError($"Invalid state name: {stateName}");
|
||
yield break;
|
||
}
|
||
|
||
duration = ScaleDuration(duration);
|
||
PlayPresentationSfx("event:/ActionFB/color_imagine");
|
||
ClearUnifiedUfSpriteWeights();
|
||
|
||
switch (state)
|
||
{
|
||
case UFState.UF:
|
||
TweenWeight(imageAscillVolume, 1f, duration);
|
||
TweenWeight(imageVolume, 0f, duration);
|
||
TweenWeight(finalVolume, 0f, duration);
|
||
break;
|
||
case UFState.imagination:
|
||
TweenWeight(imageAscillVolume, 0f, duration);
|
||
TweenWeight(imageVolume, 1f, duration);
|
||
TweenWeight(finalVolume, 0f, duration);
|
||
break;
|
||
case UFState.memory:
|
||
TweenWeight(imageAscillVolume, 0f, duration);
|
||
TweenWeight(imageVolume, 0f, duration);
|
||
TweenWeight(finalVolume, 1f, duration);
|
||
break;
|
||
default:
|
||
Debug.LogError($"Unhandled state: {state}");
|
||
yield break;
|
||
}
|
||
|
||
yield return new WaitForSeconds(duration);
|
||
}
|
||
}
|