using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using DefaultNamespace.Dto; using HighlightPlus; using MotionFramework; using MotionFramework.Scripts.Runtime.Engine.Engine.Network.WebRequest; using Newtonsoft.Json; using Unity.VisualScripting; using UnityEngine; using UnityEngine.UI; using Type = System.Type; namespace DefaultNamespace.ProcessMode { [ScriptDescription("流程模式管理器")] public class AnimationProcessManager : ModuleSingleton, IModule { private Dictionary _processes = new Dictionary(); private ProcessMode _currentMode; // 当前模式 private int _currentStepIndex; // 当前步骤索引 private int _currentActionIndex; // 当前动作索引,确保动作顺序 private int _currentActionGameIndex; // 当前动作索引,确保动作顺序 private Dictionary> _incorrectClicksPerStep; // 每个步骤的错误点击记录 private SceneStepData _sceneStepData; public AnimationProcess CurrentProcess => _processes[_currentMode.ToString()]; public delegate void CompleteEventHandler(); public delegate void UIEventHandler(); public delegate void SendMessagePrompt(string message); /// /// 全部流程结束调用方法 /// public event CompleteEventHandler OnCompleteEvent; public event UIEventHandler OnUIEvent; /// /// 右上角消息通知 /// public event SendMessagePrompt OnSendMessagePrompt; public void AddProcess(string type) { // if (!processes.ContainsKey(type)) // { // processes[type] = new AnimationProcess(type); // Enum.TryParse(type, true, out currentMode); // } _processes[type] = new AnimationProcess(type); Enum.TryParse(type, true, out _currentMode); } public void AddStepToProcess(string type, AnimationStep step) { if (_processes.ContainsKey(type)) { _processes[type].AddStep(step); } } /// /// 添加错误点击记录 /// /// 当前步骤索引 /// 错误点击的物体 private void AddIncorrectClick(int stepIndex, string clickedObject) { if (!_incorrectClicksPerStep.ContainsKey(stepIndex)) { _incorrectClicksPerStep[stepIndex] = new List(); } _incorrectClicksPerStep[stepIndex].Add(clickedObject); Debug.Log($"步骤 {stepIndex + 1} 错误点击的物体: {clickedObject}"); } public void HandleClick(string clickedObject) { string type = _currentMode.ToString(); if (_processes.ContainsKey(type)) { AnimationProcess process = _processes[type]; if (_currentStepIndex < process.Steps.Count) { AnimationStep step = process.Steps[_currentStepIndex]; ActionWithDescription currentAction = step.Actions[_currentActionIndex]; if (currentAction.IsSequential) { // 按顺序点击的逻辑 if (currentAction.CurrentObjectIndex < currentAction.TargetObjects.Count && currentAction.TargetObjects[currentAction.CurrentObjectIndex] == clickedObject) { Debug.Log($"正确点击了:{clickedObject}"); HandleModeFeedback(_currentMode, currentAction); // 处理模式特定的反馈 currentAction.CurrentObjectIndex++; // 正确点击,递增对象索引 currentAction.ClickedObjects.Add(clickedObject); // 添加到已点击对象集合 if (currentAction.CurrentObjectIndex >= currentAction.TargetObjects.Count) { CompleteAction(step, currentAction); // 完成当前动作 } } else { string correctObjectName = currentAction.TargetObjects[currentAction.CurrentObjectIndex]; Debug.Log($"错误点击或顺序错误:{clickedObject}。正确的物体是:{correctObjectName}"); AddIncorrectClick(_currentStepIndex, clickedObject); } } else { // 不按顺序点击的逻辑 if (currentAction.TargetObjects.Any(obj => obj == clickedObject)) { if (currentAction.ClickedObjects.Any(obj => obj == clickedObject)) { Debug.Log($"错误点击:{clickedObject}。这个物体已经点击过。"); return; // 如果物体已经点击过,不继续处理 } if (!currentAction.ClickedObjects.Contains(clickedObject)) { Debug.Log($"正确点击了:{clickedObject}"); currentAction.ClickedObjects.Add(clickedObject); // 添加到已点击对象集合 currentAction.CurrentObjectIndex++; HandleModeFeedback(_currentMode, currentAction); // 处理模式特定的反馈 if (currentAction.ClickedObjects.Count >= currentAction.TargetObjects.Count) { CompleteAction(step, currentAction); // 完成当前动作 } } } else { Debug.Log($"错误点击:{clickedObject}"); List correctObjectNames = new List(); foreach (var obj in currentAction.TargetObjects) { if (!currentAction.ClickedObjects.Contains(obj)) { correctObjectNames.Add(obj); } } string correctObjects = string.Join(",", correctObjectNames); Debug.Log($"正确的物体是:{correctObjects}"); AddIncorrectClick(_currentStepIndex, clickedObject); } } } } } /// /// 处理完成当前动作的逻辑 /// /// 当前步骤 /// 当前动作 private void CompleteAction(AnimationStep step, ActionWithDescription currentAction) { Debug.Log($"完成了动作 {_currentActionIndex + 1}"); step.PlayAnimation(_currentActionIndex); // 播放当前动作的动画 _currentActionIndex++; currentAction.CurrentObjectIndex = 0; // 重置当前动作对象索引 currentAction.ClickedObjects.Clear(); // 重置已点击对象集合 currentAction.FeedbackDisplayed = false; // 重置反馈显示标志 if (_currentActionIndex >= step.Actions.Count) { Debug.Log("所有动作完成!"); if (_currentMode == ProcessMode.Practice) { if (_currentStepIndex < _processes[_currentMode.ToString()].Steps.Count) { // if (currentMode == ProcessMode.Practice) // { // var nextStep = processes[currentMode.ToString()].Steps[currentStepIndex]; // HandleModeFeedback(currentMode, nextStep.Actions[0]); // 准备下一个步骤 // } var nextStep = _processes[_currentMode.ToString()].Steps[_currentStepIndex]; HandleModeFeedback(_currentMode, nextStep.Actions[0]); // 准备下一个步骤 _currentActionIndex = 0; // 重置动作索引或进入下一个大步骤 _currentStepIndex++; if (_currentStepIndex == _processes[_currentMode.ToString()].Steps.Count) { CalculateTotalScore(); Debug.Log("全部完成了!!!!"); } } else { if (MotionEngine.GetModule().GetToolsPackScene() == ToolsPackScene.其他) { OnCompleteEvent?.Invoke(); } CalculateTotalScore(); Debug.Log("全部完成了!!!!"); } } else { _currentActionIndex = 0; // 重置动作索引或进入下一个大步骤 _currentStepIndex++; if (_currentStepIndex < _processes[_currentMode.ToString()].Steps.Count) { // if (currentMode == ProcessMode.Practice) // { // var nextStep = processes[currentMode.ToString()].Steps[currentStepIndex]; // HandleModeFeedback(currentMode, nextStep.Actions[0]); // 准备下一个步骤 // } var nextStep = _processes[_currentMode.ToString()].Steps[_currentStepIndex]; HandleModeFeedback(_currentMode, nextStep.Actions[0]); // 准备下一个步骤 } else { if (MotionEngine.GetModule().GetToolsPackScene() == ToolsPackScene.其他) { OnCompleteEvent?.Invoke(); } CalculateTotalScore(); Debug.Log("全部完成了!!!!"); } } } else { Debug.Log("开始下一个动作!"); HandleModeFeedback(_currentMode, step.Actions[_currentActionIndex]); // 传递下一个动作对象 } } /// /// 判断是否为targetObjects中的最后一个物体 /// /// 当前的动作 /// 是否为targetObjects中的最后一个物体 private bool IsLastTargetObject(ActionWithDescription action) { return action.CurrentObjectIndex == action.TargetObjects.Count - 1; } /// /// 根据当前模式处理相应的反馈逻辑,包括准备下一个步骤或动作 /// /// 当前的流程模式 /// 当前步骤或动作 public void HandleModeFeedback(ProcessMode mode, object stepOrAction) { switch (mode) { case ProcessMode.Teaching: HighlightNextObject(stepOrAction as ActionWithDescription); // 高亮下一个需要点击的物体 break; case ProcessMode.Training: if (stepOrAction is ActionWithDescription action) { Debug.Log($"培训模式:{action.Description}"); OnSendMessagePrompt?.Invoke("提示:" + action.Description); // ShowTrainingStep(action.Description); // 在右上角显示流程步骤 } else if (stepOrAction is AnimationStep step) { if (step.Actions.Count > 0) { Debug.Log($"培训模式:{step.Actions[0].Description}"); OnSendMessagePrompt?.Invoke("提示:" + step.Actions[0].Description); // ShowTrainingStep(step.Actions[0].Description); // 在右上角显示流程步骤 } } break; case ProcessMode.Practice: if (stepOrAction is ActionWithDescription practiceAction) { if (IsLastTargetObject(practiceAction)) { ShowPracticeStep(practiceAction); // 只显示当前步骤 } } else if (stepOrAction is AnimationStep practiceStep) { if (practiceStep.Actions.Count > 0) { if (IsLastTargetObject(practiceStep.Actions[0])) { ShowPracticeStep(practiceStep.Actions[0]); // 只显示当前步骤 } } } break; case ProcessMode.Assessment: // 考核模式无提示 break; } } /// /// 高亮显示下一个需要点击的物体 /// /// 当前的动作 private void HighlightNextObject(ActionWithDescription action) { if (action != null) { bool hasDuplicates = action.TargetObjects.GroupBy(x => x).Any(g => g.Count() > 1); for (int i = action.CurrentObjectIndex; i < action.TargetObjects.Count; i++) { string nextObject = action.TargetObjects[i]; if (hasDuplicates) { // 处理重复物体的高亮逻辑 int count = action.TargetObjects.Take(i).Count(o => o == nextObject); // 统计当前物体之前出现的次数 if (!action.ClickedObjects.Contains($"{nextObject}_{count}")) { HighlightObject(nextObject); break; } } else { // 无重复物体的高亮逻辑 if (!action.ClickedObjects.Contains(nextObject)) { HighlightObject(nextObject); break; } } } } } /// /// 高亮指定的物体 /// /// 物体名称 private void HighlightObject(string objectName) { try { var obj = GameObject.Find(objectName); if (obj != null) { var highlightEffect = obj.GetComponent(); if (highlightEffect != null) { highlightEffect.highlighted = true; } Debug.Log($"高亮显示:{objectName}"); } } catch (Exception e) { Debug.LogError($"Error highlighting object {objectName}: {e.Message}"); } } /// /// 设置当前模式 /// /// 模式 public void SetCurrentMode(ProcessMode mode) { _currentMode = mode; _currentStepIndex = 0; _currentActionIndex = 0; } private void ShowPracticeStep(object nextStepOrAction) { if (nextStepOrAction is ActionWithDescription practiceAction) { if (OnSendMessagePrompt != null) OnSendMessagePrompt(practiceAction.Description); Debug.Log($"练习模式:{practiceAction.Description}"); } } /// /// 计算总分 /// private void CalculateTotalScore() { float totalScore = 0; foreach (var step in _processes[_currentMode.ToString()].Steps) { int stepIndex = _processes[_currentMode.ToString()].Steps.IndexOf(step); if (_incorrectClicksPerStep.TryGetValue(stepIndex, out var value)) { Debug.Log($"步骤 {stepIndex + 1} 错误点击的物体: {string.Join(", ", value)}"); } else { totalScore += step.Score; // 每个步骤满分为10 } } Debug.Log($"总分: {totalScore}"); } public void OnCreate(object createParam) { _processes = new Dictionary(); _incorrectClicksPerStep = new Dictionary>(); } public void OnUpdate() { } public void OnDestroy() { } public void OnGUI() { } public async void GetNetworkSetpData() { // string json = await MotionEngine.GetModule().GetTextAsync("", null); string jsonString = @"{ 'trainingName':'用电采集终端模拟仿真', 'appId':'ydcjzdmnfz001', 'version':'1.0.0', 'taskList':[{ 'sceneName':'抄表', 'sceneCode':'cb', 'type':'1', 'stepList':[{ 'stepName':'填写工作票', 'testPoint':'填写工作票', 'defaultScore':10 }, { 'stepName':'领取工器具及仪器设备', 'testPoint':'领取处理所需工器具及设备,包含螺丝刀、剥线钳、绝缘胶带、验电笔、盒装封印、梯子、工作证、安全帽、纱布手套、工作服、l型集中器', 'defaultScore':20 }, { 'stepName':'佩戴装备检视', 'testPoint':'佩戴背包中的安全帽、工作服及手套', 'defaultScore':5 }, { 'stepName':'前往现场', 'testPoint':'前往现场后,出示工作证并与客户进行沟通', 'defaultScore':10 }, { 'stepName':'验电', 'testPoint':'使用验电笔进行三步验电法:点击插座——点击柜门——点击插座。', 'defaultScore':10 }, { 'stepName':'更换集中器', 'testPoint':'用螺丝刀打开接线盒,将拨片调整至断电状态(带电作业调整横向滑块,断电作业调整竖向滑块,系统默认断电作业),开始作业', 'defaultScore':4 }, { 'stepName':'更换集中器', 'testPoint':'将集中器连接线的螺丝全部拧开,拧开两个固定该线的螺丝后,线消失。重复操作,直至全部线拆除', 'defaultScore':4 }, { 'stepName':'更换集中器', 'testPoint':'取出胶带将头部缠绕', 'defaultScore':4 }, { 'stepName':'更换集中器', 'testPoint':'拆除固定集中器的螺丝,取下集中器', 'defaultScore':4 }, { 'stepName':'更换集中器', 'testPoint':'取出新的集中器,移动至原先集中器位置', 'defaultScore':4 }, { 'stepName':'更换集中器', 'testPoint':'进行连线,练好线后,上螺丝', 'defaultScore':4 }, { 'stepName':'现场调试', 'testPoint':'安装完成后,申请通电调试,运行灯闪烁亮则安装成功', 'defaultScore':4 }, { 'stepName':'加装封印', 'testPoint':'盖上集中器的盖子,在集中器上加装封印、接线盒还原,关上柜门后,柜门加装封印', 'defaultScore':4 }] }] }"; _sceneStepData = JsonConvert.DeserializeObject(jsonString); Debug.Log(_sceneStepData.appId); } /// /// 初始化步骤 /// public async void InitializeFirstStep() { await Task.Delay(TimeSpan.FromSeconds(1)); _currentMode = MotionEngine.GetModule().GetProcessMode(); AddProcess(_currentMode.ToString()); string json = System.IO.File.ReadAllText(Application.streamingAssetsPath + "/DataConfig/SceneStepData.json"); StepsContainer stepsContainer = JsonConvert.DeserializeObject(json); int index = 0; foreach (var stepData in stepsContainer.Steps) { List actions = new List(); foreach (var actionData in stepData.Actions) { List targetObjects = new List(); foreach (var objectName in actionData.TargetObjects) { targetObjects.Add(objectName); } Action action = () => { }; actions.Add(new ActionWithDescription(targetObjects, action, actionData.Description, actionData.IsSequential, stepData.StepDescription)); } //通过接口获取分数数据 // AnimationStep step = new AnimationStep(stepData.StepDescription, _sceneStepData.taskList[0].stepList[index].defaultScore, actions); AnimationStep step = new AnimationStep(stepData.StepDescription,stepData.Score , actions); index++; AddStepToProcess(_currentMode.ToString(), step); } //教学模式和培训模式需要初始化一下 if (_currentMode == ProcessMode.Teaching || _currentMode == ProcessMode.Training) { if (CurrentProcess.Steps.Count > 0) { AnimationStep firstStep = CurrentProcess.Steps[0]; if (firstStep.Actions.Count > 0) { HandleModeFeedback(_currentMode, firstStep.Actions[0]); } } } } public ProcessMode GetProcessMode() { return _currentMode; } } }