feat: rewrite 3D step undo using an exact ActionHistory stack
This commit is contained in:
@@ -208,111 +208,9 @@ public class StepManager : MonoBehaviour
|
||||
|
||||
private bool TryUndoActiveHandler()
|
||||
{
|
||||
if (_pingStepIndex > 0 && _pingStepIndex <= _pingMaxStep)
|
||||
{
|
||||
if (_pingObjects == null) InitPingSteps();
|
||||
PingStepPrevious();
|
||||
return true;
|
||||
}
|
||||
if (_womanStepIndex > 0 && _womanStepIndex <= _womanMaxStep && _pingStepIndex == 0)
|
||||
{
|
||||
WomanStepPrevious();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return ActionHistory.TryUndoLast();
|
||||
}
|
||||
|
||||
private void PingStepPrevious()
|
||||
{
|
||||
if (_pingStepIndex <= 0) return;
|
||||
int idx = (_pingStepIndex - 1) / 2; // ping index (0-3, mapping to 004-001)
|
||||
bool wasSecond = (_pingStepIndex - 1) % 2 == 1; // true if was second click
|
||||
|
||||
if (wasSecond)
|
||||
{
|
||||
// Undo second click: hide chanrao, restore ping to first-click state
|
||||
if (_chanraoObjects != null && idx < _chanraoObjects.Length && _chanraoObjects[idx] != null)
|
||||
_chanraoObjects[idx].SetActive(false);
|
||||
if (_pingObjects != null && idx < _pingObjects.Length && _pingObjects[idx] != null)
|
||||
{
|
||||
var h = _pingObjects[idx].GetComponent<PingClickHandler>();
|
||||
if (h != null) h.UndoSecondClick();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Undo first click: reset current ping to blink state, and hide the next ping it spawned
|
||||
if (_pingObjects != null && idx < _pingObjects.Length && _pingObjects[idx] != null)
|
||||
{
|
||||
var h = _pingObjects[idx].GetComponent<PingClickHandler>();
|
||||
if (h != null)
|
||||
{
|
||||
// 撤销它对下一个目标的影响
|
||||
if (h.nextPing != null)
|
||||
{
|
||||
h.nextPing.SetActive(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果是最后一个,撤销它唤醒的所有其他边框
|
||||
var allPings = Object.FindObjectsOfType<PingClickHandler>();
|
||||
foreach (var p in allPings)
|
||||
{
|
||||
if (p.gameObject != h.gameObject)
|
||||
{
|
||||
p.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 重置自己到初始状态
|
||||
h.ResetState();
|
||||
}
|
||||
}
|
||||
}
|
||||
_pingStepIndex--;
|
||||
Debug.Log($"StepManager: Ping撤销 -> {_pingStepIndex}");
|
||||
OnStepChanged?.Invoke(_pingStepIndex);
|
||||
}
|
||||
|
||||
private void PingStepNext()
|
||||
{
|
||||
if (_pingStepIndex >= _pingMaxStep) return;
|
||||
int idx = _pingStepIndex / 2;
|
||||
bool isSecond = _pingStepIndex % 2 == 1;
|
||||
|
||||
if (!isSecond)
|
||||
{
|
||||
// Advance to first click: ensure ping is visible and in first-click state
|
||||
if (_pingObjects != null && idx < _pingObjects.Length && _pingObjects[idx] != null)
|
||||
{
|
||||
var ping = _pingObjects[idx];
|
||||
ping.SetActive(true);
|
||||
var h = ping.GetComponent<PingClickHandler>();
|
||||
if (h != null)
|
||||
{
|
||||
h.UndoSecondClick(); // Reset to first-click state
|
||||
// Trigger first click via reflection/method
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Advance to second click: show chanrao
|
||||
if (_chanraoObjects != null && idx < _chanraoObjects.Length && _chanraoObjects[idx] != null)
|
||||
_chanraoObjects[idx].SetActive(true);
|
||||
if (_pingObjects != null && idx < _pingObjects.Length && _pingObjects[idx] != null)
|
||||
{
|
||||
var h = _pingObjects[idx].GetComponent<PingClickHandler>();
|
||||
if (h != null) h.UndoShow();
|
||||
}
|
||||
// Show next ping for first click
|
||||
if (idx + 1 < 4 && _pingObjects != null && _pingObjects[idx+1] != null)
|
||||
_pingObjects[idx+1].SetActive(true);
|
||||
}
|
||||
_pingStepIndex++;
|
||||
Debug.Log($"StepManager: Ping前进 -> {_pingStepIndex}");
|
||||
OnStepChanged?.Invoke(_pingStepIndex);
|
||||
}
|
||||
|
||||
public void RecordPingStep(int pingIndex, bool secondClick)
|
||||
{
|
||||
@@ -321,6 +219,20 @@ public class StepManager : MonoBehaviour
|
||||
OnStepChanged?.Invoke(_pingStepIndex);
|
||||
}
|
||||
|
||||
public void DecrementPingStep()
|
||||
{
|
||||
_pingStepIndex--;
|
||||
Debug.Log($"StepManager: Ping撤销 -> {_pingStepIndex}");
|
||||
OnStepChanged?.Invoke(_pingStepIndex);
|
||||
}
|
||||
|
||||
public void DecrementWomanStep()
|
||||
{
|
||||
if (_womanStepIndex > 0) _womanStepIndex--;
|
||||
Debug.Log($"StepManager: Woman撤销 -> {_womanStepIndex}");
|
||||
OnStepChanged?.Invoke(_womanStepIndex);
|
||||
}
|
||||
|
||||
public void PreviousStep()
|
||||
{
|
||||
Debug.LogError("====== StepManager: 接收到 PreviousStep 指令! ======");
|
||||
@@ -429,25 +341,6 @@ public class StepManager : MonoBehaviour
|
||||
|
||||
public void RecordWomanStep(int newStepIndex) { _womanStepIndex = Mathf.Clamp(newStepIndex, 0, _womanMaxStep); Debug.Log($"StepManager: Woman步进 -> {_womanStepIndex}"); OnStepChanged?.Invoke(_womanStepIndex); }
|
||||
|
||||
private void WomanStepPrevious()
|
||||
{
|
||||
if (_womanStepIndex <= 0) return;
|
||||
_womanStepIndex--;
|
||||
MoveWomanToStep(_womanStepIndex);
|
||||
UpdateTouchVisibility(_womanStepIndex);
|
||||
Debug.Log($"StepManager: Woman撤销 -> {_womanStepIndex}");
|
||||
OnStepChanged?.Invoke(_womanStepIndex);
|
||||
}
|
||||
|
||||
private void WomanStepNext()
|
||||
{
|
||||
if (_womanStepIndex >= _womanMaxStep) return;
|
||||
_womanStepIndex++;
|
||||
MoveWomanToStep(_womanStepIndex);
|
||||
UpdateTouchVisibility(_womanStepIndex);
|
||||
Debug.Log($"StepManager: Woman前进 -> {_womanStepIndex}");
|
||||
OnStepChanged?.Invoke(_womanStepIndex);
|
||||
}
|
||||
|
||||
private void MoveWomanToStep(int step)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public static class ActionHistory
|
||||
{
|
||||
public enum ActionType
|
||||
{
|
||||
Shose,
|
||||
ChanraoTuibu,
|
||||
PingFirst,
|
||||
PingSecond,
|
||||
Woman
|
||||
}
|
||||
|
||||
public class HistoryItem
|
||||
{
|
||||
public ActionType Type;
|
||||
public MonoBehaviour Handler;
|
||||
public int ExtraInt;
|
||||
}
|
||||
|
||||
public static Stack<HistoryItem> History = new Stack<HistoryItem>();
|
||||
|
||||
public static bool TryUndoLast()
|
||||
{
|
||||
if (History.Count == 0) return false;
|
||||
var item = History.Pop();
|
||||
|
||||
if (item.Type == ActionType.Shose)
|
||||
{
|
||||
var h = item.Handler as ShoseClickHandler;
|
||||
if (h != null) h.ResetState();
|
||||
}
|
||||
else if (item.Type == ActionType.ChanraoTuibu)
|
||||
{
|
||||
var h = item.Handler as ChanraoTuibuHandler;
|
||||
if (h != null) h.ResetState();
|
||||
}
|
||||
else if (item.Type == ActionType.PingSecond)
|
||||
{
|
||||
var h = item.Handler as PingClickHandler;
|
||||
if (h != null) h.UndoSecondClick();
|
||||
|
||||
// 撤销对 UI 步骤的影响
|
||||
var sm = Object.FindObjectOfType<StepManager>();
|
||||
if (sm != null) sm.DecrementPingStep();
|
||||
}
|
||||
else if (item.Type == ActionType.PingFirst)
|
||||
{
|
||||
var h = item.Handler as PingClickHandler;
|
||||
if (h != null)
|
||||
{
|
||||
if (h.nextPing != null) h.nextPing.SetActive(false);
|
||||
else
|
||||
{
|
||||
var allPings = Object.FindObjectsOfType<PingClickHandler>();
|
||||
foreach (var p in allPings) { if (p != h) p.UndoShow(); }
|
||||
}
|
||||
h.ResetState();
|
||||
}
|
||||
|
||||
var sm = Object.FindObjectOfType<StepManager>();
|
||||
if (sm != null) sm.DecrementPingStep();
|
||||
}
|
||||
else if (item.Type == ActionType.Woman)
|
||||
{
|
||||
var sm = Object.FindObjectOfType<StepManager>();
|
||||
if (sm != null) sm.DecrementWomanStep();
|
||||
|
||||
// 隐藏下一个小球并恢复当前小球
|
||||
var h = item.Handler as TouchPositionHandler;
|
||||
if (h != null)
|
||||
{
|
||||
if (h.nextTouchObject != null) h.nextTouchObject.SetActive(false);
|
||||
h.gameObject.SetActive(true);
|
||||
var mr = h.GetComponent<MeshRenderer>();
|
||||
if (mr != null) mr.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,7 @@ public class ChanraoTuibuHandler : MonoBehaviour
|
||||
public void PerformClick()
|
||||
{
|
||||
Debug.Log($"[ChanraoTuibu] {name} 被点击");
|
||||
ActionHistory.Push(ActionHistory.ActionType.ChanraoTuibu, this);
|
||||
_isBlinking = false;
|
||||
StopAllCoroutines();
|
||||
if (_outlineMesh != null) _outlineMesh.enabled = false;
|
||||
@@ -88,10 +89,12 @@ public class ChanraoTuibuHandler : MonoBehaviour
|
||||
|
||||
public void ResetState()
|
||||
{
|
||||
_isBlinking = true;
|
||||
var mr = GetComponent<MeshRenderer>(); if (mr != null) mr.enabled = false;
|
||||
var smr = GetComponent<SkinnedMeshRenderer>(); if (smr != null) smr.enabled = false;
|
||||
foreach (var r in GetComponentsInChildren<Renderer>(true)) { if (_outlineMesh != null && r == _outlineMesh) continue; r.enabled = false; }
|
||||
if (_outlineMesh != null) _outlineMesh.enabled = true;
|
||||
if (nextObject != null) nextObject.SetActive(false);
|
||||
StopAllCoroutines();
|
||||
StartCoroutine(BlinkOutline());
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ public class PingClickHandler : MonoBehaviour
|
||||
{
|
||||
_modelShown = true;
|
||||
_isBlinking = false;
|
||||
ActionHistory.Push(ActionHistory.ActionType.PingFirst, this);
|
||||
StopAllCoroutines();
|
||||
if (_modelRenderer != null) _modelRenderer.enabled = true;
|
||||
foreach (var r in GetComponentsInChildren<Renderer>(true)) r.enabled = true;
|
||||
@@ -92,7 +93,8 @@ public class PingClickHandler : MonoBehaviour
|
||||
else
|
||||
{
|
||||
if (chanraoObject != null) { chanraoObject.SetActive(true); Debug.Log($"[PingClick] {name} → {chanraoObject.name}"); }
|
||||
gameObject.SetActive(false);
|
||||
HideSelf();
|
||||
ActionHistory.Push(ActionHistory.ActionType.PingSecond, this);
|
||||
var sm = FindObjectOfType<StepManager>();
|
||||
if (sm != null) sm.RecordPingStep(pingIndex, true);
|
||||
|
||||
@@ -123,15 +125,26 @@ public class PingClickHandler : MonoBehaviour
|
||||
public void ReEnableBorder() { _isBlinking = true; if (_outlineMesh != null) { _outlineMesh.enabled = true; StopAllCoroutines(); StartCoroutine(BlinkOutline()); } }
|
||||
public void UndoSecondClick()
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
ShowSelf();
|
||||
_modelShown = true;
|
||||
_isBlinking = false;
|
||||
if (_modelRenderer != null) _modelRenderer.enabled = true;
|
||||
foreach (var r in GetComponentsInChildren<Renderer>(true)) r.enabled = true;
|
||||
if (_outlineMesh != null) _outlineMesh.enabled = false;
|
||||
}
|
||||
public void UndoShow() { HideSelf(); }
|
||||
|
||||
private void HideSelf()
|
||||
{
|
||||
foreach (var r in GetComponentsInChildren<Renderer>(true)) r.enabled = false;
|
||||
var col = GetComponent<Collider>(); if (col != null) col.enabled = false;
|
||||
_isBlinking = false;
|
||||
StopAllCoroutines();
|
||||
}
|
||||
public void UndoShow() { gameObject.SetActive(false); }
|
||||
|
||||
private void ShowSelf()
|
||||
{
|
||||
foreach (var r in GetComponentsInChildren<Renderer>(true)) r.enabled = true;
|
||||
if (_outlineMesh != null) _outlineMesh.enabled = false;
|
||||
var col = GetComponent<Collider>(); if (col != null) col.enabled = true;
|
||||
}
|
||||
|
||||
public void ResetState()
|
||||
{
|
||||
|
||||
@@ -79,6 +79,7 @@ public class ShoseClickHandler : MonoBehaviour
|
||||
if (_clicked) return;
|
||||
_clicked = true;
|
||||
Debug.Log("[ShoseClick] ★ 被点击 ★");
|
||||
ActionHistory.Push(ActionHistory.ActionType.Shose, this);
|
||||
StopAllCoroutines();
|
||||
if (_outlineMesh != null) _outlineMesh.enabled = false;
|
||||
if (targetPoint != null) { transform.position = targetPoint.position; transform.rotation = targetPoint.rotation; }
|
||||
@@ -157,6 +158,8 @@ public class ShoseClickHandler : MonoBehaviour
|
||||
transform.rotation = _initialRotation;
|
||||
}
|
||||
|
||||
if (nextObject != null) nextObject.SetActive(false);
|
||||
|
||||
StopAllCoroutines();
|
||||
StartCoroutine(BlinkOutline());
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ public class TouchPositionHandler : MonoBehaviour
|
||||
int stepIndex = transform.GetSiblingIndex() + 1;
|
||||
var sm = FindObjectOfType<StepManager>();
|
||||
if (sm != null) sm.RecordWomanStep(stepIndex);
|
||||
ActionHistory.Push(ActionHistory.ActionType.Woman, this);
|
||||
|
||||
// point1 点击后先激活 Shose
|
||||
if (stepIndex == 1)
|
||||
|
||||
Reference in New Issue
Block a user