Unity AR万用表引导异常:仅显示各模式第一步问题排查
Unity AR万用表电流测量引导模式功能修复
需求说明
- 电流测量引导模式(
TipMode.CurrentMeasurement)需实现完整流程:- 初始状态:显示
TipCurrentMeasurementRedAdapter文本,高亮红适配器与蓝色端口 - 红适配器连接蓝色端口后:显示
TipCurrentMeasurementBlackAdapter文本,高亮黑适配器与黑色端口 - 黑适配器连接黑色端口后:显示
TipCurrentMeasurementSelectionKnob文本,高亮选择旋钮
- 初始状态:显示
- 错误处理:若红适配器错误连接到红色端口,需红色高亮该连接,并显示本地化表中
ErrorRedAdapterConnection文本
问题分析
原代码存在两个核心问题导致引导流程无法正常推进:
- 电流测量引导的第一步仅判断红适配器是否连接,未验证是否连接到蓝色端口,错误连接到红色端口时也会进入下一步
- 错误处理方法
HandleErrors()未在Update()中调用,导致错误状态无法实时更新
修复后完整代码
using System; using System.Collections.Generic; using UnityEngine; using MixedReality.Toolkit.UX; using UnityEngine.Localization; using UnityEngine.Localization.Components; namespace Assets.Multimeter.Scripts { public class MultimeterOrder : MonoBehaviour { public Transform RedAdapterTransform; public Transform BlackAdapterTransform; public GameObject RedPort; public GameObject BlackPort; public GameObject BluePort; public GameObject SelectionKnob; public GameObject TextInstructionGameObject; public LocalizeStringEvent TextInstructionLocalizeStringEvent; private readonly List<Tuple<Renderer, Color>> rend = new(); private enum TipMode { None, ResistanceMeasurement, CurrentMeasurement, VoltageMeasurement } private TipMode tipModeType = TipMode.None; private bool greenBlinkingStartable = true; private float greenBlinkingStartTimer; private const float greenBlinkingDuration = 1.5f; private const float greenBlinkingSpeed = 3f, redBlinkingSpeed = 1f, normalBlinkingSpeed = 2f; private DialogPool dialogPool; private IDialog dialog; private enum Error { NoError, ErrorRedAdapterConnection } private Error errorType = Error.NoError; private Shader shaderForBlinking, defaultShader; private bool colorIsRed; private bool colorIsGreen; private ProbeConnection probeConnection; private enum ResistanceMeasurementSteps { None, RedAdapter, BlackAdapter, SelectionKnob } private ResistanceMeasurementSteps resistanceMeasurementStep = ResistanceMeasurementSteps.None; private enum VoltageMeasurementSteps { None, RedAdapter, BlackAdapter, SelectionKnob } private VoltageMeasurementSteps voltageMeasurementStep = VoltageMeasurementSteps.None; private enum CurrentMeasurementSteps { None, RedAdapter, BlackAdapter, SelectionKnob } private CurrentMeasurementSteps currentMeasurementStep = CurrentMeasurementSteps.None; private void Start() { foreach (Renderer rendChild in this.GetComponentsInChildren<Renderer>()) { this.rend.Add(new Tuple<Renderer, Color>(rendChild, rendChild.material.color)); } this.dialogPool = this.GetComponent<DialogPool>(); this.shaderForBlinking = Shader.Find("Standard"); this.defaultShader = Shader.Find("glTF/PbrMetallicRoughness"); probeConnection = FindObjectOfType<ProbeConnection>(); } private void Update() { ResetDialogs(); HandleErrors(); switch (tipModeType) { case TipMode.ResistanceMeasurement: HandleResistanceMeasurement(); break; case TipMode.VoltageMeasurement: HandleVoltageMeasurement(); break; case TipMode.CurrentMeasurement: HandleCurrentMeasurement(); break; default: HandleDefault(); break; } } private void HandleResistanceMeasurement() { switch (resistanceMeasurementStep) { case ResistanceMeasurementSteps.RedAdapter: HighlightPortAndAdapter(RedPort, RedAdapterTransform); if (IsAdapterConnectedToPort(RedAdapterTransform, RedPort)) { ActivateTextInstruction("TipResistanceMeasurementBlackAdapter"); resistanceMeasurementStep = ResistanceMeasurementSteps.BlackAdapter; errorType = Error.NoError; } else if (IsAdapterConnectedToPort(RedAdapterTransform, BluePort)) { HighlightError(BluePort); } break; case ResistanceMeasurementSteps.BlackAdapter: HighlightPortAndCheckConnection(BlackPort, BlackAdapterTransform, () => { ActivateTextInstruction("TipResistanceMeasurementSelectionKnob"); resistanceMeasurementStep = ResistanceMeasurementSteps.SelectionKnob; }); break; case ResistanceMeasurementSteps.SelectionKnob: HighlightSelectionKnob(); break; } } private void HandleVoltageMeasurement() { switch (voltageMeasurementStep) { case VoltageMeasurementSteps.RedAdapter: HighlightPortAndAdapter(RedPort, RedAdapterTransform); if (IsAdapterConnectedToPort(RedAdapterTransform, RedPort)) { ActivateTextInstruction("TipVoltageMeasurementBlackAdapter"); voltageMeasurementStep = VoltageMeasurementSteps.BlackAdapter; errorType = Error.NoError; } else if (IsAdapterConnectedToPort(RedAdapterTransform, BluePort)) { HighlightError(BluePort); } break; case VoltageMeasurementSteps.BlackAdapter: HighlightPortAndCheckConnection(BlackPort, BlackAdapterTransform, () => { ActivateTextInstruction("TipVoltageMeasurementSelectionKnob"); voltageMeasurementStep = VoltageMeasurementSteps.SelectionKnob; }); break; case VoltageMeasurementSteps.SelectionKnob: HighlightSelectionKnob(); break; } } private void HandleCurrentMeasurement() { switch (currentMeasurementStep) { case CurrentMeasurementSteps.RedAdapter: HighlightPortAndAdapter(BluePort, RedAdapterTransform); if (IsAdapterConnectedToPort(RedAdapterTransform, BluePort)) { ActivateTextInstruction("TipCurrentMeasurementBlackAdapter"); currentMeasurementStep = CurrentMeasurementSteps.BlackAdapter; errorType = Error.NoError; } else if (IsAdapterConnectedToPort(RedAdapterTransform, RedPort)) { HighlightError(RedPort); } break; case CurrentMeasurementSteps.BlackAdapter: HighlightPortAndCheckConnection(BlackPort, BlackAdapterTransform, () => { ActivateTextInstruction("TipCurrentMeasurementSelectionKnob"); currentMeasurementStep = CurrentMeasurementSteps.SelectionKnob; }); break; case CurrentMeasurementSteps.SelectionKnob: HighlightSelectionKnob(); break; } } private void HighlightPortAndCheckConnection(GameObject port, Transform adapterTransform, Action onConnected) { HighlightPortAndAdapter(port, adapterTransform); if (IsAdapterConnectedToPort(adapterTransform, port)) { onConnected?.Invoke(); errorType = Error.NoError; } else if (IsAdapterConnected(adapterTransform)) { if (tipModeType == TipMode.CurrentMeasurement && adapterTransform == RedAdapterTransform && port == BluePort) { HighlightError(RedPort); } else { HighlightError(port); } } } private void HighlightPortAndAdapter(GameObject port, Transform adapterTransform) { if (tipModeType == TipMode.CurrentMeasurement && port == BluePort) { ColorBlinkBluePort(port.GetComponent<Renderer>(), adapterTransform.GetComponent<Renderer>()); } else { ColorBlink(port.GetComponent<Renderer>()); ColorBlink(adapterTransform.GetComponent<Renderer>()); } } private void ColorBlinkBluePort(Renderer portRenderer, Renderer adapterRenderer) { if (portRenderer != null && adapterRenderer != null) { portRenderer.material.color = Color.Lerp(Color.blue, Color.white, Mathf.PingPong(Time.time * normalBlinkingSpeed, 1)); adapterRenderer.material.color = Color.Lerp(Color.red, Color.white, Mathf.PingPong(Time.time * normalBlinkingSpeed, 1)); } } private bool IsAdapterConnectedToPort(Transform adapterTransform, GameObject targetPort) { return probeConnection.IsAdapterConnectedToPort(adapterTransform, targetPort); } private bool IsAdapterConnected(Transform adapterTransform) { return probeConnection.IsAdapterConnected(adapterTransform); } private void HighlightSelectionKnob() { if (SelectionKnob.activeInHierarchy) { GreenColorBlink(tipModeType); } } private void ColorReset() { if (colorIsRed || colorIsGreen) { foreach (var rendComponent in rend) { rendComponent.Item1.material.color = rendComponent.Item2; } colorIsRed = false; colorIsGreen = false; errorType = Error.NoError; CloseDialog(); } } private void ColorBlink(Renderer renderer) { if (renderer != null) { renderer.material.color = Color.Lerp(Color.red, Color.white, Mathf.PingPong(Time.time * normalBlinkingSpeed, 1)); } } private void GreenColorBlink(TipMode mode) { TextInstructionGameObject.SetActive(false); if (greenBlinkingStartable) { greenBlinkingStartTimer = Time.time; greenBlinkingStartable = false; } if (Time.time - greenBlinkingStartTimer < greenBlinkingDuration) { foreach (var rendComponent in rend) { if (rendComponent.Item1.material.shader != defaultShader) { rendComponent.Item1.material.shader = defaultShader; } rendComponent.Item1.material.color = Color.Lerp(rendComponent.Item2, Color.green, Mathf.PingPong(Time.time * greenBlinkingSpeed, 1)); colorIsGreen = true; } } else if (colorIsGreen) { foreach (var rendComponent in rend) { rendComponent.Item1.material.color = rendComponent.Item2; } colorIsGreen = false; greenBlinkingStartable = true; } } private void HighlightError(GameObject port) { ActivateTextInstruction("ErrorRedAdapterConnection"); ColorBlink(port.GetComponent<Renderer>()); errorType = Error.ErrorRedAdapterConnection; } private void RedColorBlink() { TextInstructionGameObject.SetActive(false); foreach (var rendComponent in rend) { if (rendComponent.Item1.material.shader != defaultShader) { rendComponent.Item1.material.shader = defaultShader; } colorIsRed = true; rendComponent.Item1.material.color = Color.Lerp(rendComponent.Item2, Color.red, Mathf.PingPong(Time.time * redBlinkingSpeed, 1)); } } private void OnDestroy() { CloseDialog(); } private void ResetDialogs() { if (dialog != null) { dialog.Dismiss(); dialog = null; } } private void ShowDialog(string dialogKey) { CloseDialog(); } private void CloseDialog() { if (dialog != null) { dialog.Dismiss(); dialog = null; } } public void SetResistanceMeasurementTips(bool pressed) { if (pressed) { Debug.Log("Resistance measurement button pressed."); tipModeType = TipMode.ResistanceMeasurement; ActivateTextInstruction("TipResistanceMeasurementRedAdapter"); resistanceMeasurementStep = ResistanceMeasurementSteps.RedAdapter; errorType = Error.NoError; } else { Debug.Log("Resistance measurement button released."); tipModeType = TipMode.None; TextInstructionGameObject.SetActive(false); resistanceMeasurementStep = ResistanceMeasurementSteps.None; ColorReset(); } } public void SetCurrentMeasurementTips(bool pressed) { if (pressed) { Debug.Log("Current measurement button pressed."); tipModeType = TipMode.CurrentMeasurement; ActivateTextInstruction("TipCurrentMeasurementRedAdapter"); currentMeasurementStep = CurrentMeasurementSteps.RedAdapter; errorType = Error.NoError; } else { Debug.Log("Current measurement button released."); tipModeType = TipMode.None; TextInstructionGameObject.SetActive(false); currentMeasurementStep = CurrentMeasurementSteps.None; ColorReset(); } } public void SetVoltageMeasurementTips(bool pressed) { if (pressed) { Debug.Log("Voltage measurement button pressed."); tipModeType = TipMode.VoltageMeasurement; ActivateTextInstruction("TipVoltageMeasurementRedAdapter"); voltageMeasurementStep = VoltageMeasurementSteps.RedAdapter; errorType = Error.NoError; } else { Debug.Log("Voltage measurement button released."); tipModeType = TipMode.None; TextInstructionGameObject.SetActive(false); voltageMeasurementStep = VoltageMeasurementSteps.None; ColorReset(); } } private void ActivateTextInstruction(string instructionKey) { TextInstructionGameObject.SetActive(true); TextInstructionLocalizeStringEvent.StringReference = new LocalizedString("MultimeterTable", instructionKey); TextInstructionLocalizeStringEvent.RefreshString(); } private void HandleErrors() { switch (errorType) { case Error.ErrorRedAdapterConnection: RedColorBlink(); break; case Error.NoError: if (colorIsRed) { ColorReset(); } break; } } private void HandleDefault() { ColorReset(); } } }
关键修改点
- 新增端口验证方法:
IsAdapterConnectedToPort,用于确认适配器是否连接到指定端口(需确保ProbeConnection类实现对应逻辑) - 修正电流引导逻辑:仅当红适配器连接到蓝色端口时才推进流程,错误连接到红色端口时触发错误提示
- 实时错误处理:在
Update中调用HandleErrors,确保错误状态实时更新 - 状态重置优化:切换引导模式或完成步骤时自动重置错误状态,避免残留提示
内容的提问来源于stack exchange,提问作者Katherin Jose
相关产品推荐
相关产品推荐

