Improve exam flow and WebGL build
This commit is contained in:
@@ -0,0 +1,404 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class SplintPracticeFlowManager : MonoBehaviour
|
||||
{
|
||||
private const string ManMubanName = "manMuban";
|
||||
private const string ManInjuryName = "manInjury";
|
||||
|
||||
private readonly HashSet<PingClickHandler> _placedPings = new HashSet<PingClickHandler>();
|
||||
private readonly HashSet<PingClickHandler> _finishedPings = new HashSet<PingClickHandler>();
|
||||
private readonly HashSet<SplintObjectClickHandler> _clickedPlanks = new HashSet<SplintObjectClickHandler>();
|
||||
|
||||
private GameObject _manMuban;
|
||||
private GameObject _manInjury;
|
||||
private PingClickHandler[] _pings;
|
||||
private SplintObjectClickHandler _bodyPad;
|
||||
private SplintObjectClickHandler[] _planks;
|
||||
private bool _bodyClicked;
|
||||
private bool _active;
|
||||
private Coroutine _finishRoutine;
|
||||
|
||||
public bool IsActive => _active && SplintPracticeSelected;
|
||||
|
||||
private bool SplintPracticeSelected
|
||||
{
|
||||
get
|
||||
{
|
||||
return GameManager.Instance != null &&
|
||||
GameManager.Instance.CurrentMode == ExperimentMode.Learn &&
|
||||
GameManager.Instance.CurrentFixationMethod == FixationMethod.SplintFixation;
|
||||
}
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
AutoBind();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
AutoBind();
|
||||
StopPractice();
|
||||
}
|
||||
|
||||
public void BeginPractice()
|
||||
{
|
||||
if (!SplintPracticeSelected) return;
|
||||
|
||||
AutoBind();
|
||||
_active = true;
|
||||
_placedPings.Clear();
|
||||
_finishedPings.Clear();
|
||||
_clickedPlanks.Clear();
|
||||
_bodyClicked = false;
|
||||
|
||||
if (_manInjury != null) _manInjury.SetActive(false);
|
||||
if (_manMuban != null) _manMuban.SetActive(true);
|
||||
|
||||
HideSplintObjects();
|
||||
ConfigurePings();
|
||||
ConfigureBodyPad();
|
||||
ConfigurePlanks();
|
||||
|
||||
ShowTip("请先完成伤情评估和脱鞋;脱鞋后按由脚踝到大腿的顺序预置 4 条固定带。");
|
||||
Debug.Log("[SplintPractice] 夹板固定练习流程已初始化");
|
||||
}
|
||||
|
||||
public void StopPractice()
|
||||
{
|
||||
_active = false;
|
||||
_placedPings.Clear();
|
||||
_finishedPings.Clear();
|
||||
_clickedPlanks.Clear();
|
||||
_bodyClicked = false;
|
||||
AutoBind();
|
||||
HideSplintObjects();
|
||||
if (_manMuban != null) _manMuban.SetActive(false);
|
||||
}
|
||||
|
||||
public bool ConfigureShose(ShoseClickHandler shose)
|
||||
{
|
||||
if (shose == null || !IsActive) return false;
|
||||
|
||||
AutoBind();
|
||||
ConfigurePings();
|
||||
|
||||
PingClickHandler firstPing = GetPingByIndex(0);
|
||||
if (firstPing == null) return false;
|
||||
|
||||
shose.nextObject = firstPing.gameObject;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool OnPingFirstClick(PingClickHandler ping)
|
||||
{
|
||||
if (!IsActive || ping == null || !IsSplintPing(ping)) return false;
|
||||
|
||||
_placedPings.Add(ping);
|
||||
Debug.Log($"[SplintPractice] 已放置夹板绑带 {_placedPings.Count}/4: {ping.name}");
|
||||
|
||||
if (_placedPings.Count >= 4)
|
||||
{
|
||||
ShowBodyPadTarget();
|
||||
ShowTip("四条固定带已预置。下一步:点击 Body.001 蓝色边框,放置夹板衬垫。");
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowTip($"已预置固定带 {_placedPings.Count}/4。继续由远端向近端点击下一个蓝色绑带点。");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnPlankClicked(SplintObjectClickHandler plank)
|
||||
{
|
||||
if (!IsActive || plank == null) return;
|
||||
|
||||
if (plank == _bodyPad)
|
||||
{
|
||||
_bodyClicked = true;
|
||||
Debug.Log("[SplintPractice] 已放置夹板衬垫 Body.001");
|
||||
ShowPlankTargets();
|
||||
ShowTip("衬垫已放置。下一步:依次点击两块木板蓝色边框,将夹板置于伤肢两侧。");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_bodyClicked) return;
|
||||
|
||||
_clickedPlanks.Add(plank);
|
||||
Debug.Log($"[SplintPractice] 已放置夹板 {_clickedPlanks.Count}/2: {plank.name}");
|
||||
|
||||
if (_clickedPlanks.Count >= 2)
|
||||
{
|
||||
EnableSecondPingStage();
|
||||
ShowTip("两侧夹板已放置。下一步:再次点击 4 个蓝色固定点,完成夹板系带固定。");
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowTip("已放置一侧夹板。继续点击另一块木板蓝色边框。");
|
||||
}
|
||||
}
|
||||
|
||||
public void UndoPlank(SplintObjectClickHandler plank)
|
||||
{
|
||||
if (plank == null) return;
|
||||
|
||||
_clickedPlanks.Remove(plank);
|
||||
_finishedPings.Clear();
|
||||
plank.gameObject.SetActive(true);
|
||||
plank.ResetState(true);
|
||||
|
||||
if (plank == _bodyPad)
|
||||
{
|
||||
_bodyClicked = false;
|
||||
HidePlankTargets();
|
||||
return;
|
||||
}
|
||||
|
||||
DisableSecondPingStage();
|
||||
}
|
||||
|
||||
public bool OnPingSecondClick(PingClickHandler ping)
|
||||
{
|
||||
if (!IsActive || ping == null || !IsSplintPing(ping)) return false;
|
||||
|
||||
_finishedPings.Add(ping);
|
||||
Debug.Log($"[SplintPractice] 已完成夹板固定点 {_finishedPings.Count}/4: {ping.name}");
|
||||
|
||||
if (_finishedPings.Count >= 4)
|
||||
{
|
||||
ShowTip("夹板固定已完成,请观察固定效果并点击结束确认。");
|
||||
if (_finishRoutine != null) StopCoroutine(_finishRoutine);
|
||||
_finishRoutine = StartCoroutine(ShowEndPanelDelayed());
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowTip($"已完成固定点 {_finishedPings.Count}/4。继续由远端向近端点击下一个蓝色固定点。");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ResetToFirstPingStage()
|
||||
{
|
||||
if (!IsActive) return;
|
||||
|
||||
_placedPings.Clear();
|
||||
_finishedPings.Clear();
|
||||
_clickedPlanks.Clear();
|
||||
_bodyClicked = false;
|
||||
HideSplintObjects();
|
||||
ConfigurePings();
|
||||
ConfigureBodyPad();
|
||||
ConfigurePlanks();
|
||||
|
||||
PingClickHandler firstPing = GetPingByIndex(0);
|
||||
if (firstPing != null)
|
||||
{
|
||||
firstPing.gameObject.SetActive(true);
|
||||
firstPing.ResetState(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void AutoBind()
|
||||
{
|
||||
_manMuban = FindSceneObject(ManMubanName);
|
||||
_manInjury = FindSceneObject(ManInjuryName);
|
||||
}
|
||||
|
||||
private void ConfigurePings()
|
||||
{
|
||||
if (_manMuban == null) return;
|
||||
|
||||
_pings = new PingClickHandler[4];
|
||||
string[] guideNames = { "ping.001", "ping.002", "ping.003", "ping.004" };
|
||||
string[] targetNames = { "Armature/Bottoms.001", "ping.005", "ping.006", "ping.007" };
|
||||
|
||||
for (int i = 0; i < guideNames.Length; i++)
|
||||
{
|
||||
Transform guide = _manMuban.transform.Find(guideNames[i]);
|
||||
Transform target = _manMuban.transform.Find(targetNames[i]);
|
||||
if (guide == null || target == null) continue;
|
||||
|
||||
PingClickHandler handler = guide.GetComponent<PingClickHandler>();
|
||||
if (handler == null) handler = guide.gameObject.AddComponent<PingClickHandler>();
|
||||
|
||||
handler.pingIndex = i;
|
||||
handler.chanraoObject = target.gameObject;
|
||||
handler.nextPing = null;
|
||||
_pings[i] = handler;
|
||||
|
||||
target.gameObject.SetActive(false);
|
||||
guide.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _pings.Length - 1; i++)
|
||||
{
|
||||
if (_pings[i] != null && _pings[i + 1] != null)
|
||||
_pings[i].nextPing = _pings[i + 1].gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigureBodyPad()
|
||||
{
|
||||
if (_manMuban == null) return;
|
||||
|
||||
Transform body = _manMuban.transform.Find("Body.001");
|
||||
if (body == null) return;
|
||||
|
||||
_bodyPad = body.GetComponent<SplintObjectClickHandler>();
|
||||
if (_bodyPad == null) _bodyPad = body.gameObject.AddComponent<SplintObjectClickHandler>();
|
||||
body.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
private void ConfigurePlanks()
|
||||
{
|
||||
if (_manMuban == null) return;
|
||||
|
||||
string[] plankNames = { "Wood plank - warm oak board", "Wood plank - warm oak board.001" };
|
||||
List<SplintObjectClickHandler> planks = new List<SplintObjectClickHandler>();
|
||||
|
||||
for (int i = 0; i < plankNames.Length; i++)
|
||||
{
|
||||
Transform plank = _manMuban.transform.Find(plankNames[i]);
|
||||
if (plank == null) continue;
|
||||
|
||||
SplintObjectClickHandler handler = plank.GetComponent<SplintObjectClickHandler>();
|
||||
if (handler == null) handler = plank.gameObject.AddComponent<SplintObjectClickHandler>();
|
||||
planks.Add(handler);
|
||||
plank.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
_planks = planks.ToArray();
|
||||
}
|
||||
|
||||
private void HideSplintObjects()
|
||||
{
|
||||
if (_manMuban == null) return;
|
||||
|
||||
string[] names =
|
||||
{
|
||||
"ping.001", "ping.002", "ping.003", "ping.004",
|
||||
"ping.005", "ping.006", "ping.007",
|
||||
"Body.001",
|
||||
"Wood plank - warm oak board", "Wood plank - warm oak board.001"
|
||||
};
|
||||
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
Transform target = _manMuban.transform.Find(names[i]);
|
||||
if (target != null) target.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
Transform bottoms = _manMuban.transform.Find("Armature/Bottoms.001");
|
||||
if (bottoms != null) bottoms.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
private void ShowBodyPadTarget()
|
||||
{
|
||||
if (_bodyPad == null) ConfigureBodyPad();
|
||||
if (_bodyPad == null) return;
|
||||
|
||||
_bodyPad.gameObject.SetActive(true);
|
||||
_bodyPad.ResetState(true);
|
||||
}
|
||||
|
||||
private void ShowPlankTargets()
|
||||
{
|
||||
if (_planks == null || _planks.Length == 0) ConfigurePlanks();
|
||||
|
||||
for (int i = 0; i < _planks.Length; i++)
|
||||
{
|
||||
if (_planks[i] == null) continue;
|
||||
_planks[i].gameObject.SetActive(true);
|
||||
_planks[i].ResetState(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void HidePlankTargets()
|
||||
{
|
||||
if (_planks == null) return;
|
||||
|
||||
for (int i = 0; i < _planks.Length; i++)
|
||||
{
|
||||
if (_planks[i] == null) continue;
|
||||
_planks[i].ResetState(false);
|
||||
_planks[i].gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnableSecondPingStage()
|
||||
{
|
||||
if (_pings == null || _pings.Length == 0) ConfigurePings();
|
||||
|
||||
for (int i = 0; i < _pings.Length; i++)
|
||||
{
|
||||
if (_pings[i] == null) continue;
|
||||
_pings[i].gameObject.SetActive(true);
|
||||
_pings[i].ReEnableBorder();
|
||||
}
|
||||
}
|
||||
|
||||
private void DisableSecondPingStage()
|
||||
{
|
||||
if (_pings == null) return;
|
||||
|
||||
for (int i = 0; i < _pings.Length; i++)
|
||||
{
|
||||
if (_pings[i] == null) continue;
|
||||
if (_pings[i].chanraoObject != null) _pings[i].chanraoObject.SetActive(false);
|
||||
_pings[i].ResetState(false);
|
||||
_pings[i].gameObject.SetActive(_placedPings.Contains(_pings[i]));
|
||||
}
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator ShowEndPanelDelayed()
|
||||
{
|
||||
yield return new WaitForSeconds(1f);
|
||||
UIManager uiManager = FindObjectOfType<UIManager>();
|
||||
if (uiManager != null) uiManager.ShowEndPanel();
|
||||
_finishRoutine = null;
|
||||
}
|
||||
|
||||
private PingClickHandler GetPingByIndex(int index)
|
||||
{
|
||||
if (_pings == null || _pings.Length == 0) ConfigurePings();
|
||||
if (_pings == null || index < 0 || index >= _pings.Length) return null;
|
||||
return _pings[index];
|
||||
}
|
||||
|
||||
private bool IsSplintPing(PingClickHandler ping)
|
||||
{
|
||||
if (ping == null || _pings == null) return false;
|
||||
|
||||
for (int i = 0; i < _pings.Length; i++)
|
||||
{
|
||||
if (_pings[i] == ping) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private GameObject FindSceneObject(string objectName)
|
||||
{
|
||||
GameObject found = GameObject.Find(objectName);
|
||||
if (found != null) return found;
|
||||
|
||||
Transform[] all = Resources.FindObjectsOfTypeAll<Transform>();
|
||||
for (int i = 0; i < all.Length; i++)
|
||||
{
|
||||
Transform t = all[i];
|
||||
if (t != null && t.gameObject.scene.IsValid() && t.name == objectName)
|
||||
return t.gameObject;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ShowTip(string text)
|
||||
{
|
||||
UIManager uiManager = FindObjectOfType<UIManager>();
|
||||
if (uiManager != null) uiManager.ShowTip(text);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user