Files
aibis-dream/Assets/Scripts/FixSystemNew/FixSceneDirector.cs
T
dingyuntian d316922b3a fix(fix-system): 修复维修中心销毁时的依赖清理异常
FixSystemCenter.OnSingletonDestroy 在场景销毁阶段访问的 CameraKit、
BubbleSlotKit 可能已清理,且 Director.QuitCurrentMode 协程依赖的
对象可能已拆除。改为判空访问,并新增 Director.Reset 直接清理状态。
2026-07-18 23:59:19 +08:00

129 lines
4.5 KiB
C#

using System.Collections;
using AibisDream.Framework;
using UnityEngine;
namespace AibisDream.FixSystem
{
/// <summary>
/// Directs Fix scene mode transitions. This is a scene cue board, not a gameplay state machine:
/// cues orchestrate cameras, timelines, UI masks, bubbles and interaction setup.
/// </summary>
public class FixSceneDirector
{
public FixSceneMode CurrentMode { get; private set; }
public string CurrentArgs { get; private set; } = "";
public bool HasMode { get; private set; }
public bool IsTransitioning { get; private set; }
private IFixSceneCue _currentCue;
public IEnumerator Init(FixSceneMode initMode)
{
yield return TransitionInternal(initMode, "", FixTransitionMode.Immediate);
}
public IEnumerator TransitionTo(FixSceneMode nextMode, string args = "")
{
yield return TransitionInternal(nextMode, args, FixTransitionMode.Animated);
}
public IEnumerator TransitionToImmediate(FixSceneMode nextMode, string args = "")
{
yield return TransitionInternal(nextMode, args, FixTransitionMode.Immediate);
}
public IEnumerator QuitCurrentMode()
{
if (_currentCue != null)
{
var transition = new FixTransition(CurrentMode, FixSceneMode.Default, "", FixTransitionMode.Animated);
yield return _currentCue.Exit(transition);
}
CurrentArgs = "";
_currentCue = null;
CurrentMode = FixSceneMode.Default;
HasMode = false;
IsTransitioning = false;
}
/// <summary>
/// Clears director state without running cue exits. Used while the owning scene is
/// being destroyed, when cue dependencies may already have been torn down.
/// </summary>
public void Reset()
{
CurrentArgs = "";
_currentCue = null;
CurrentMode = FixSceneMode.Default;
HasMode = false;
IsTransitioning = false;
}
private IEnumerator TransitionInternal(FixSceneMode nextMode, string args, FixTransitionMode mode)
{
if (IsTransitioning && mode == FixTransitionMode.Animated)
{
Debug.LogWarning($"[FixSceneDirector] Transition ignored while another transition is running: {CurrentMode} -> {nextMode}");
yield break;
}
if (HasMode && CurrentMode.Equals(nextMode))
{
yield break;
}
IsTransitioning = true;
var transition = new FixTransition(HasMode ? CurrentMode : null, nextMode, args, mode);
if (mode == FixTransitionMode.Animated && _currentCue != null)
{
yield return _currentCue.Exit(transition);
}
_currentCue = CreateCue(nextMode);
CurrentMode = nextMode;
CurrentArgs = args ?? "";
HasMode = true;
EnumEventSystem.Global.Send(EventEnum.FixSceneModeChanged, nextMode);
if (mode == FixTransitionMode.Immediate)
{
yield return _currentCue.EnterImmediate(transition);
}
else
{
yield return _currentCue.Enter(transition);
}
IsTransitioning = false;
}
private static IFixSceneCue CreateCue(FixSceneMode nextMode)
{
return nextMode switch
{
FixSceneMode.Default => new DefaultCue(),
FixSceneMode.Clinic => new ClinicCue(),
FixSceneMode.BodyModule => new BodyModuleCue(),
FixSceneMode.Memory => new MemoryCue(),
FixSceneMode.Eye => new EyeCue(),
FixSceneMode.UF => new UfCue(),
FixSceneMode.Expression => new ExpressionCue(),
FixSceneMode.Emo => new EmoCue(),
FixSceneMode.Op => new OpCue(),
FixSceneMode.EmoCut => new EmoCutCue(),
FixSceneMode.MemoryCut => new MemoryCutCue(),
FixSceneMode.LogicCut => new LogicCutCue(),
FixSceneMode.Dream => new DreamCue(),
FixSceneMode.AnalysisMode => new AnalysisModeCue(),
FixSceneMode.Sales => new SalesCue(),
FixSceneMode.BlockPuzzle => new BlockPuzzleCue(),
_ => new DefaultCue()
};
}
}
}