diff --git a/Assets/Scripts/FixSystemNew/BodyModule/BodyModuleYarnCommand.cs b/Assets/Scripts/FixSystemNew/BodyModule/BodyModuleYarnCommand.cs
index 06cc1057a..d9b3a6459 100644
--- a/Assets/Scripts/FixSystemNew/BodyModule/BodyModuleYarnCommand.cs
+++ b/Assets/Scripts/FixSystemNew/BodyModule/BodyModuleYarnCommand.cs
@@ -159,7 +159,7 @@ namespace AibisDream
[YarnCommand("RetractCable")]
public static void RetractCable()
{
- CablePanel.PullUpCable();
+ CablePanel?.PullUpCable();
}
[YarnCommand("StartHeadBreathing")]
diff --git a/Assets/Scripts/FixSystemNew/Screen System/FixPanel/CablePanel.cs b/Assets/Scripts/FixSystemNew/Screen System/FixPanel/CablePanel.cs
index cd598e842..643377b7f 100644
--- a/Assets/Scripts/FixSystemNew/Screen System/FixPanel/CablePanel.cs
+++ b/Assets/Scripts/FixSystemNew/Screen System/FixPanel/CablePanel.cs
@@ -36,6 +36,10 @@ namespace AibisDream.FixSystem
#region 系统状态
public bool isCableRetracted = true; // 线缆是否收起
+ // 与 isCableRetracted(当前可交互状态)分开记录最后一次指令的目标,
+ // 防止相反方向或外部 DOKill 触发旧动画回调,把线缆恢复到错误状态。
+ private bool targetCableRetracted = true;
+
[SerializeField] private Transform retractedPos; // 收起位置
private ISocket curSocket;
@@ -86,6 +90,8 @@ namespace AibisDream.FixSystem
private void InitCableVisualFromPrefab()
{
+ targetCableRetracted = isCableRetracted;
+
if (isCableRetracted)
{
SetRetractCable();
@@ -145,6 +151,8 @@ namespace AibisDream.FixSystem
public void DropDownCableImmediate()
{
+ targetCableRetracted = false;
+ PlugRef.transform.DOKill(false);
PlugRef.PullUpSocketSilent();
CableReelRef.ResetRotation();
PlugRef.RestoreAtStartPositionImmediate();
@@ -212,14 +220,25 @@ namespace AibisDream.FixSystem
}
}
+ ///
+ /// 从插孔拔出(若已插入),放回初始可插线位:线缆放下、可拖拽,不收起。
+ ///
public void ResetPlug()
{
- if (IsPlugInSocket())
+ bool wasPlugged = IsPlugInSocket();
+ if (wasPlugged)
{
PlugRef.PullUpSocket();
}
BodyModuleSystem.CloseModuleSlots(null);
+
+ // 已在初始可插线位且未收起:只关槽,不重复放线/音效
+ if (!wasPlugged && !isCableRetracted && !targetCableRetracted)
+ {
+ return;
+ }
+
DropDownCableImmediate();
AudioManager.Instance.PlaySfx("event:/ActionFB/mods_close");
@@ -313,45 +332,71 @@ namespace AibisDream.FixSystem
return BodyModuleSystem.TryFindClosestModule(sourcePos, out targetModule);
}
+ /// 收起线缆:无论是否插在模块上,统一收到线盘位。
public void PullUpCable()
{
- if (isCableRetracted) return;
-
- if (IsPlugInSocket())
+ bool wasPlugged = IsPlugInSocket();
+ if (wasPlugged)
{
PlugRef.PullUpSocket();
}
BodyModuleSystem.CloseModuleSlots(null);
- // 收线动画:绳身按纯插值收拢到收纳位(不走拖拽物理,避免其阻尼参数在极短时长内来不及收敛而甩鞭),
- // 插头 DOMove 与绳收拢共用同一时长,动画结束时绳已真正收完,再切换到收起态不会有可见的切割感
+ // 已在收起或正在收起,且本次无需拔插:不重复收线动画/音效
+ if (targetCableRetracted && !wasPlugged)
+ {
+ isCableRetracted = true;
+ return;
+ }
+
+ targetCableRetracted = true;
+ isCableRetracted = true;
+
+ PlugRef.transform.DOKill(false);
+
+ if (physicCableRef.State == PhysicCable.CableState.Hidden)
+ {
+ ApplyRetractedState();
+ return;
+ }
+
suppressPlugFollow = true;
physicCableRef.CollapseTo(retractedPos.position, RetractDuration);
PlugRef.transform.DOMove(retractedPos.position, RetractDuration)
- .OnComplete(() =>
- {
- ApplyRetractedState();
- isCableRetracted = true;
- });
+ .OnComplete(CompleteRetractIfCurrent)
+ .OnKill(CompleteRetractIfCurrent);
AudioManager.Instance.PlaySfx("event:/ActionFB/mods_close");
AudioManager.Instance.PlaySfx("event:/FollowInput/plugdrop");
}
+ private void CompleteRetractIfCurrent()
+ {
+ if (!targetCableRetracted) return;
+ ApplyRetractedState();
+ isCableRetracted = true;
+ }
+
public void DropDownCable()
{
- if (!isCableRetracted) return;
- // 确保 Plug 已脱离 Socket(收起状态下通常已脱离,此处为防御性调用)
+ if (!isCableRetracted && !targetCableRetracted) return;
+
+ targetCableRetracted = false;
PlugRef.PullUpSocket();
+ PlugRef.transform.DOKill(false);
CableReelRef.ResetRotation();
suppressPlugFollow = true;
- PlugRef.transform.DOMove(PlugRef.GetStartPos(), 0.1f).OnComplete(() =>
- {
- suppressPlugFollow = false;
- physicCableRef.ShowFree(true);
- isCableRetracted = false;
- });
+ PlugRef.transform.DOMove(PlugRef.GetStartPos(), 0.1f).OnComplete(CompleteDropIfCurrent)
+ .OnKill(CompleteDropIfCurrent);
+ }
+
+ private void CompleteDropIfCurrent()
+ {
+ if (targetCableRetracted) return;
+ suppressPlugFollow = false;
+ physicCableRef.ShowFree(true);
+ isCableRetracted = false;
}
/// 应用收起状态的视觉与组件设置(不含动画、不含 isCableRetracted 更新)
@@ -360,8 +405,6 @@ namespace AibisDream.FixSystem
physicCableRef.Hide();
suppressPlugFollow = false;
- // 强制收起时长可能短于拔出反馈动画(挤压 punch scale),未播完就会被打断,
- // 收起完成后强制清掉,避免插头带着没播完的形变停在收纳位
PlugRef.CancelFeedbackTween();
PlugRef.transform.position = retractedPos.position;
@@ -374,8 +417,10 @@ namespace AibisDream.FixSystem
public void SetRetractCable()
{
- ApplyRetractedState();
+ targetCableRetracted = true;
isCableRetracted = true;
+ PlugRef.transform.DOKill(false);
+ ApplyRetractedState();
}
#region 灯光系统 - 供外部调用
diff --git a/Assets/Scripts/FixSystemNew/States/CoreFixCues.cs b/Assets/Scripts/FixSystemNew/States/CoreFixCues.cs
index ae0a3a799..997b92879 100644
--- a/Assets/Scripts/FixSystemNew/States/CoreFixCues.cs
+++ b/Assets/Scripts/FixSystemNew/States/CoreFixCues.cs
@@ -84,7 +84,7 @@ namespace AibisDream.FixSystem
}
else
{
- FixPanelSystem.GetRepairPanel().ResetPlug();
+ FixPanelSystem.GetRepairPanel()?.ResetPlug();
yield return CameraKit.Instance.SwitchCamera(CameraEnum.BodyModule);
}
@@ -104,7 +104,7 @@ namespace AibisDream.FixSystem
bodyModuleSystem.SwitchModuleGroup(moduleState);
}
- FixPanelSystem.GetRepairPanel().ResetPlug();
+ FixPanelSystem.GetRepairPanel()?.ResetPlug();
yield return CameraKit.Instance.SwitchCamera(CameraEnum.BodyModule, true);
BubbleSlotKit.Instance.LoadBubbles(BubbleSlotEnum.BodyModule);
@@ -117,9 +117,7 @@ namespace AibisDream.FixSystem
public IEnumerator Exit(FixTransition transition)
{
var bodyModuleSystem = FixSystemCenter.SystemDic.Get();
- // 拔出插头
- FixPanelSystem.GetRepairPanel().ResetPlug();
- // 关闭交互
+ FixPanelSystem.GetRepairPanel()?.PullUpCable();
bodyModuleSystem.DisableSystem();
yield break;
}
diff --git a/Assets/Scripts/FixSystemNew/States/CutFixCues.cs b/Assets/Scripts/FixSystemNew/States/CutFixCues.cs
index 28476e628..a6810382f 100644
--- a/Assets/Scripts/FixSystemNew/States/CutFixCues.cs
+++ b/Assets/Scripts/FixSystemNew/States/CutFixCues.cs
@@ -23,7 +23,7 @@ namespace AibisDream.FixSystem
// Cut的气泡统一放在BodyModule下
BubbleSlotKit.Instance.LoadBubbles(BubbleSlotEnum.Cut);
- FixPanelSystem.GetRepairPanel().ResetPlug();
+ FixPanelSystem.GetRepairPanel()?.PullUpCable();
var bodyModule = bodyModuleSystem.FindBodyModuleByName("Emo");
if (bodyModule != null)
{
@@ -70,7 +70,7 @@ namespace AibisDream.FixSystem
// Cut的气泡统一放在BodyModule下
BubbleSlotKit.Instance.LoadBubbles(BubbleSlotEnum.Cut);
- FixPanelSystem.GetRepairPanel().ResetPlug();
+ FixPanelSystem.GetRepairPanel()?.PullUpCable();
var bodyModule = bodyModuleSystem.FindBodyModuleByName("Memory");
if (bodyModule != null)
{
@@ -117,6 +117,7 @@ namespace AibisDream.FixSystem
// Cut的气泡统一放在BodyModule下
BubbleSlotKit.Instance.LoadBubbles(BubbleSlotEnum.Cut);
+ FixPanelSystem.GetRepairPanel()?.PullUpCable();
var bodyModule = bodyModuleSystem.FindBodyModuleByName("Logic");
if (bodyModule != null)
{
diff --git a/Assets/Scripts/FixSystemNew/States/HuoShanFixCues.cs b/Assets/Scripts/FixSystemNew/States/HuoShanFixCues.cs
index 8ebe2186b..3396821fe 100644
--- a/Assets/Scripts/FixSystemNew/States/HuoShanFixCues.cs
+++ b/Assets/Scripts/FixSystemNew/States/HuoShanFixCues.cs
@@ -41,8 +41,8 @@ namespace AibisDream.FixSystem
var bodyModuleSystem = FixSystemCenter.SystemDic.Get();
yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f);
- // 重置身体模块
- FixPanelSystem.GetRepairPanel().ResetPlug();
+ // 离开表达深入:保持线缆收起,回到 BodyModule 后由 Yarn DropCable 再放线
+ FixPanelSystem.GetRepairPanel()?.PullUpCable();
// 关闭表达系统视图
expressionManager.CloseView();
@@ -77,7 +77,7 @@ namespace AibisDream.FixSystem
public IEnumerator Exit(FixTransition transition)
{
- FixPanelSystem.GetRepairPanel().ResetPlug();
+ FixPanelSystem.GetRepairPanel()?.PullUpCable();
yield break;
}
}
@@ -98,8 +98,7 @@ namespace AibisDream.FixSystem
yield return CameraKit.Instance.SwitchCamera(CameraEnum.BodyModule);
}
- // 插头回到初始插孔
- FixPanelSystem.GetRepairPanel().ResetPlug();
+ FixPanelSystem.GetRepairPanel()?.PullUpCable();
// 切换到分析模式相机
yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f);
diff --git a/Assets/Scripts/FixSystemNew/States/PeipeiFixCues.cs b/Assets/Scripts/FixSystemNew/States/PeipeiFixCues.cs
index a7f50b802..028b913e4 100644
--- a/Assets/Scripts/FixSystemNew/States/PeipeiFixCues.cs
+++ b/Assets/Scripts/FixSystemNew/States/PeipeiFixCues.cs
@@ -21,9 +21,7 @@ namespace AibisDream.FixSystem
yield return CameraKit.Instance.SwitchCamera(CameraEnum.BodyModule);
}
- // 插头回到初始插孔
- FixPanelSystem.GetRepairPanel().ResetPlug();
- // 切换相机
+ FixPanelSystem.GetRepairPanel()?.PullUpCable();
yield return CameraKit.Instance.SwitchCamera(CameraEnum.UF);
yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f);
ufSystem.OpenUFView();
@@ -65,9 +63,7 @@ namespace AibisDream.FixSystem
var eyeModule = bodyModuleSystem.FindBodyModuleByType();
yield return eyeModule.OpenEye();
- // 插头回到初始插孔
- FixPanelSystem.GetRepairPanel().ResetPlug();
- // 切换相机
+ FixPanelSystem.GetRepairPanel()?.PullUpCable();
yield return CameraKit.Instance.SwitchCamera(CameraEnum.Eye);
yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f);
yield return CameraKit.Instance.SwitchCamera(CameraEnum.EyeDeep);
@@ -118,9 +114,7 @@ namespace AibisDream.FixSystem
}
yield return memorySystem.DropMemoryProjector();
- // 插头回到初始插孔
- FixPanelSystem.GetRepairPanel().ResetPlug();
- // 相机聚焦到目标位
+ FixPanelSystem.GetRepairPanel()?.PullUpCable();
yield return CameraKit.Instance.SwitchCamera(CameraEnum.Memory);
yield return UIManager.Instance.GetPanel().FadeInAsync(duration);
memorySystem.OnEnter();
@@ -134,7 +128,7 @@ namespace AibisDream.FixSystem
FixPanelSystem.Instance.TaskPanel?.CollapsePanelTemporary(immediate: true);
yield return memorySystem.DropMemoryProjector();
- FixPanelSystem.GetRepairPanel().ResetPlug();
+ FixPanelSystem.GetRepairPanel()?.PullUpCable();
yield return CameraKit.Instance.SwitchCamera(CameraEnum.Memory, true);
memorySystem.OnEnter();
BubbleSlotKit.Instance.LoadBubbles(BubbleSlotEnum.Memory);