Health/Assets/Scripts/Service/YogaManager.cs

362 lines
13 KiB
C#
Raw Normal View History

2023-11-07 13:55:35 +00:00
using NUnit.Framework.Internal;
using OpenCVForUnity.CoreModule;
using OpenCVForUnity.DnnModule;
using OpenCVForUnity.UnityUtils;
using OpenCVForUnity.UnityUtils.Helper;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
2023-11-12 15:09:33 +00:00
using System.Runtime.CompilerServices;
2023-11-07 13:55:35 +00:00
using UnityEngine;
2023-11-27 05:49:53 +00:00
using UnityEngine.Rendering.Universal;
2023-11-10 07:17:23 +00:00
using UnityEngine.UI;
using Yoga;
2023-11-07 13:55:35 +00:00
public class YogaManager : MonoSingleton<YogaManager>
{
private List<Point> _baseKeyPoints = new List<Point>();
2023-11-23 07:22:09 +00:00
private Mat _rgbaMat;
public Mat RgbaMat
{
get
{
return _rgbaMat;
}
set => _rgbaMat = value;
}
private Queue<(DateTime, List<Point>)> _estimateKeyPointsCache = new Queue<(DateTime, List<Point>)>();
public Queue<(DateTime, List<Point>)> EstimateKeyPointsCache
{
get => _estimateKeyPointsCache;
}
private List<Point> _currEstimateKeyPoints;
public List<Point> CurrEstimateKeyPoints { get => _currEstimateKeyPoints; set => _currEstimateKeyPoints = value; }
public void AddCurrEstimateKeyPoints(List<Point> points)
{
_currEstimateKeyPoints = points;
_estimateKeyPointsCache.Enqueue((DateTime.Now, points));
if (_estimateKeyPointsCache.Count > YogaConfig.CurrEstimateKeyPointsMaxCount)
{
_estimateKeyPointsCache.Dequeue();
}
}
2023-11-24 18:39:53 +00:00
private List<float[]> _personRectResult = new List<float[]>();
public List<float[]> PersonRectResult { get => _personRectResult; set => _personRectResult = value; }
2023-11-07 13:55:35 +00:00
public List<Point> BaseKeyPoints { get => _baseKeyPoints; set => _baseKeyPoints = value; }
2023-11-07 13:55:35 +00:00
2023-11-27 05:49:53 +00:00
private int _currentCheckPointCount; //当前动作计数
public int CurrentCheckPointCount { get => _currentCheckPointCount; }
2023-11-07 16:51:42 +00:00
2023-11-27 05:49:53 +00:00
private int _currentCheckPointSuccessCount; //当前成功动作计数
public int CurrentCheckPointSuccessCount { get => _currentCheckPointSuccessCount; }
2023-11-07 17:51:34 +00:00
2023-11-27 05:49:53 +00:00
public int MaxCheckPointCount => LevelData.MaxCheckPointCount;
2023-11-07 17:51:34 +00:00
2023-11-27 05:49:53 +00:00
private int _levelIndex = -1; //用户选择界面选择的动作索引
public int LevelIndex { get => _levelIndex; internal set => _levelIndex = value; }
2023-11-07 16:51:42 +00:00
private Dictionary<AvatarAction, PoseBase> _actions = new Dictionary<AvatarAction, PoseBase>();
2023-11-07 13:55:35 +00:00
2023-11-27 05:49:53 +00:00
private bool _isSamplingRunning = false;
2023-11-10 07:17:23 +00:00
public YogaData LevelData
2023-11-15 08:10:56 +00:00
{
2023-11-24 18:39:53 +00:00
get
{
if (_levelData == null)
2023-11-24 18:39:53 +00:00
{
LogPrint.Warning("Action Not Load!", PrintLevel.Normal);
InitData();
}
return _levelData;
2023-11-24 18:39:53 +00:00
}
set => _levelData = value;
2023-11-15 08:10:56 +00:00
}
private Estimator _currentEstimator;
public Estimator CurrentEstimator { get => _currentEstimator; internal set => _currentEstimator = value; }
2023-11-10 07:17:23 +00:00
private YogaData _levelData = null;
2023-11-27 05:49:53 +00:00
private int _actionIndex = 0;
private int _comboTimes = 0;
private bool? _samplingResult = null;
private bool? _samplingYogaResult;
public DateTime ActionStartTime { get; set; }
2023-11-27 05:49:53 +00:00
public int ActionIndex { get => _actionIndex; internal set => _actionIndex = value; }
public bool? SamplingResult { get => _samplingResult; }
2023-11-07 15:28:19 +00:00
public void InitData()
2023-11-07 13:55:35 +00:00
{
2023-11-07 16:51:42 +00:00
_actions[AvatarAction.HeadTurnLeft] = new HeadTurnLeft();
_actions[AvatarAction.HeadTurnRight] = new HeadTurnRight();
2023-11-10 07:17:23 +00:00
_actions[AvatarAction.HeadTurnUp] = new HeadTurnUp();
_actions[AvatarAction.HeadTurnDown] = new HeadTurnDown();
_actions[AvatarAction.HandsUp] = new HandsUp();
_actions[AvatarAction.HandsDown] = new HandsHold();
2023-11-27 06:46:43 +00:00
_actions[AvatarAction.LeftLateralHead] = new LeftLateralHead();
_actions[AvatarAction.RightLateralHead] = new RightLateralHead();
_actions[AvatarAction.Hold] = new HoldPosition();
2023-11-07 13:55:35 +00:00
2023-11-27 05:49:53 +00:00
_currentCheckPointCount = 0;
_currentCheckPointSuccessCount = 0;
_comboTimes = 0;
2023-11-07 17:51:34 +00:00
2023-11-10 07:17:23 +00:00
//根据用户选择的动作索引,获取相应的资源
2023-11-27 05:49:53 +00:00
LevelData = YogaDataLoader.LoadData(LevelIndex);
EventManager.Instance.Dispatch(YogaEventType.UpdateProgress, CurrentCheckPointSuccessCount, CurrentCheckPointCount);
2023-11-07 13:55:35 +00:00
}
2023-11-07 17:51:34 +00:00
private void OnEnable()
{
EventManager.Instance.AddEventListener(YogaEventType.UI_LevelFinished, ClearingSettlement);
EventManager.Instance.AddEventListener(YogaEventType.Action_Success, OnActionSuccess);
EventManager.Instance.AddEventListener(YogaEventType.Action_Fail, OnActionFailed);
2023-11-27 06:46:43 +00:00
EventManager.Instance.AddEventListener(YogaEventType.Action_StartSampling, OnSamplingStart);
EventManager.Instance.AddEventListener(YogaEventType.Action_EndSampling, OnSamplingEnd);
2023-11-27 05:49:53 +00:00
EventManager.Instance.AddEventListener(YogaEventType.Action_Evaluate, OnEvaluation);
//extra event
EventManager.Instance.AddEventListener(YogaEventType.Action_MoveDistanceExactly, ExtraMoveDistanceExactly);
EventManager.Instance.AddEventListener(YogaEventType.Action_MoveDistanceNotAccurate, ExtraMoveDistanceNotAccurate);
EventManager.Instance.AddEventListener(YogaEventType.Action_SpeedTooSlow, ExtraSpeedTooSlow);
EventManager.Instance.AddEventListener(YogaEventType.Action_SpeedTooFast, ExtraSpeedTooFast);
2023-11-07 17:51:34 +00:00
}
private void OnDisable()
{
EventManager.Instance.RemoveEventListener(YogaEventType.UI_LevelFinished, ClearingSettlement);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_Success, OnActionSuccess);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_Fail, OnActionFailed);
2023-11-27 05:49:53 +00:00
EventManager.Instance.RemoveEventListener(YogaEventType.Action_StartSampling, OnSamplingStart);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_EndSampling, OnSamplingEnd);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_Evaluate, OnEvaluation);
//extra event
EventManager.Instance.RemoveEventListener(YogaEventType.Action_MoveDistanceExactly, ExtraMoveDistanceExactly);
EventManager.Instance.AddEventListener(YogaEventType.Action_MoveDistanceNotAccurate, ExtraMoveDistanceNotAccurate);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_SpeedTooSlow, ExtraSpeedTooSlow);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_SpeedTooFast, ExtraSpeedTooFast);
2023-11-07 17:51:34 +00:00
}
#region UI相关
2023-11-07 17:51:34 +00:00
private void OnActionSuccess()
{
2023-11-27 05:49:53 +00:00
_currentCheckPointSuccessCount++;
_currentCheckPointCount++;
//是否为连续正确动作
2023-11-10 07:17:23 +00:00
UpdateData();
2023-11-07 17:51:34 +00:00
}
private void OnActionFailed()
{
2023-11-27 05:49:53 +00:00
_currentCheckPointCount++;
2023-11-10 07:17:23 +00:00
UpdateData();
}
private void UpdateData()
{
2023-11-27 05:49:53 +00:00
if (CurrentCheckPointCount > MaxCheckPointCount)//如果超过最大数,则停止检测,跳转到下一个动作/下一个动作引导/奖励界面
2023-11-10 07:17:23 +00:00
{
LogPrint.Warning("CurrentActionCount > MaxActionCount", PrintLevel.Normal);
ClearingSettlement();
2023-11-10 07:17:23 +00:00
}
2023-11-27 05:49:53 +00:00
EventManager.Instance.Dispatch(YogaEventType.UpdateProgress, CurrentCheckPointSuccessCount, CurrentCheckPointCount, MaxCheckPointCount);//args[0] = successCount args[1] = excutedCount args[2] = totalCount
2023-11-07 17:51:34 +00:00
}
/// <summary>
/// 跳转结算界面
/// </summary>
public void ClearingSettlement()
2023-11-07 13:55:35 +00:00
{
//跳转到奖励界面
UIManager.Instance.CloseCurrent(); //关闭当前界面并停止检测
2023-11-27 05:49:53 +00:00
UIManager.Instance.ShowPanel<ClearingSettlementUI>(false, CurrentCheckPointSuccessCount, MaxCheckPointCount);//args[0] = successCount args[1] = totalCount
2023-11-26 10:14:22 +00:00
_estimateKeyPointsCache.Clear();
}
#endregion
#region
//采样质量评估
2023-11-27 05:49:53 +00:00
public bool? SampleQualityEvaluation(AvatarAction actionType, DateTime startTime, DateTime endTime)
{
2023-11-27 18:00:13 +00:00
var pointsSource = new List<(DateTime, List<Point>)>(_estimateKeyPointsCache);
//获取时间间隔内的所有点及向量变化
var framePoints = _estimateKeyPointsCache.Where(x => x.Item1 >= startTime && x.Item1 <= endTime).ToList();
if (framePoints == null)
{
LogPrint.Warning("No point has been estimated!");
framePoints = new List<(DateTime, List<Point>)>();
}
//循环遍历所有的点,检测是否符合最低点数要求
var checkedPoints = new List<(DateTime, List<Point>)>();
for (int i = 0; i < framePoints.Count; i++)
{
var p = framePoints[i];
if (!ActionCheckPoints(p.Item2))
continue;
checkedPoints.Add(p);
}
if (checkedPoints.Count < 2) //0级实现逻辑
{
2023-11-27 05:49:53 +00:00
return NeedMoreData(actionType, startTime, endTime);
}
else
{
2023-11-27 05:49:53 +00:00
return _actions[actionType].AnalyzingAction(checkedPoints);
}
}
//需要更多数据
2023-11-27 05:49:53 +00:00
private bool? NeedMoreData(AvatarAction actionType, DateTime startTime, DateTime endTime)
{
//获取1秒后时间间隔内的所有点及向量变化
var points = _estimateKeyPointsCache.Where(x => x.Item1 >= startTime.AddSeconds(1) && x.Item1 <= endTime.AddSeconds(1)).ToList();
if (points == null)
{
//提示摆正姿势
LogPrint.Warning("No point has been estimated!");
2023-11-27 05:49:53 +00:00
return null;
}
//检测动作是否正确
2023-11-27 05:49:53 +00:00
return _actions[actionType].AnalyzingAction(points, true);
}
#endregion
#region
2023-11-27 05:49:53 +00:00
private void OnSamplingStart()
{
2023-11-27 05:49:53 +00:00
//获取开始时间标记戳
ActionStartTime = DateTime.Now;
_isSamplingRunning = true;
}
2023-11-27 05:49:53 +00:00
private void OnSamplingEnd(params object[] args)
{
_isSamplingRunning = false;
if (args == null || args.Length == 0)
{
LogPrint.Error("GetActionBasePoint args is null. Please check animation event trigger configuration.");
return;
}
try
{
AvatarAction actionType = (AvatarAction)args.FirstOrDefault();
2023-11-27 05:49:53 +00:00
var startTime = ActionStartTime;
_samplingResult = SampleQualityEvaluation(actionType, ActionStartTime, DateTime.Now);
//只有hold动作检测
if (actionType == AvatarAction.Hold)
{
2023-11-27 05:49:53 +00:00
_samplingYogaResult = _samplingResult;
}
}
catch (Exception e)
{
LogPrint.Exception(e);
}
}
2023-11-27 05:49:53 +00:00
private void OnEvaluation()
{
2023-11-27 05:49:53 +00:00
if (_samplingYogaResult == null || _samplingYogaResult == false)
{
2023-11-27 05:49:53 +00:00
_samplingYogaResult = null;
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
return;
}
2023-11-27 05:49:53 +00:00
EventManager.Instance.Dispatch(YogaEventType.Action_Success);
_comboTimes++;
if (_comboTimes >= 3)
{
2023-11-27 05:49:53 +00:00
AudioManager.Instance.PlayCVInQueue("WellDone");
}
2023-11-27 05:49:53 +00:00
else if (_comboTimes == 2)
{
2023-11-27 05:49:53 +00:00
AudioManager.Instance.PlayCVInQueue("Nice");
}
else
{
AudioManager.Instance.PlayCVInQueue("Good");
}
2023-11-27 05:49:53 +00:00
_samplingYogaResult = null;
}
/// extra
private void ExtraMoveDistanceExactly()
{
AudioManager.Instance.PlayCVInQueue("ExactlyCorrect");
}
private void ExtraMoveDistanceNotAccurate()
{
AudioManager.Instance.PlayCVInQueue("NotAccurate");
}
private void ExtraSpeedTooFast()
{
AudioManager.Instance.PlayCVInQueue("SpeedTooFast");
}
private void ExtraSpeedTooSlow()
{
AudioManager.Instance.PlayCVInQueue("SpeedTooSlow");
}
#endregion
2023-11-12 15:09:33 +00:00
public bool ActionCheckPoints(List<Point> points)
{
if (points == null || points.Count == 0)
{
LogPrint.Log("ActionCheckPoints points is null");
2023-11-12 15:09:33 +00:00
return false;
}
2023-11-13 02:53:34 +00:00
2023-11-14 10:52:43 +00:00
//for (int i = 0; i < points.Count; i++)
//{
// Point p = points[i];
// if (p != new Point(-1, -1))
2023-11-24 05:13:10 +00:00
// LogPrint.Warning($"ActionPoints p({i}): {i.tagName()}, value: {p.x},{p.y}");
2023-11-14 10:52:43 +00:00
//}
2023-11-13 02:53:34 +00:00
foreach (var p in LevelData.MustPoints)
2023-11-12 15:09:33 +00:00
{
2023-11-13 02:53:34 +00:00
if (!p.IsValid(points)) //有一个点不符合 返回false
{
2023-11-25 20:52:27 +00:00
//LogPrint.Log($"ActionCheckPoints failed, {p} is not valid");
2023-11-12 15:09:33 +00:00
return false;
2023-11-15 08:10:56 +00:00
}
2023-11-12 15:09:33 +00:00
}
2023-11-13 06:43:34 +00:00
//不设的情况下,不检测
if (LevelData.AnyPoints != null && LevelData.AnyPoints.Count > 0)
2023-11-13 06:43:34 +00:00
{
foreach (var p in LevelData.AnyPoints)
2023-11-13 06:43:34 +00:00
{
if (p.IsValid(points)) //有一个点符合 返回true
{
return true;
}
}
return false; //没有一个点符合 返回false
}
2023-11-12 15:09:33 +00:00
return true;
}
2023-11-15 08:10:56 +00:00
}