ShanxiKnowledgeBase/SXElectricityInformationAcq.../Assets/Scripts/ProcessMode/AnimationProcessManager.cs

714 lines
30 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<AnimationProcessManager>, IModule
{
private Dictionary<string, AnimationProcess> _processes = new Dictionary<string, AnimationProcess>();
private ProcessMode _currentMode; // 当前模式
private int _currentStepIndex; // 当前步骤索引
private int _currentActionIndex; // 当前动作索引,确保动作顺序
private int _currentActionGameIndex; // 当前动作索引,确保动作顺序
private Dictionary<int, List<string>> _incorrectClicksPerStep; // 每个步骤的错误点击记录
private SceneStepData _sceneStepData;
private List<SubmitScoreStep> _submitScoreSteps = new List<SubmitScoreStep>();
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);
/// <summary>
/// 全部流程结束调用方法
/// </summary>
public event CompleteEventHandler OnCompleteEvent;
public event UIEventHandler OnUIEvent;
/// <summary>
/// 右上角消息通知
/// </summary>
public event StepProcessMessage OnStepProcessMessage;
/// <summary>
/// 教学模式箭头指向
/// </summary>
public event TeachingPromptsObjects OnTeachingPromptsObjects;
/// <summary>
/// 步骤描述
/// </summary>
public event StepProcessDescriptionMessage OnStepProcessDescriptionMessage;
// /// <summary>
// /// 教学模式提示
// /// </summary>
// 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);
}
}
/// <summary>
/// 添加错误点击记录
/// </summary>
/// <param name="stepIndex">当前步骤索引</param>
/// <param name="clickedObject">错误点击的物体</param>
private void AddIncorrectClick(int stepIndex, string clickedObject)
{
if (!_incorrectClicksPerStep.ContainsKey(stepIndex))
{
_incorrectClicksPerStep[stepIndex] = new List<string>();
}
_incorrectClicksPerStep[stepIndex].Add(clickedObject);
Debug.Log($"步骤 {stepIndex + 1} 错误点击的物体: {clickedObject}");
}
public bool HandleClick(string clickedObject)
{
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)
{
// 强制有序处理
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($"<color=red>错误点击</color>,正确对象:{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
{
string correctObjectName = currentAction.TargetObjects[currentAction.CurrentObjectIndex];
Debug.Log($"错误点击或顺序错误:{clickedObject}。正确的物体是:{correctObjectName}");
OnStepProcessDescriptionMessage?.Invoke($"<color=red>错误点击</color>,正确:{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($"<color=red>错误点击:</color>{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<string> correctObjectNames = new List<string>();
foreach (var obj in currentAction.TargetObjects)
{
if (!currentAction.ClickedObjects.Contains(obj))
{
correctObjectNames.Add(obj);
}
}
string correctObjects = string.Join(",", correctObjectNames);
Debug.Log($"正确的物体是:{correctObjects}");
OnStepProcessDescriptionMessage?.Invoke($"<color=red>错误点击</color>,正确:{correctObjects}");
AddIncorrectClick(_currentStepIndex, clickedObject);
return false;
}
}
}
}
}
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);
}
}
/// <summary>
/// 处理完成当前动作的逻辑
/// </summary>
/// <param name="step">当前步骤</param>
/// <param name="currentAction">当前动作</param>
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)
{
Debug.Log(CalculateTotalScore());
OnCompleteEvent?.Invoke(CalculateTotalScore());
Debug.Log("全部完成了!!!!");
}
}
else
{
if (MotionEngine.GetModule<ToolsPackManager>().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<ToolsPackManager>().GetToolsPackScene() == ToolsPackScene.)
{
OnCompleteEvent?.Invoke(CalculateTotalScore());
}
OnTeachingPromptsObjects(null);
Debug.Log("所有得步骤都已经完成了!");
}
}
}
else
{
Debug.Log("开始下一个动作!");
HandleModeFeedback(_currentMode, step.Actions[_currentActionIndex]); // 传递下一个动作对象
}
}
/// <summary>
/// 判断是否为targetObjects中的最后一个物体
/// </summary>
/// <param name="action">当前的动作</param>
/// <returns>是否为targetObjects中的最后一个物体</returns>
private bool IsLastTargetObject(ActionWithDescription action)
{
return action.CurrentObjectIndex == action.TargetObjects.Count - 1;
}
/// <summary>
/// 根据当前模式处理相应的反馈逻辑,包括准备下一个步骤或动作
/// </summary>
/// <param name="mode">当前的流程模式</param>
/// <param name="stepOrAction">当前步骤或动作</param>
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;
}
}
/// <summary>
/// 高亮显示下一个需要点击的物体
/// </summary>
/// <param name="action">当前的动作</param>
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} <size=30>{nextObject}</size>");
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} <size=30><align=center>{nextObject}</align></size>");
if (action.IsUI)
{
OnTeachingPromptsObjects?.Invoke(null);
}
else
{
HighlightObject(nextObject);
}
break;
}
}
}
}
}
/// <summary>
/// 高亮指定的物体
/// </summary>
/// <param name="objectName">物体名称</param>
private void HighlightObject(string objectName)
{
try
{
var obj = GameObject.Find(objectName);
if (obj != null)
{
OnTeachingPromptsObjects?.Invoke(obj);
var highlightEffect = obj.GetComponent<HighlightEffect>();
if (highlightEffect != null)
{
highlightEffect.highlighted = true;
}
Debug.Log($"高亮显示:{objectName}");
}
}
catch (Exception e)
{
Debug.LogError($"Error highlighting object {objectName}: {e.Message}");
}
}
/// <summary>
/// 设置当前模式
/// </summary>
/// <param name="mode">模式</param>
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}");
}
}
/// <summary>
/// 计算总分
/// </summary>
private int CalculateTotalScore()
{
float totalScore = 0;
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.stepName = step.StepDescription;
sub.testPoint = step.Actions[0].Description;
}
else
{
Debug.Log("步骤没问题");
totalScore += step.Score; // 每个步骤满分为10
sub.score = (int)step.Score;
sub.stepName = step.StepDescription;
sub.testPoint = step.Actions[0].Description;
}
_submitScoreSteps.Add(sub);
}
Debug.Log($"总分: {totalScore}");
return (int)totalScore;
}
public void OnCreate(object createParam)
{
_processes = new Dictionary<string, AnimationProcess>();
_incorrectClicksPerStep = new Dictionary<int, List<string>>();
}
public void OnUpdate()
{
}
public void OnDestroy()
{
}
public void OnGUI()
{
}
public async void GetNetworkSetpData()
{
// string json = await MotionEngine.GetModule<WebRequestManager>().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<SceneStepData>(jsonString);
Debug.Log(_sceneStepData.appId);
}
/// <summary>
/// 初始化步骤
/// </summary>
public async void InitializeFirstStep()
{
await Task.Delay(TimeSpan.FromSeconds(1));
_currentMode = MotionEngine.GetModule<DataConfigManager>().GetProcessMode();
AddProcess(_currentMode.ToString());
string json = System.IO.File.ReadAllText(Application.streamingAssetsPath + "/DataConfig/SceneStepData.json");
StepsContainer stepsContainer = JsonConvert.DeserializeObject<StepsContainer>(json);
int index = 0;
foreach (var stepData in stepsContainer.Steps)
{
List<ActionWithDescription> actions = new List<ActionWithDescription>();
foreach (var actionData in stepData.Actions)
{
List<string> targetObjects = new List<string>();
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));
}
//通过接口获取分数数据
// 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;
}
public List<SubmitScoreStep> GetSubmitScoreStepList()
{
// _submitScoreSteps = new List<SubmitScoreStep>() { new SubmitScoreStep() { score = 10, stepName = "asd", testPoint = "大苏打实打实打算" } };
return _submitScoreSteps;
}
}
}