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

774 lines
32 KiB
C#

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<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 List<SubmitScoreStep> _submitScoreSteps = new List<SubmitScoreStep>();
private List<Record> 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);
/// <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}");
}
bool IsInPracticeOrAssessment()//0912 HQB判断当前是否为考试
{
return (MotionEngine.GetModule<DataConfigManager>().GetProcessMode() == ProcessMode.Assessment ||
MotionEngine.GetModule<DataConfigManager>().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($"<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
{
if (IsInPracticeOrAssessment()) return true;//0911HQB
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);
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);
}
}
/// <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("所有动作完成!=>" + 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<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($"异常高亮物体 {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>
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;
totalScore += step.Score; // HQB 步骤完成才能加分
}
sub.stepName = step.StepDescription;
sub.testPoint = step.Actions[0].Description;
sub.setScore = step.Score;
}
if (MotionEngine.GetModule<DataConfigManager>().GetProcessMode() == ProcessMode.Assessment)//HQB 考试才记录用户记录
_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()
{
//Debug.Log("==>当前得分:" + CalculateTotalScore());
}
public void OnDestroy()
{
}
public void OnGUI()
{
}
public async UniTask<bool> GetNetworkSetpData()
{
try
{
int kaoID = MotionEngine.GetModule<InfoDataManager>().GetParsedData().ExamId;
Debug.Log(APIs.queryByExamId + kaoID);
string json = await MotionEngine.GetModule<WebRequestManager>().GetTextAsync(APIs.queryByExamId + kaoID, null);
Debug.Log("获取得考试题目---->" + json);
SceneStepData _sceneStepData = JsonConvert.DeserializeObject<SceneStepData>(json);
records = JsonConvert.DeserializeObject<List<Record>>(_sceneStepData.data.examContent);
Debug.Log(_sceneStepData.data.examContent);
return true;
}
catch (Exception e)
{
Debug.Log(e.Message);
MotionEngine.GetModule<MessageManager>().OpenMessageWindow("没有考试题目", MessageTypeEnum.Error);
return false;
}
}
/// <summary>
/// 初始化步骤
/// </summary>
public async void InitializeFirstStep()
{
await Task.Delay(TimeSpan.FromSeconds(1));
_currentMode = MotionEngine.GetModule<DataConfigManager>().GetProcessMode();
//如果是考核模式,就需要获取分数,其他模式用默认分数
if (_currentMode == ProcessMode.Assessment)
{
//获取网络步骤分数
if (!await MotionEngine.GetModule<AnimationProcessManager>().GetNetworkSetpData())
{
return;
}
}
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));
}
// 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<SubmitScoreStep> GetSubmitScoreStepList()
{
// _submitScoreSteps = new List<SubmitScoreStep>() { new SubmitScoreStep() { score = 10, stepName = "asd", testPoint = "大苏打实打实打算" } };
return _submitScoreSteps;
}
/// <summary>
/// HQB 在考试模式下对分数进行修正,结算点:
/// </summary>
public int AdjustedTotalScore()
{
int totalScore = 0;
return totalScore;
}
//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;
// }
//}
}
}