using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; using Cysharp.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 List _submitScoreSteps = new List(); private List records; public AnimationProcess CurrentProcess => _processes[_currentMode.ToString()]; public delegate void CompleteEventHandler(int score); public delegate void UIEventHandler(); public delegate void StepProcessDescriptionMessage(string message); public delegate void StepProcessMessage(string message); public delegate void TeachingPromptsObjects(GameObject gameObj); public delegate void TeachingMessagePrompt(string message); /// /// 全部流程结束调用方法 /// public event CompleteEventHandler OnCompleteEvent; public event UIEventHandler OnUIEvent; /// /// 右上角消息通知 /// public event StepProcessMessage OnStepProcessMessage; /// /// 教学模式箭头指向 /// public event TeachingPromptsObjects OnTeachingPromptsObjects; /// /// 步骤描述 /// public event StepProcessDescriptionMessage OnStepProcessDescriptionMessage; // /// // /// 教学模式提示 // /// // public event TeachingMessagePrompt TeachingMessagePromptEvent; 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}"); } bool IsInPracticeOrAssessment()//0912 HQB判断当前是否为考试 { return (MotionEngine.GetModule().GetProcessMode() == ProcessMode.Assessment || MotionEngine.GetModule().GetProcessMode() == ProcessMode.Practice); } public bool HandleClick(string clickedObject)//0911HQB 练习和考试点击全部返回True,把出口都换成True { System.Diagnostics.StackTrace ts = new System.Diagnostics.StackTrace(); System.Diagnostics.StackFrame[] stac = ts.GetFrames(); MethodBase call = stac[1].GetMethod(); Type callin = call.DeclaringType; Debug.Log(callin.Name); Debug.Log(call.Name); Debug.Log("点击得物体--->" + 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 (_currentMode == ProcessMode.Teaching)//HQB 教学模式,不用管 { // 强制有序处理 if (currentAction.TargetObjects[currentAction.CurrentObjectIndex].Equals(clickedObject)) { ProcessCorrectClick(step, currentAction, clickedObject); return true; } else { // 输出错误信息,提示正确的点击对象 string correctObjectName = currentAction.TargetObjects[currentAction.CurrentObjectIndex]; Debug.Log($"错误点击:{clickedObject}。正确的物体是:{correctObjectName}"); OnStepProcessDescriptionMessage?.Invoke($"错误点击,正确对象:{correctObjectName}"); return false; } } else { if (currentAction.IsSequential) { // 按顺序点击的逻辑 if (currentAction.CurrentObjectIndex < currentAction.TargetObjects.Count && currentAction.TargetObjects[currentAction.CurrentObjectIndex] == clickedObject) { Debug.Log($"正确点击了:{clickedObject}"); currentAction.CurrentObjectIndex++; // 正确点击,递增对象索引 currentAction.ClickedObjects.Add(clickedObject); // 添加到已点击对象集合 HandleModeFeedback(_currentMode, currentAction); // 处理模式特定的反馈 if (currentAction.CurrentObjectIndex >= currentAction.TargetObjects.Count) { CompleteAction(step, currentAction); // 完成当前动作 } return true; } else { if (IsInPracticeOrAssessment()) return true;//0911HQB string correctObjectName = currentAction.TargetObjects[currentAction.CurrentObjectIndex]; Debug.Log($"错误点击或顺序错误:{clickedObject}。正确的物体是:{correctObjectName}"); OnStepProcessDescriptionMessage?.Invoke($"错误点击,正确:{correctObjectName}"); AddIncorrectClick(_currentStepIndex, clickedObject); return false; } } else { // 不按顺序点击的逻辑 if (currentAction.TargetObjects.Any(obj => obj == clickedObject)) { if (currentAction.ClickedObjects.Any(obj => obj == clickedObject)) { Debug.Log($"错误点击:{clickedObject}。这个物体已经点击过。"); OnStepProcessDescriptionMessage?.Invoke($"错误点击:{clickedObject}。这个物体已经点击过。"); return true; // 如果物体已经点击过,不继续处理 } 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); // 完成当前动作 } return true; } } 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}"); OnStepProcessDescriptionMessage?.Invoke($"错误点击,正确:{correctObjects}"); AddIncorrectClick(_currentStepIndex, clickedObject); if (IsInPracticeOrAssessment()) return true;//0911HQB 此处要保留错误,但是要能跳到下一步 return false; } } } } } //if (IsInPracticeOrAssessment()) return true;//0911HQB return false; } private void ProcessCorrectClick(AnimationStep step, ActionWithDescription currentAction, string clickedObject) { Debug.Log($"正确点击了:{clickedObject}"); currentAction.ClickedObjects.Add(clickedObject); currentAction.CurrentObjectIndex++; if (currentAction.CurrentObjectIndex >= currentAction.TargetObjects.Count) { CompleteAction(step, currentAction); } else { // 更新UI或其他元素以显示下一个目标对象 HighlightNextObject(currentAction); } } /// /// 处理完成当前动作的逻辑 /// /// 当前步骤 /// 当前动作 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("所有动作完成!=>" + step.StepDescription); step.IsCompleted = true; 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) { Debug.Log(CalculateTotalScore()); OnCompleteEvent?.Invoke(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()); } OnTeachingPromptsObjects(null); 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.StepDescription}"); OnStepProcessMessage?.Invoke("提示:" + action.StepDescription); OnStepProcessDescriptionMessage?.Invoke("提示:" + action.StepDescription); // ShowTrainingStep(action.Description); // 在右上角显示流程步骤 } else if (stepOrAction is AnimationStep step) { if (step.Actions.Count > 0) { Debug.Log($"培训模式:{step.Actions[0].StepDescription}"); OnStepProcessMessage?.Invoke("提示:" + step.Actions[0].StepDescription); OnStepProcessDescriptionMessage?.Invoke("提示:" + step.Actions[0].StepDescription); // 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}")) { OnStepProcessMessage?.Invoke("提示:" + action.StepDescription); OnStepProcessDescriptionMessage?.Invoke($"{action.Description}{nextObject}"); // TeachingMessagePromptEvent?.Invoke($"{action.Description} {nextObject}"); if (action.IsUI) { OnTeachingPromptsObjects?.Invoke(null); } else { HighlightObject(nextObject); } break; } } else { // 无重复物体的高亮逻辑 if (!action.ClickedObjects.Contains(nextObject)) { OnStepProcessMessage?.Invoke("提示:" + action.StepDescription); OnStepProcessDescriptionMessage?.Invoke($"{action.Description}{nextObject}"); // TeachingMessagePromptEvent?.Invoke($"{action.Description} {nextObject}"); if (action.IsUI) { OnTeachingPromptsObjects?.Invoke(null); } else { HighlightObject(nextObject); } break; } } } } } /// /// 高亮指定的物体 /// /// 物体名称 private void HighlightObject(string objectName) { try { var obj = GameObject.Find(objectName); if (obj != null) { OnTeachingPromptsObjects?.Invoke(obj); var highlightEffect = obj.GetComponent(); if (highlightEffect != null) { highlightEffect.highlighted = true; } Debug.Log($"高亮显示:{objectName}"); } } catch (Exception e) { Debug.LogError($"异常高亮物体 {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 (OnStepProcessMessage != null) OnStepProcessMessage(practiceAction.StepDescription); OnStepProcessDescriptionMessage?.Invoke(practiceAction.StepDescription); Debug.Log($"练习模式:{practiceAction.StepDescription}"); } } /// /// 计算总分 /// public int CalculateTotalScore() { float totalScore = 0; if (!_processes.ContainsKey(_currentMode.ToString())) return -1; foreach (var step in _processes[_currentMode.ToString()].Steps) { SubmitScoreStep sub = new SubmitScoreStep(); int stepIndex = _processes[_currentMode.ToString()].Steps.IndexOf(step); if (_incorrectClicksPerStep.TryGetValue(stepIndex, out var value)) { float sco = step.Score / step.Actions[0].TargetObjects.Count; Debug.Log("每个物体的分数--->" + sco); float zong = step.Score - sco * value.Count; totalScore += zong; Debug.Log("扣的分数--->" + (step.Score - sco * value.Count)); Debug.Log($"步骤 {stepIndex + 1} 错误点击的物体: {string.Join(", ", value)}"); sub.score = (int)zong; sub.setScore = step.Score; sub.stepName = step.StepDescription; sub.testPoint = step.Actions[0].Description; } else { Debug.Log("步骤没问题"); totalScore += step.Score; // 每个步骤满分为10 if (!step.IsCompleted) { sub.score = 0; } else { sub.score = (int)step.Score; } sub.stepName = step.StepDescription; sub.testPoint = step.Actions[0].Description; sub.setScore = step.Score; } _submitScoreSteps.Add(sub); } Debug.Log($"总分: {totalScore}"); return (int)totalScore; } public void OnCreate(object createParam) { _processes = new Dictionary(); _incorrectClicksPerStep = new Dictionary>(); } public void OnUpdate() { Debug.Log("==>当前得分:" + CalculateTotalScore()); } public void OnDestroy() { } public void OnGUI() { } public async UniTask GetNetworkSetpData() { try { int kaoID = MotionEngine.GetModule().GetParsedData().ExamId; Debug.Log(APIs.queryByExamId + kaoID); string json = await MotionEngine.GetModule().GetTextAsync(APIs.queryByExamId + kaoID, null); Debug.Log("获取得考试题目---->" + json); SceneStepData _sceneStepData = JsonConvert.DeserializeObject(json); records = JsonConvert.DeserializeObject>(_sceneStepData.data.examContent); Debug.Log(_sceneStepData.data.examContent); return true; } catch (Exception e) { Debug.Log(e.Message); MotionEngine.GetModule().OpenMessageWindow("没有考试题目", MessageTypeEnum.Error); return false; } } /// /// 初始化步骤 /// public async void InitializeFirstStep() { await Task.Delay(TimeSpan.FromSeconds(1)); _currentMode = MotionEngine.GetModule().GetProcessMode(); //如果是考核模式,就需要获取分数,其他模式用默认分数 if (_currentMode == ProcessMode.Assessment) { //获取网络步骤分数 if (!await MotionEngine.GetModule().GetNetworkSetpData()) { return; } } 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, actionData.IsUI)); } // Debug.Log(records[index].Score); // index++; // //通过接口获取分数数据 AnimationStep step = null; //如果是考核模式,就需要获取分数,其他模式用默认分数 if (_currentMode == ProcessMode.Assessment) { step = new AnimationStep(stepData.StepDescription, records[index].Score, actions); } else { step = new AnimationStep(stepData.StepDescription, stepData.Score, 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; } public List GetSubmitScoreStepList() { // _submitScoreSteps = new List() { new SubmitScoreStep() { score = 10, stepName = "asd", testPoint = "大苏打实打实打算" } }; return _submitScoreSteps; } /// /// HQB 在考试模式下对分数进行修正,结算点: /// public int AdjustedTotalScore() { } //public void AdjustScoreInPractice(CheckPoint checkPoint) //{ // if (!_processes.ContainsKey(_currentMode.ToString())) return; // switch (checkPoint) // { // case CheckPoint.FirstInLive://第一次从工具间到现场 // foreach (var step in _processes[_currentMode.ToString()].Steps) // { // switch (step.StepDescription) // { // case "填写工作票": // if (!step.IsCompleted) // { // foreach (var item in _incorrectClicksPerStep)//检查_incorrectClicksPerStep // { // foreach (var item1 in item.Value) // { // if (item1.Contains("工作单") && WorkorderComponent.instance.filledOrder) // { // step.IsCompleted = true; // step.Score = 10; // } // } // } // } // step.IsCompleted = WorkorderComponent.instance.filledOrder; // break; // case "领取工器具及仪器设备": // if (!step.IsCompleted) // { // } // break; // } // } // _incorrectClicksPerStep.Clear(); // break; // } //} } }