修改运作流程

This commit is contained in:
terric 2023-11-27 13:49:53 +08:00
parent b3d8d06b12
commit a2437a89c9
81 changed files with 400612 additions and 355729 deletions

View File

@ -78,6 +78,32 @@ AnimatorState:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1102 &-958221975385946498
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: LateralHead
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: c75612d9f1883b341938119f5209cdae, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1102 &-119720837827415242
AnimatorState:
serializedVersion: 6
@ -126,6 +152,32 @@ AnimatorController:
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
--- !u!1102 &2262962203372547000
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: SitUpright
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: ae49d9718e5c77e4d9a353bad084b22e, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1107 &8614111743423132251
AnimatorStateMachine:
serializedVersion: 6
@ -147,6 +199,12 @@ AnimatorStateMachine:
- serializedVersion: 1
m_State: {fileID: -7085785883482666976}
m_Position: {x: 300, y: 270, z: 0}
- serializedVersion: 1
m_State: {fileID: 2262962203372547000}
m_Position: {x: 530, y: 130, z: 0}
- serializedVersion: 1
m_State: {fileID: -958221975385946498}
m_Position: {x: 300, y: 320, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c75612d9f1883b341938119f5209cdae
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ae49d9718e5c77e4d9a353bad084b22e
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

BIN
Assets/Resources/CV/And.wav Normal file

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 7b8e89d757ee80645b795c0eae5081c2
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 6de05fb8758071c4a8e872b62be416c5
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 539a84ee39fd9764fb55686ee9490ce0
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 45abf728e036be642a06704316554305
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 4a9c968766f7d4748bd0c0b4ee17cdbc
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 25f7fc72f59fa2148a95367beb5de6dc
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Resources/CV/Now.wav Normal file

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 8beb4af93e325c34cae68ddb662d4353
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: fa7805ab161b27943bb2362e8ef07a44
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 0fec83efe6655844f86090b5c75bd335
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: abc053efb0e43fb44b3812f7e50598d4
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

8
Assets/Resources/SE.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e6f7e153e2ce17c4eb052426e8aae456
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 2b99ce8c9d20fb14c8e2232ca89712cc
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: e14ab1ee2041fe842b24e87b895c635d
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7dc7f9ac2c5716c45aab1a02191adfa5
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 998f5cf7179256648b9d7e1487bd0fdd
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -111,11 +111,11 @@ public class CVEstimator : Singleton<CVEstimator>
{
try
{
LogPrint.Log($"Estimation Thread Running!IsRunning:{IsRunning} {DateTime.Now}, {YogaManager.Instance.CurrentEstimator.GetType().FullName}", PrintLevel.Important);
LogPrint.Log($"Estimation Thread Running!IsRunning:{IsRunning} {DateTime.Now}", PrintLevel.Important);
Mat rgbaMat = YogaManager.Instance.RgbaMat;
if (rgbaMat == null)
{
LogPrint.Log("WebCamTexture is null. ", PrintLevel.Important);
LogPrint.Log("WebCamTexture is null. ");
LogPrint.Log("Re-Estimation.");
continue; //重新检测
}
@ -123,7 +123,7 @@ public class CVEstimator : Singleton<CVEstimator>
if (!YogaManager.Instance.CurrentEstimator.Esitmate(bgrMat, rgbaMat, out List<Point> points))
{
LogPrint.Log("Pose estimation failed. Re-Estimating.", PrintLevel.Important);
LogPrint.Log("Pose estimation failed. Re-Estimating.");
continue; //重新检测
}

View File

@ -40,13 +40,13 @@ public abstract class Estimator
if (centerX < width / 2) //主驾驶
{
//选择为副驾驶返回false
if (GlobalData.Instance.Position == PositionType.CoDriver)
if (!GlobalData.Instance.IsDriverPosition)
return false;
}
else //副驾驶
{
//选择为主驾驶返回false
if (GlobalData.Instance.Position == PositionType.Driver)
if (GlobalData.Instance.IsDriverPosition)
return false;
}

View File

@ -74,7 +74,7 @@ public class MediaPipeEstimator : Estimator
float y2 = Mathf.Floor(results_arr[3] * y_factor - y_shift);
//主副驾
if (GlobalData.Instance.Position == PositionType.CoDriver)
if (!GlobalData.Instance.IsDriverPosition)
{
if ((x1 + x2) / 2 < bgrMat.size().width / 2) //副驾,主驾位跳过
{

View File

@ -114,7 +114,7 @@ public class OpenPoseEsimater : Estimator
float[] box = new float[4];
float shift = bgrMat.width() / 2 * YogaManager.Instance.LevelData.RectCutRate;
if (GlobalData.Instance.Position == PositionType.CoDriver)
if (!GlobalData.Instance.IsDriverPosition) //副驾驶
{
box[0] = 0; //left
box[1] = 0; //top

View File

@ -9,8 +9,11 @@ public class HandsHold : PoseBase
{
//必要点位 "RShoulder", "LShoulder", "RElbow", "LElbow"
//计算肩膀到手肘矢量,右手
Vector2 rightHandVector = GetAverageVector(startPoint, endPoint, "RElbow");
Vector2 leftHandVector = GetAverageVector(startPoint, endPoint, "LElbow");
//Vector2 rightHandVector = GetAverageVector(startPoint, endPoint, "RElbow");
//Vector2 leftHandVector = GetAverageVector(startPoint, endPoint, "LElbow");
Vector2 rightHandVector = GetTwoPointAverageVector(startPoint, endPoint, "RElbow", "RShoulder");
Vector2 leftHandVector = GetTwoPointAverageVector(startPoint, endPoint, "LElbow", "LShoulder");
//平均矢量
Vector2 averageVector = (rightHandVector + leftHandVector) / 2;
@ -29,41 +32,9 @@ public class HandsHold : PoseBase
"LWrist".Equals(tagName);
}
public override void ValidationMovement(Vector2 distance, TimeSpan totalTimeSpan, int level)
public override bool? MovementValidation(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
if (totalTimeSpan.TotalMilliseconds / 1000 < 0.05f)
{
LogPrint.Error("TimeSpan too short");
return;
}
var angle = Vector2.SignedAngle(Vector2.down, distance);
LogPrint.Log($"Angle:{angle}", PrintLevel.Normal);
if (MathF.Abs(angle) < 50 && distance.magnitude > 5f)
EventManager.Instance.Dispatch(YogaEventType.Action_Success); //方向不能偏移超过10°
else
{
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
return;
}
if (level < 1)
return;
LogPrint.Log($"distance x:{distance.x}, y:{distance.y}, magnitude:{distance.magnitude}");
if (distance.magnitude > 80f || distance.magnitude < 20f)
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceNotAccurate);
else
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceExactly);
if (level < 2)
return;
var speed = distance.magnitude / totalTimeSpan.TotalSeconds;
LogPrint.Log($"speed:{speed}", PrintLevel.Normal);
if (speed > 0.5f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooFast); //速度语音提示
else if (speed < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooSlow); //速度语音提示
return BasicMovementValidation(distance, totalTimeSpan, Vector2.down, level);
}
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)

View File

@ -9,8 +9,12 @@ public class HandsUp : PoseBase
{
//必要点位 "RShoulder", "LShoulder", "RElbow", "LElbow"
//计算肩膀到手肘矢量,右手
Vector2 rightHandVector = GetAverageVector(startPoint, endPoint, "RElbow");
Vector2 leftHandVector = GetAverageVector(startPoint, endPoint, "LElbow");
//Vector2 rightHandVector = GetAverageVector(startPoint, endPoint, "RElbow");
//Vector2 leftHandVector = GetAverageVector(startPoint, endPoint, "LElbow");
Vector2 rightHandVector = GetTwoPointAverageVector(startPoint, endPoint, "RElbow", "RShoulder");
Vector2 leftHandVector = GetTwoPointAverageVector(startPoint, endPoint, "LElbow", "LShoulder");
//平均矢量
Vector2 averageVector = (rightHandVector + leftHandVector) / 2;
@ -30,41 +34,9 @@ public class HandsUp : PoseBase
"LWrist".Equals(tagName);
}
public override void ValidationMovement(Vector2 distance, TimeSpan totalTimeSpan, int level)
public override bool? MovementValidation(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
if (totalTimeSpan.TotalMilliseconds / 1000 < 0.05f)
{
LogPrint.Error("TimeSpan too short");
return;
}
var angle = Vector2.SignedAngle(Vector2.up, distance);
LogPrint.Log($"Angle:{angle}", PrintLevel.Normal);
if (MathF.Abs(angle) < 50 && distance.magnitude > 5f)
EventManager.Instance.Dispatch(YogaEventType.Action_Success); //方向不能偏移超过10°
else
{
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
return;
}
if (level < 1)
return;
LogPrint.Log($"distance x:{distance.x}, y:{distance.y}, magnitude:{distance.magnitude}", PrintLevel.Normal);
if (distance.magnitude > 80f || distance.magnitude < 20f)
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceNotAccurate);
else
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceExactly);
if (level < 2)
return;
var speed = distance.magnitude / totalTimeSpan.TotalSeconds;
LogPrint.Log($"speed:{speed}", PrintLevel.Normal);
if (speed > 0.5f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooFast); //速度语音提示
else if (speed < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooSlow); //速度语音提示
return BasicMovementValidation(distance, totalTimeSpan, Vector2.up, level);
}
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)

View File

@ -10,7 +10,8 @@ public class HeadTurnDown : PoseBase
List<Vector2> vectors = new List<Vector2>();
//必要点位 Nose Neck
//计算鼻子到头颈矢量
return GetAverageVector(startPoint, endPoint, "Nose");
//return GetAverageVector(startPoint, endPoint, "Nose");
return GetTwoPointAverageVector(startPoint, endPoint, "Nose", "Neck");
}
protected override bool IsMovePoint(string tagName)
@ -18,43 +19,9 @@ public class HeadTurnDown : PoseBase
return "Nose" == tagName || "REye" == tagName || "LEye" == tagName || "REar" == tagName || "LEar" == tagName;
}
public override void ValidationMovement(Vector2 distance, TimeSpan totalTimeSpan, int level)
public override bool? MovementValidation(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
if (totalTimeSpan.TotalMilliseconds / 1000 < 0.05f)
{
LogPrint.Error("TimeSpan too short");
return;
}
var angle = Vector2.SignedAngle(Vector2.down, distance);
LogPrint.Log($"Angle:{angle}", PrintLevel.Normal);
if (MathF.Abs(angle) < 50 && distance.magnitude > 5f)
EventManager.Instance.Dispatch(YogaEventType.Action_Success); //方向不能偏移超过10°
else
{
LogPrint.Warning($"Angle:{angle}, magnitude:{distance.magnitude}", PrintLevel.Important);
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
return;
}
if (level < 1)
return;
LogPrint.Log($"distance x:{distance.x}, y:{distance.y}, magnitude:{distance.magnitude}", PrintLevel.Normal);
if (distance.magnitude > 80f || distance.magnitude < 20f)
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceNotAccurate);
else
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceExactly);
if (level < 2)
return;
var speed = distance.magnitude / totalTimeSpan.TotalSeconds;
LogPrint.Log($"speed:{speed}", PrintLevel.Normal);
if (speed > 20f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooFast); //速度语音提示
else if (speed < 8f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooSlow); //速度语音提示
return BasicMovementValidation(distance, totalTimeSpan, Vector2.down, level);
}
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)

View File

@ -11,7 +11,8 @@ public class HeadTurnLeft : PoseBase
List<Vector2> vectors = new List<Vector2>();
//必要点位 Nose Neck
//计算鼻子到头颈矢量
return GetAverageVector(startPoint, endPoint, "Nose");
//return GetAverageVector(startPoint, endPoint, "Nose");
return GetTwoPointAverageVector(startPoint, endPoint, "Nose", "Neck");
}
protected override bool IsMovePoint(string tagName)
@ -19,42 +20,9 @@ public class HeadTurnLeft : PoseBase
return "Nose" == tagName || "REye" == tagName || "LEye" == tagName || "REar" == tagName || "LEar" == tagName;
}
public override void ValidationMovement(Vector2 distance, TimeSpan totalTimeSpan, int level)
public override bool? MovementValidation(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
if (totalTimeSpan.TotalMilliseconds / 1000 < 0.05f)
{
LogPrint.Error("TimeSpan too short");
return;
}
var angle = Vector2.SignedAngle(Vector2.left, distance);
LogPrint.Log($"Angle:{angle}", PrintLevel.Normal);
if (MathF.Abs(angle) < 50 && distance.magnitude > 5f)
EventManager.Instance.Dispatch(YogaEventType.Action_Success); //方向不能偏移超过10°
else
{
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
return;
}
if (level < 1)
return;
LogPrint.Log($"distance x:{distance.x}, y:{distance.y}, magnitude:{distance.magnitude}", PrintLevel.Normal);
if (distance.magnitude > 80f || distance.magnitude < 20f)
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceNotAccurate);
else
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceExactly);
if (level < 2)
return;
var speed = distance.magnitude / totalTimeSpan.TotalSeconds;
LogPrint.Log($"speed:{speed}", PrintLevel.Normal);
if (speed > 0.5f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooFast); //速度语音提示
else if (speed < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooSlow); //速度语音提示
return BasicMovementValidation(distance, totalTimeSpan, Vector2.left, level);
}
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)

View File

@ -11,7 +11,8 @@ public class HeadTurnRight : PoseBase
List<Vector2> vectors = new List<Vector2>();
//必要点位 Nose Neck
//计算鼻子到头颈矢量
return GetAverageVector(startPoint, endPoint, "Nose");
//return GetAverageVector(startPoint, endPoint, "Nose");
return GetTwoPointAverageVector(startPoint, endPoint, "Nose", "Neck");
}
protected override bool IsMovePoint(string tagName)
@ -19,42 +20,9 @@ public class HeadTurnRight : PoseBase
return "Nose" == tagName || "REye" == tagName || "LEye" == tagName || "REar" == tagName || "LEar" == tagName;
}
public override void ValidationMovement(Vector2 distance, TimeSpan totalTimeSpan, int level)
public override bool? MovementValidation(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
if (totalTimeSpan.TotalMilliseconds / 1000 < 0.05f)
{
LogPrint.Error("TimeSpan too short");
return;
}
var angle = Vector2.SignedAngle(Vector2.right, distance);
LogPrint.Log($"Angle:{angle}", PrintLevel.Normal);
if (MathF.Abs(angle) < 50 && distance.magnitude > 5f)
EventManager.Instance.Dispatch(YogaEventType.Action_Success); //方向不能偏移超过10°
else
{
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
return;
}
if (level < 1)
return;
LogPrint.Log($"distance x:{distance.x}, y:{distance.y}, magnitude:{distance.magnitude}", PrintLevel.Normal);
if (distance.magnitude > 80f || distance.magnitude < 20f)
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceNotAccurate);
else
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceExactly);
if (level < 2)
return;
var speed = distance.magnitude / totalTimeSpan.TotalSeconds;
LogPrint.Log($"speed:{speed}", PrintLevel.Normal);
if (speed > 0.5f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooFast); //速度语音提示
else if (speed < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooSlow); //速度语音提示
return BasicMovementValidation(distance, totalTimeSpan, Vector2.right, level);
}
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)

View File

@ -10,7 +10,8 @@ public class HeadTurnUp : PoseBase
List<Vector2> vectors = new List<Vector2>();
//必要点位 Nose Neck
//计算鼻子到头颈矢量
return GetAverageVector(startPoint, endPoint, "Nose");
//return GetAverageVector(startPoint, endPoint, "Nose");
return GetTwoPointAverageVector(startPoint, endPoint, "Nose", "Neck");
}
protected override bool IsMovePoint(string tagName)
@ -18,42 +19,9 @@ public class HeadTurnUp : PoseBase
return "Nose" == tagName || "REye" == tagName || "LEye" == tagName || "REar" == tagName || "LEar" == tagName;
}
public override void ValidationMovement(Vector2 distance, TimeSpan totalTimeSpan, int level)
public override bool? MovementValidation(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
if (totalTimeSpan.TotalMilliseconds / 1000 < 0.05f)
{
LogPrint.Error("TimeSpan too short");
return;
}
var angle = Vector2.SignedAngle(Vector2.up, distance);
LogPrint.Log($"Angle:{angle}", PrintLevel.Normal);
if (MathF.Abs(angle) < 50 && distance.magnitude > 5f)
EventManager.Instance.Dispatch(YogaEventType.Action_Success); //方向不能偏移超过10°
else
{
LogPrint.Warning($"Angle:{angle}, magnitude:{distance.magnitude}", PrintLevel.Important);
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
return;
}
if (level < 1)
return;
LogPrint.Log($"distance x:{distance.x}, y:{distance.y}, magnitude:{distance.magnitude}", PrintLevel.Normal);
if (distance.magnitude > 80f || distance.magnitude < 20f)
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceNotAccurate);
else
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceExactly);
if (level < 2)
return;
var speed = distance.magnitude / totalTimeSpan.TotalSeconds;
LogPrint.Log($"speed:{speed}", PrintLevel.Normal);
if (speed > 0.5f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooFast); //速度语音提示
else if (speed < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooSlow); //速度语音提示
return BasicMovementValidation(distance, totalTimeSpan, Vector2.up, level);
}
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)

View File

@ -0,0 +1,50 @@
using OpenCVForUnity.CoreModule;
using System;
using System.Collections.Generic;
using UnityEngine;
public class HoldPosition : PoseBase
{
public override Vector2 GetBasicVectorDirection(List<Point> startPoint, List<Point> endPoint)
{
List<Vector2> vectors = new List<Vector2>();
//必要点位 Nose Neck
//计算鼻子到头颈矢量
//return GetAverageVector(startPoint, endPoint, "Nose");
return GetTwoPointAverageVector(startPoint, endPoint, "Nose", "Neck");
}
protected override bool IsMovePoint(string tagName)
{
return "Nose" == tagName || "REye" == tagName || "LEye" == tagName || "REar" == tagName || "LEar" == tagName;
}
public override bool? MovementValidation(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
if (totalTimeSpan.TotalMilliseconds / 1000 < 0.05f)
{
LogPrint.Error("TimeSpan too short");
return null;
}
//保持姿势不发生移动
if (distance.magnitude < 10f)//允许一定误差
{
//EventManager.Instance.Dispatch(YogaEventType.Action_Success);
return true;
}
else
{
LogPrint.Warning($"Hold Position, magnitude:{distance.magnitude}", PrintLevel.Important);
//EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
return false;
}
}
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)
{
throw new NotImplementedException();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6f85606217bc2de4ba8e53c63820220c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,58 @@
using OpenCVForUnity.CoreModule;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class LeftLateralHead : PoseBase
{
public override bool? AnalyzingAction(List<(DateTime, List<Point>)> points, bool isDataReGather = false)
{
if (points.Count < 2) // 0级实现逻辑 不做操作
return null;
var pointList = points.OrderBy(p => p.Item1);
var startP = points.First().Item2;
var endP = points.Last().Item2;
var startDir = "Nose".vector(startP) - "Neck".vector(startP);
var endDir = "Nose".vector(endP) - "Neck".vector(endP);
var angle = Vector2.SignedAngle(startDir, endDir);
LogPrint.Log($"angle: {angle}", PrintLevel.Normal);
if (MathF.Abs(angle) > 10)
{
return true;
}
else
{
return false;
}
}
//public override Vector2 GetBasicVectorDirection(List<Point> startPoint, List<Point> endPoint)
//{
// List<Vector2> vectors = new List<Vector2>();
// 必要点位 Nose Neck
// 计算鼻子到头颈矢量
// return GetAverageVector(startPoint, endPoint, "Nose");
// return GetTwoPointAverageVector(startPoint, endPoint, "Nose", "Neck");
//}
protected override bool IsMovePoint(string tagName)
{
return "Nose" == tagName || "REye" == tagName || "LEye" == tagName || "REar" == tagName || "LEar" == tagName;
}
public override bool? MovementValidation(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
return BasicMovementValidation(distance, totalTimeSpan, Vector2.left, level);
}
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)
{
throw new NotImplementedException();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 47eb13eda73bb7e4eac717169eb64f1d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -19,11 +19,34 @@ public abstract class PoseBase
}
return retVal;
}
public abstract Vector2 GetBasicVectorDirection(List<Point> startPoint, List<Point> endPoint);
public virtual Vector2 GetBasicVectorDirection(List<Point> startPoint, List<Point> endPoint) { return Vector2.zero; }
//public abstract void SpeedCheck(double v);
public abstract void ValidationMovement(Vector2 distance, TimeSpan totalTimeSpan, int level);
public abstract bool? MovementValidation(Vector2 distance, TimeSpan totalTimeSpan, int level);
public abstract void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan);
/// <summary>
/// 侦测两帧之间的平均矢量
/// </summary>
/// <param name="startPoint">起始帧</param>
/// <param name="endPoint">结束帧</param>
/// <param name="movePoint">必须为必要点</param>
/// <param name="staticPoint">必须为必要点</param>
/// <returns></returns>
protected Vector2 GetTwoPointAverageVector(List<Point> startPoint, List<Point> endPoint, string movePoint, string staticPoint)
{
Vector2 startEyeV = new Vector2((float)movePoint.p(startPoint).x - (float)staticPoint.p(startPoint).x, (float)movePoint.p(startPoint).y - (float)staticPoint.p(startPoint).y);
Vector2 endEyeV = new Vector2((float)movePoint.p(endPoint).x - (float)staticPoint.p(endPoint).x, (float)movePoint.p(endPoint).y - (float)staticPoint.p(endPoint).y);
return endEyeV - startEyeV;
}
/// <summary>
/// 对全身多点进行平均矢量计算
/// </summary>
/// <param name="startPoint"></param>
/// <param name="endPoint"></param>
/// <param name="movePoint"></param>
/// <returns></returns>
protected Vector2 GetAverageVector(List<Point> startPoint, List<Point> endPoint, string movePoint)
{
List<Vector2> vectors = new List<Vector2>();
@ -69,10 +92,10 @@ public abstract class PoseBase
/// </summary>
/// <param name="points"></param>
/// <param name="isDataReGather"></param>
public virtual void AnalyzingAction(List<(DateTime, List<Point>)> points, bool isDataReGather = false)
public virtual bool? AnalyzingAction(List<(DateTime, List<Point>)> points, bool isDataReGather = false)
{
if (points.Count < 2) // 0级实现逻辑 不做操作
return;
return null;
var distance = Vector2.zero;
TimeSpan totalTimeSpan = TimeSpan.MinValue;
@ -81,7 +104,7 @@ public abstract class PoseBase
var p1 = points[i].Item2;
var p2 = points[i + 1].Item2;
var vector = GetAverageVector(p1, p2, "Nose"); //关键点Nose
var vector = GetBasicVectorDirection(p1, p2);
distance += vector;
if (vector.magnitude > 0.1f) //如果矢量长度大于0.1f,说明有运动
{
@ -106,6 +129,58 @@ public abstract class PoseBase
}
//动作方位是否正确
ValidationMovement(distance, totalTimeSpan, level);
return MovementValidation(distance, totalTimeSpan, level);
}
/// <summary>
/// 帮助方法,用于提供基础的检测,动作方位是否正确
/// </summary>
/// <param name="distance"></param>
/// <param name="totalTimeSpan"></param>
/// <param name="direction"></param>
/// <param name="level"></param>
protected bool? BasicMovementValidation(Vector2 distance, TimeSpan totalTimeSpan, Vector2 direction, int level)
{
if (totalTimeSpan.TotalMilliseconds / 1000 < 0.05f)
{
LogPrint.Error("TimeSpan too short");
return null;
}
var angle = Vector2.SignedAngle(direction, distance);
LogPrint.Log($"Angle:{angle}", PrintLevel.Normal);
if (MathF.Abs(angle) < 50 && distance.magnitude > 10f)
{
//EventManager.Instance.Dispatch(YogaEventType.Action_Success); //方向不能偏移超过10°
return true;
}
else
{
LogPrint.Warning($"Angle:{angle}, magnitude:{distance.magnitude}", PrintLevel.Important);
//EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
return false;
}
//if (level < 1)
// return;
//暂时关闭距离检测,因为距离检测不准确
//LogPrint.Log($"distance x:{distance.x}, y:{distance.y}, magnitude:{distance.magnitude}", PrintLevel.Normal);
//if (distance.magnitude > 80f || distance.magnitude < 20f)
// EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceNotAccurate);
//else
// EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceExactly);
//if (level < 2)
// return;
//暂时关闭速度检测,因为速度检测不准确
//var speed = distance.magnitude / totalTimeSpan.TotalSeconds;
//LogPrint.Log($"speed:{speed}", PrintLevel.Normal);
//if (speed > 20f)
// EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooFast); //速度语音提示
//else if (speed < 8f)
// EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooSlow); //速度语音提示
}
}

View File

@ -0,0 +1,58 @@
using OpenCVForUnity.CoreModule;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class RightLateralHead : PoseBase
{
public override bool? AnalyzingAction(List<(DateTime, List<Point>)> points, bool isDataReGather = false)
{
if (points.Count < 2) // 0级实现逻辑 不做操作
return null;
var pointList = points.OrderBy(p => p.Item1);
var startP = points.First().Item2;
var endP = points.Last().Item2;
var startDir = "Nose".vector(startP) - "Neck".vector(startP);
var endDir = "Nose".vector(endP) - "Neck".vector(endP);
var angle = Vector2.SignedAngle(startDir, endDir);
LogPrint.Log($"angle: {angle}", PrintLevel.Normal);
if (MathF.Abs(angle) > 10)
{
return true;
}
else
{
return false;
}
}
//public override Vector2 GetBasicVectorDirection(List<Point> startPoint, List<Point> endPoint)
//{
// List<Vector2> vectors = new List<Vector2>();
// //必要点位 Nose Neck
// //计算鼻子到头颈矢量
// //return GetAverageVector(startPoint, endPoint, "Nose");
// return GetTwoPointAverageVector(startPoint, endPoint, "Nose", "Neck");
//}
protected override bool IsMovePoint(string tagName)
{
return "Nose" == tagName || "REye" == tagName || "LEye" == tagName || "REar" == tagName || "LEar" == tagName;
}
public override bool? MovementValidation(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
return BasicMovementValidation(distance, totalTimeSpan, Vector2.right, level);
}
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)
{
throw new NotImplementedException();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: acc96f5678272bb43bc70fd7c1737ede
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,18 +1,25 @@
using SRF;
using SRF;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Audio;
//声音管理器
//声音管理器
public class AudioManager : MonoSingleton<AudioManager>
{
private Queue<string> _CVFiles = new Queue<string>();
private AudioSource _cvSouce;
private AudioSource _cvSource;
private AudioSource _seSource;
private AudioSource _bgmSource;
private readonly float _cvCDTime = 0.2f;
private float _cvCDTimer = 0;
//音乐音量
//音乐音量
private float _musicVolume;
private float _cvVolume;
private Queue<(string, AudioClip)> _cacheMusicSource = new Queue<(string, AudioClip)>();
private const int _musciSourceCacheNumber = 20;
public float MusicVolume
{
@ -28,9 +35,6 @@ public class AudioManager : MonoSingleton<AudioManager>
set => _seVolume = value;
}
private float _cvVolume;
private Queue<AudioSource> _cacheAudioSource;
public float CVVolume
{
get => _cvVolume;
@ -39,11 +43,30 @@ public class AudioManager : MonoSingleton<AudioManager>
public override void Init()
{
_cvSouce = gameObject.GetComponentOrAdd<AudioSource>();
_cvSouce.name = "CVSource";
_cvSource = GetAudioSource("CVSource");
_seSource = GetAudioSource("SESource");
_bgmSource = GetAudioSource("BGMSource");
}
//播放音乐
private AudioSource GetAudioSource(string name)
{
var transAS = transform.Find(name);
AudioSource retVal;
if (transAS != null)
{
retVal = transAS.GetComponent<AudioSource>();
}
else
{
GameObject asGo = new GameObject(name);
asGo.transform.SetParent(transform);
retVal = asGo.GetComponentOrAdd<AudioSource>();
retVal.name = name;
}
return retVal;
}
//播放音乐
public void PlayMusic(string name)
{
@ -51,7 +74,9 @@ public class AudioManager : MonoSingleton<AudioManager>
public void PlaySE(string name)
{
var clip = GetAudioClip("SE", name);
_seSource.clip = clip;
_seSource.Play();
}
public void PlayCV(string name)
@ -66,15 +91,15 @@ public class AudioManager : MonoSingleton<AudioManager>
private void Update()
{
//播放队列中音频
//播放队列中音频
if (_CVFiles.Count > 0)
{
//正在播放
if (_cvSouce.isPlaying)
//正在播放
if (_cvSource.isPlaying)
{
return;
}
//播放完成后等待0.5秒
//播放完成后等待0.5秒
if (_cvCDTimer < _cvCDTime)
{
_cvCDTimer += Time.deltaTime;
@ -84,8 +109,8 @@ public class AudioManager : MonoSingleton<AudioManager>
var name = _CVFiles.Dequeue();
var clip = GetAudioClip("CV", name);
_cvSouce.clip = clip;
_cvSouce.Play();
_cvSource.clip = clip;
_cvSource.Play();
}
}
@ -96,7 +121,7 @@ public class AudioManager : MonoSingleton<AudioManager>
public void StopSE()
{
_seSource.Stop();
}
public void StopCV()
@ -104,9 +129,34 @@ public class AudioManager : MonoSingleton<AudioManager>
}
/// <summary>
/// 获取音频文件
/// 总缓存10个
/// </summary>
/// <param name="type"></param>
/// <param name="path"></param>
/// <returns></returns>
private AudioClip GetAudioClip(string type, string path)
{
var retVal = Resources.Load<AudioClip>($"{type}/{path}");
return retVal;
var retVal = _cacheMusicSource.ToArray().ToList().Find(x => x.Item1.Equals($"{type}/{path}"));
if (retVal.Item2 != null)
{
return retVal.Item2;
}
var clip = Resources.Load<AudioClip>($"{type}/{path}");
if (clip == null)
{
LogPrint.Error($"AudioClip {type}/{path} is not exist!");
return null;
}
_cacheMusicSource.Enqueue(($"{type}/{path}", clip));
if (_cacheMusicSource.Count > _musciSourceCacheNumber)
{
var tmp = _cacheMusicSource.Dequeue();
Resources.UnloadAsset(tmp.Item2);
}
return clip;
}
}

View File

@ -92,4 +92,9 @@ public enum YogaEventType
Action_SpeedTooSlow,
Action_MoveDistanceNotAccurate,
UI_LevelFinished,
Sound_CountDownAudio,
Sound_CountDownEndAudio,
Action_StartSampling,
Action_EndSampling,
Action_Evaluate,
}

View File

@ -1,12 +1,32 @@
using UnityEngine;
using System;
using UnityEngine;
public class GlobalData : MonoSingleton<GlobalData>
{
private PositionType _position = PositionType.None;
private int _cameraIndex = 0;
private bool _isEstimationDebugMode = true;
private bool _isFlip = false;
public PositionType Position { get => _position; internal set => _position = value; }
public PositionType Position
{
get => _position;
internal set => _position = value;
}
public bool IsDriverPosition
{
get
{
return (IsFlip ? _position != PositionType.Driver : _position == PositionType.Driver); //图像反向时,主驾驶和副驾驶的位置判断相反
}
}
public bool IsFlip
{
get => _isFlip;
internal set => _isFlip = value;
}
public int CameraIndex { get => _cameraIndex; internal set => _cameraIndex = value; }
public bool IsEstimationPrintMode { get => _isEstimationDebugMode; internal set => _isEstimationDebugMode = value; }

View File

@ -10,6 +10,7 @@ using System.Data;
using System.Linq;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using UnityEngine.UI;
using Yoga;
@ -27,7 +28,6 @@ public class YogaManager : MonoSingleton<YogaManager>
set => _rgbaMat = value;
}
protected bool _isCorrectAction = false;
private Queue<(DateTime, List<Point>)> _estimateKeyPointsCache = new Queue<(DateTime, List<Point>)>();
public Queue<(DateTime, List<Point>)> EstimateKeyPointsCache
{
@ -52,20 +52,20 @@ public class YogaManager : MonoSingleton<YogaManager>
public List<Point> BaseKeyPoints { get => _baseKeyPoints; set => _baseKeyPoints = value; }
private int _currentActionCount; //当前动作计数
public int CurrentActionCount { get => _currentActionCount; }
private int _currentCheckPointCount; //当前动作计数
public int CurrentCheckPointCount { get => _currentCheckPointCount; }
private int _currentSuccessActionCount; //当前成功动作计数
public int CurrentSuccessActionCount { get => _currentSuccessActionCount; }
private int _currentCheckPointSuccessCount; //当前成功动作计数
public int CurrentCheckPointSuccessCount { get => _currentCheckPointSuccessCount; }
public int MaxActionCount => LevelData.MaxActionCount;
public int MaxCheckPointCount => LevelData.MaxCheckPointCount;
private int _actionIndex = -1; //用户选择界面选择的动作索引
public int ActionIndex { get => _actionIndex; internal set => _actionIndex = value; }
private int _levelIndex = -1; //用户选择界面选择的动作索引
public int LevelIndex { get => _levelIndex; internal set => _levelIndex = value; }
private Dictionary<AvatarAction, PoseBase> _actions = new Dictionary<AvatarAction, PoseBase>();
private bool _isActionRunning = false;
private bool _isSamplingRunning = false;
public YogaData LevelData
@ -87,7 +87,15 @@ public class YogaManager : MonoSingleton<YogaManager>
public Estimator CurrentEstimator { get => _currentEstimator; internal set => _currentEstimator = value; }
private YogaData _levelData = null;
private int _actionIndex = 0;
private int _comboTimes = 0;
private bool? _samplingResult = null;
private bool? _samplingYogaResult;
public DateTime ActionStartTime { get; set; }
public int ActionIndex { get => _actionIndex; internal set => _actionIndex = value; }
public bool? SamplingResult { get => _samplingResult; }
public void InitData()
{
_actions[AvatarAction.HeadTurnLeft] = new HeadTurnLeft();
@ -97,22 +105,21 @@ public class YogaManager : MonoSingleton<YogaManager>
_actions[AvatarAction.HandsUp] = new HandsUp();
_actions[AvatarAction.HandsDown] = new HandsHold();
_currentActionCount = 0;
_currentSuccessActionCount = 0;
_currentCheckPointCount = 0;
_currentCheckPointSuccessCount = 0;
_comboTimes = 0;
//根据用户选择的动作索引,获取相应的资源
LevelData = YogaDataLoader.LoadData(ActionIndex);
EventManager.Instance.Dispatch(YogaEventType.UpdateProgress, CurrentSuccessActionCount, CurrentActionCount);
LevelData = YogaDataLoader.LoadData(LevelIndex);
EventManager.Instance.Dispatch(YogaEventType.UpdateProgress, CurrentCheckPointSuccessCount, CurrentCheckPointCount);
}
private void OnEnable()
{
EventManager.Instance.AddEventListener(YogaEventType.UI_ScoreUpdate, ScoreUpdate);
EventManager.Instance.AddEventListener(YogaEventType.UI_LevelFinished, ClearingSettlement);
EventManager.Instance.AddEventListener(YogaEventType.Action_Success, OnActionSuccess);
EventManager.Instance.AddEventListener(YogaEventType.Action_Fail, OnActionFailed);
EventManager.Instance.AddEventListener(YogaEventType.Action_Start, OnActionStart);
EventManager.Instance.AddEventListener(YogaEventType.Action_End, OnActionEnd);
EventManager.Instance.AddEventListener(YogaEventType.Action_Evaluate, OnEvaluation);
//extra event
EventManager.Instance.AddEventListener(YogaEventType.Action_MoveDistanceExactly, ExtraMoveDistanceExactly);
EventManager.Instance.AddEventListener(YogaEventType.Action_MoveDistanceNotAccurate, ExtraMoveDistanceNotAccurate);
@ -121,15 +128,17 @@ public class YogaManager : MonoSingleton<YogaManager>
}
private void OnDisable()
{
EventManager.Instance.RemoveEventListener(YogaEventType.UI_ScoreUpdate, ScoreUpdate);
EventManager.Instance.RemoveEventListener(YogaEventType.UI_LevelFinished, ClearingSettlement);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_Success, OnActionSuccess);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_Fail, OnActionFailed);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_Start, OnActionStart);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_End, OnActionEnd);
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);
@ -140,27 +149,27 @@ public class YogaManager : MonoSingleton<YogaManager>
#region UI相关
private void OnActionSuccess()
{
_currentSuccessActionCount++;
_currentActionCount++;
AudioManager.Instance.PlayCVInQueue("Correct");
_currentCheckPointSuccessCount++;
_currentCheckPointCount++;
//是否为连续正确动作
UpdateData();
}
private void OnActionFailed()
{
_currentActionCount++;
AudioManager.Instance.PlayCVInQueue("Wrong");
_currentCheckPointCount++;
UpdateData();
}
private void UpdateData()
{
if (CurrentActionCount > MaxActionCount)//如果超过最大数,则停止检测,跳转到下一个动作/下一个动作引导/奖励界面
if (CurrentCheckPointCount > MaxCheckPointCount)//如果超过最大数,则停止检测,跳转到下一个动作/下一个动作引导/奖励界面
{
LogPrint.Warning("CurrentActionCount > MaxActionCount", PrintLevel.Normal);
ClearingSettlement();
}
EventManager.Instance.Dispatch(YogaEventType.UpdateProgress, CurrentSuccessActionCount, CurrentActionCount, MaxActionCount);//args[0] = successCount args[1] = excutedCount args[2] = totalCount
EventManager.Instance.Dispatch(YogaEventType.UpdateProgress, CurrentCheckPointSuccessCount, CurrentCheckPointCount, MaxCheckPointCount);//args[0] = successCount args[1] = excutedCount args[2] = totalCount
}
/// <summary>
@ -170,31 +179,16 @@ public class YogaManager : MonoSingleton<YogaManager>
{
//跳转到奖励界面
UIManager.Instance.CloseCurrent(); //关闭当前界面并停止检测
UIManager.Instance.ShowPanel<ClearingSettlementUI>(false, CurrentSuccessActionCount, MaxActionCount);//args[0] = successCount args[1] = totalCount
UIManager.Instance.ShowPanel<ClearingSettlementUI>(false, CurrentCheckPointSuccessCount, MaxCheckPointCount);//args[0] = successCount args[1] = totalCount
_estimateKeyPointsCache.Clear();
}
public void ScoreUpdate()
{
if (_isCorrectAction)
{
EventManager.Instance.Dispatch(YogaEventType.Action_Success);
}
else
{
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
}
_isCorrectAction = false;//重置
}
#endregion
#region
//采样质量评估
public void SampleQualityEvaluation(AvatarAction actionType, DateTime startTime, DateTime endTime)
public bool? SampleQualityEvaluation(AvatarAction actionType, DateTime startTime, DateTime endTime)
{
//获取时间间隔内的所有点及向量变化
var framePoints = _estimateKeyPointsCache.Where(x => x.Item1 >= startTime && x.Item1 <= endTime).ToList();
@ -216,16 +210,16 @@ public class YogaManager : MonoSingleton<YogaManager>
if (checkedPoints.Count < 2) //0级实现逻辑
{
NeedMoreData(actionType, startTime, endTime);
return NeedMoreData(actionType, startTime, endTime);
}
else
{
_actions[actionType].AnalyzingAction(checkedPoints);
return _actions[actionType].AnalyzingAction(checkedPoints);
}
}
//需要更多数据
private void NeedMoreData(AvatarAction actionType, DateTime startTime, DateTime endTime)
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();
@ -233,95 +227,73 @@ public class YogaManager : MonoSingleton<YogaManager>
{
//提示摆正姿势
LogPrint.Warning("No point has been estimated!");
return;
return null;
}
//检测动作是否正确
_actions[actionType].AnalyzingAction(points, true);
return _actions[actionType].AnalyzingAction(points, true);
}
#endregion
#region
private void OnActionStart(params object[] args)
{
//如果上一次动作还未结束
if (_isActionRunning)
{
//结束上一次动作
OnActionEnd();
}
if (args == null || args.Length < 2)
private void OnSamplingStart()
{
LogPrint.Error("GetActionBasePoint args is null. Please check animation event trigger configuration.");
return;
}
try
{
AvatarAction actionType = (AvatarAction)args.FirstOrDefault();
bool isMoveBack = (bool)args.LastOrDefault();
LogPrint.Log($"PlayGuideVoice: {actionType}");
if (isMoveBack)
{
AudioManager.Instance.PlayCVInQueue(actionType.ToString());
}
else
{
AudioManager.Instance.PlayCVInQueue("BackToPosition");
}
//获取开始时间标记戳
ActionStartTime = DateTime.Now;
_isActionRunning = true;
}
catch (Exception e)
{
LogPrint.Exception(e);
return;
}
_isSamplingRunning = true;
}
private void OnActionEnd(params object[] args)
private void OnSamplingEnd(params object[] args)
{
//如果上一次动作已经结束
if (!_isActionRunning)
return;
_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();
bool isActionEnd = (bool)args.LastOrDefault();
var startTime = ActionStartTime;
var endTime = DateTime.Now;
LogPrint.Log($"PlayGuideVoice: {actionType}");
if (isActionEnd)
_samplingResult = SampleQualityEvaluation(actionType, ActionStartTime, DateTime.Now);
//只有hold动作检测
if (actionType == AvatarAction.Hold)
{
AudioManager.Instance.PlayCVInQueue("End");
_samplingYogaResult = _samplingResult;
}
else
{
AudioManager.Instance.PlayCVInQueue("Hold");
}
//结束上一次动作
//对动作进行采样质量评估
SampleQualityEvaluation(actionType, startTime, endTime);
_isActionRunning = false;
}
catch (Exception e)
{
LogPrint.Exception(e);
return;
}
}
private void OnEvaluation()
{
if (_samplingYogaResult == null || _samplingYogaResult == false)
{
_samplingYogaResult = null;
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
return;
}
EventManager.Instance.Dispatch(YogaEventType.Action_Success);
_comboTimes++;
if (_comboTimes >= 3)
{
AudioManager.Instance.PlayCVInQueue("WellDone");
}
else if (_comboTimes == 2)
{
AudioManager.Instance.PlayCVInQueue("Nice");
}
else
{
AudioManager.Instance.PlayCVInQueue("Good");
}
_samplingYogaResult = null;
}
/// extra
private void ExtraMoveDistanceExactly()
{

8
Assets/Scripts/Test.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a97e4ec7287092d42b7a85cd01a0b49a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,238 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using Yoga;
public class TestGuideUI : UIPanelBase
{
private GameObject _guide;
private Animator _effectAnimator;
private Transform _content;
//计时进度条
private Image _progressBar;
private DateTime _startTime;
private float _totalSeconds;
//面板显示数据
private TextMeshProUGUI _successText;
private TextMeshProUGUI _totalText;
private TextMeshProUGUI _kcalText;
public GudieAnimationManager GuideMgr => _guide.GetComponent<GudieAnimationManager>();
private void Awake()
{
_guide = GameObject.FindWithTag("Guide");
if (_guide == null)
{
LogPrint.Error("Guide is null");
}
_effectAnimator = transform.Find("Content").GetComponentInChildren<Animator>();
_content = transform.Find("Content");
_progressBar = _content.Find("Guide/ProgressBar/Background/ProgressBar").GetComponent<Image>();
var detailPanel = _content.Find("DetailPanel");
_successText = detailPanel.Find("SuccessCount").GetComponent<TextMeshProUGUI>();
_totalText = detailPanel.Find("TotalCount").GetComponent<TextMeshProUGUI>();
_kcalText = detailPanel.Find("KcalNum").GetComponent<TextMeshProUGUI>();
}
private void OnEnable()
{
EventManager.Instance.AddEventListener(YogaEventType.PlayAnimation, PlayAnimation);
EventManager.Instance.AddEventListener(YogaEventType.Action_Success, ShowSuccessEffect);
EventManager.Instance.AddEventListener(YogaEventType.UpdateProgress, UpdateSuccessCount);
EventManager.Instance.AddEventListener(YogaEventType.Action_Fail, ShowFailEffect);
EventManager.Instance.AddEventListener(YogaEventType.DEBUG_CONSOLE_ChangeCamMode, ChangeCameraCaptureMode);
//倒计时音效
EventManager.Instance.AddEventListener(YogaEventType.Sound_CountDownAudio, PlayCountDownAudio);
EventManager.Instance.AddEventListener(YogaEventType.Sound_CountDownEndAudio, PlayCountDownEndAudio);
}
private void OnDisable()
{
EventManager.Instance.RemoveEventListener(YogaEventType.PlayAnimation, PlayAnimation);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_Success, ShowSuccessEffect);
EventManager.Instance.RemoveEventListener(YogaEventType.UpdateProgress, UpdateSuccessCount);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_Fail, ShowFailEffect);
EventManager.Instance.RemoveEventListener(YogaEventType.DEBUG_CONSOLE_ChangeCamMode, ChangeCameraCaptureMode);
//倒计时音效
EventManager.Instance.RemoveEventListener(YogaEventType.Sound_CountDownAudio, PlayCountDownAudio);
EventManager.Instance.RemoveEventListener(YogaEventType.Sound_CountDownEndAudio, PlayCountDownEndAudio);
}
#region Event Func
private void PlayAnimation(params object[] args)
{
var animeType = args.FirstOrDefault();
if (animeType == null)
{
LogPrint.Error("PlayAnimation animeType is null");
return;
}
if (animeType is AvatarAction)
{
GuideMgr.Play(Enum.GetName(typeof(AvatarAction), animeType));
return;
}
if (animeType is List<AvatarAction>)
{
var actionList = animeType as List<AvatarAction>;
if (actionList == null)
{
LogPrint.Error("PlayAnimation actionList is null");
return;
}
GuideMgr.PlayCurrentActionList(actionList);
return;
}
}
private void UpdateSuccessCount(params object[] args)
{
//args[0] = successCount args[1] = excutedCount args[2] = totalCount
if (args.Length < 3)
{
LogPrint.Error("UpdateSuccessCount args is not enough");
return;
}
var successCount = (int)args[0];
var excutedCount = (int)args[1];
if (_successText != null)
{
_successText.text = successCount.ToString();
}
if (_kcalText != null)
{
_kcalText.text = (successCount * 0.1f + (excutedCount - successCount) * 0.5f).ToString("F1");
}
}
private void ShowFailEffect()
{
_effectAnimator.Play("WindowEffectError", 0, 0f);//边框闪烁
}
private void ShowSuccessEffect()
{
_effectAnimator.Play("WindowEffectCorrect", 0, 0f);//边框闪烁
}
#endregion
public override void Init(object[] pageData)
{
base.Init(pageData);
if (_guide == null)
_guide = GameObject.FindWithTag("Guide");
if (pageData[0] == null)
{
LogPrint.Error("Guide is null");
return;
}
YogaData data = pageData[0] as YogaData;
_totalSeconds = data.TotalSeconds;
if (_totalSeconds == 0)
{
LogPrint.Error("TotalSeconds is 0");
return;
}
//重置显示数据
if (_successText != null)
{
_successText.text = "0";
}
if (_totalText != null)
{
_totalText.text = data.MaxCheckPointCount.ToString();
}
if (_kcalText != null)
{
_kcalText.text = "0";
}
}
//播放倒计时音效
private void PlayCountDownAudio()
{
AudioManager.Instance.PlaySE("CountDown");
}
//播放开始音效
private void PlayCountDownEndAudio()
{
AudioManager.Instance.PlaySE("CountDownEnd");
}
//更新进度条
private void ProgressUpdate()
{
var passedTime = Math.Abs((_startTime - DateTime.Now).TotalSeconds);
_progressBar.fillAmount = (float)(passedTime / _totalSeconds);
}
public override void OnEnter()
{
base.OnEnter();
_guide.SetActive(true);
EventManager.Instance.Dispatch(YogaEventType.StartMotionCapture);
EventManager.Instance.Dispatch(YogaEventType.PlayAnimation, YogaManager.Instance.LevelData.Actions);
//EventManager.Instance.Dispatch(YogaEventType.PlayAnimation, YogaManager.Instance.LevelData.Action);
_startTime = DateTime.Now;
InvokeRepeating("ProgressUpdate", 0, 0.05f); //20fps
}
public override void OnExit()
{
base.OnExit();
if (_guide != null)
_guide.SetActive(false);
GuideMgr.Stop();
EventManager.Instance.Dispatch(YogaEventType.StopMotionCapture);
}
private void ChangeCameraCaptureMode()
{
Transform webCam = _content.Find("WebCameraCaptureManager");
Transform usbCam = _content.Find("USBCameraCaptureManager");
CaptureManagerBase manager;
if (webCam == null || usbCam == null)
{
LogPrint.Error("ChangeCameraCaptureMode webCam or usbCam is null");
return;
}
if (webCam.gameObject.activeSelf)
{
webCam.gameObject.SetActive(false);
usbCam.gameObject.SetActive(true);
manager = usbCam.GetComponent<MotionUSBCameraCaptureManager>();
}
else
{
webCam.gameObject.SetActive(true);
usbCam.gameObject.SetActive(false);
manager = webCam.GetComponent<MotionWebCaptureManager>();
}
manager.Init();
manager.IsOnCamCapture = true;
CVEstimator.Instance.StartEstimation();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5f47dab2c015c444b9f6ed1cd99a9c2f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,4 +1,4 @@
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Yoga;
@ -21,7 +21,7 @@ public class TestUI : UIPanelBase
public void OnPosBtnClick()
{
if (GlobalData.Instance.Position == PositionType.CoDriver)
if (!GlobalData.Instance.IsDriverPosition) //当前为副驾驶
{
GlobalData.Instance.Position = PositionType.Driver;
}

View File

@ -0,0 +1,12 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestYogaManager : MonoBehaviour
{
private void Awake()
{
UIManager.Instance.LoadReset();
UIManager.Instance.ShowPanel<TestGuideUI>(YogaManager.Instance.LevelData);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 147592cc6d14ae1439dfaa25f80d242e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -7,7 +7,7 @@ public class ActionListUIPanel : UIPanelBase
{
public void OnLoadBtnClicked(int index)
{
YogaManager.Instance.ActionIndex = index;
YogaManager.Instance.LevelIndex = index;
YogaManager.Instance.InitData();
LoadingManager.Instance.Load("YogaMain");
UIManager.Instance.ClearPanel();

View File

@ -2,6 +2,8 @@
using OpenCVForUnity.ImgprocModule;
using OpenCVForUnity.UnityUtils;
using Serenegiant.UVC;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@ -37,8 +39,19 @@ namespace Yoga
private void Awake()
{
Init();
InvokeRepeating("GCCollection", 0, 1f);
}
private void GCCollection()
{
if (_isOnCamCapture && enabled == true)
StartCoroutine(CleanUp());
}
private IEnumerator CleanUp()
{
GC.Collect();
yield return Resources.UnloadUnusedAssets();
GC.Collect();
}
public void Init()
{
_isInited = true;
@ -50,11 +63,13 @@ namespace Yoga
private void OnEnable()
{
EventRegist();
ManagerEnable();
}
private void OnDisable()
{
EventRemove();
ManagerDisable();
}
private void Update()
@ -74,8 +89,6 @@ namespace Yoga
if (YogaManager.Instance.CurrentEstimator.Check(ref img))//检测模型,将错误信息打印在图片上
{
if (YogaManager.Instance.RgbaMat != null)
YogaManager.Instance.RgbaMat.Dispose();
YogaManager.Instance.RgbaMat = img.clone();
//打印
@ -155,6 +168,16 @@ namespace Yoga
EventManager.Instance.AddEventListener(YogaEventType.StopMotionCapture, OnStopMotionCapture);
}
protected virtual void ManagerEnable()
{
}
protected virtual void ManagerDisable()
{
}
protected virtual void EventRemove()
{
EventManager.Instance.RemoveEventListener(YogaEventType.StartMotionCapture, OnStartMotionCapture);

View File

@ -1,4 +1,5 @@
using System.Collections;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
@ -6,6 +7,19 @@ public class GudieAnimationManager : MonoBehaviour
{
private Animator _animator;
private string _currName;
private List<AvatarAction> _actionList = new List<AvatarAction>();
public Animator Animator
{
get
{
if (_animator == null)
{
_animator = transform.GetComponentInChildren<Animator>();
}
return _animator;
}
}
private void Awake()
{
@ -14,32 +28,39 @@ public class GudieAnimationManager : MonoBehaviour
public void Play(string name)
{
_animator.CrossFade(name, 0.5f);
Animator.CrossFade(name, 0.5f);
_currName = name;
}
public void PlayCurrentActionList(List<AvatarAction> actionList)
{
_actionList = actionList;
YogaManager.Instance.ActionIndex = 0;
Play(Enum.GetName(typeof(AvatarAction), _actionList[YogaManager.Instance.ActionIndex]));
}
private void Update()
{
if (string.IsNullOrEmpty(_currName))
return;
//当未达到指标且动画播放完毕时,重新播放
if (_animator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 1.0f)
if (Animator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 1.0f)
{
if (YogaManager.Instance.CurrentActionCount < YogaManager.Instance.MaxActionCount)
//如果列表动画index小于列表长度播放下一个动画
YogaManager.Instance.ActionIndex++;
//如果列表动画index大于等于列表长度说明动画播放完毕停止播放
if (YogaManager.Instance.ActionIndex >= YogaManager.Instance.LevelData.Actions.Count)
{
_animator.Play(_currName, 0, 0.0f);
Stop();
return;
}
Play(Enum.GetName(typeof(AvatarAction), _actionList[YogaManager.Instance.ActionIndex]));
}
}
public void Stop()
{
_animator.StopPlayback();
Animator.StopPlayback();
}
public void FrameEstimate()
{
EventManager.Instance.Dispatch(YogaEventType.PoseEstimate);
}
}

View File

@ -15,20 +15,17 @@ namespace Yoga
private void Awake()
{
_flipImg = Resources.Load<Material>("Materials/Unlit_FlipHorizontal");
InvokeRepeating("GCCollection", 0, 1f);
}
private void GCCollection()
protected override void ManagerEnable()
{
StartCoroutine(CleanUp());
}
private IEnumerator CleanUp()
{
GC.Collect();
yield return Resources.UnloadUnusedAssets();
GC.Collect();
GlobalData.Instance.IsFlip = true;
}
protected override void ManagerDisable()
{
GlobalData.Instance.IsFlip = false;
}
protected override Mat GetMat()
{
Mat img = null;

View File

@ -49,6 +49,10 @@ public class GuideUI : UIPanelBase
EventManager.Instance.AddEventListener(YogaEventType.UpdateProgress, UpdateSuccessCount);
EventManager.Instance.AddEventListener(YogaEventType.Action_Fail, ShowFailEffect);
EventManager.Instance.AddEventListener(YogaEventType.DEBUG_CONSOLE_ChangeCamMode, ChangeCameraCaptureMode);
//倒计时音效
EventManager.Instance.AddEventListener(YogaEventType.Sound_CountDownAudio, PlayCountDownAudio);
EventManager.Instance.AddEventListener(YogaEventType.Sound_CountDownEndAudio, PlayCountDownEndAudio);
}
private void OnDisable()
@ -58,6 +62,10 @@ public class GuideUI : UIPanelBase
EventManager.Instance.RemoveEventListener(YogaEventType.UpdateProgress, UpdateSuccessCount);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_Fail, ShowFailEffect);
EventManager.Instance.RemoveEventListener(YogaEventType.DEBUG_CONSOLE_ChangeCamMode, ChangeCameraCaptureMode);
//倒计时音效
EventManager.Instance.RemoveEventListener(YogaEventType.Sound_CountDownAudio, PlayCountDownAudio);
EventManager.Instance.RemoveEventListener(YogaEventType.Sound_CountDownEndAudio, PlayCountDownEndAudio);
}
#region Event Func
@ -70,7 +78,24 @@ public class GuideUI : UIPanelBase
return;
}
if (animeType is AvatarAction)
{
GuideMgr.Play(Enum.GetName(typeof(AvatarAction), animeType));
return;
}
if (animeType is List<AvatarAction>)
{
var actionList = animeType as List<AvatarAction>;
if (actionList == null)
{
LogPrint.Error("PlayAnimation actionList is null");
return;
}
GuideMgr.PlayCurrentActionList(actionList);
return;
}
}
private void UpdateSuccessCount(params object[] args)
@ -136,7 +161,7 @@ public class GuideUI : UIPanelBase
if (_totalText != null)
{
_totalText.text = data.MaxActionCount.ToString();
_totalText.text = data.MaxCheckPointCount.ToString();
}
if (_kcalText != null)
@ -145,6 +170,17 @@ public class GuideUI : UIPanelBase
}
}
//播放倒计时音效
private void PlayCountDownAudio()
{
AudioManager.Instance.PlaySE("CountDown");
}
//播放开始音效
private void PlayCountDownEndAudio()
{
AudioManager.Instance.PlaySE("CountDownEnd");
}
//¸üнø¶ÈÌõ
private void ProgressUpdate()
{
@ -157,7 +193,8 @@ public class GuideUI : UIPanelBase
base.OnEnter();
_guide.SetActive(true);
EventManager.Instance.Dispatch(YogaEventType.StartMotionCapture);
EventManager.Instance.Dispatch(YogaEventType.PlayAnimation, YogaManager.Instance.LevelData.Action);
EventManager.Instance.Dispatch(YogaEventType.PlayAnimation, YogaManager.Instance.LevelData.Actions);
//EventManager.Instance.Dispatch(YogaEventType.PlayAnimation, YogaManager.Instance.LevelData.Action);
_startTime = DateTime.Now;
InvokeRepeating("ProgressUpdate", 0, 0.05f); //20fps

View File

@ -1,17 +1,30 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Yoga;
using static UnityEngine.Rendering.GPUSort;
public class RobotController : MonoBehaviour
{
public void ActionEnd(AvatarAction action)
public void ActionEnd()
{
EventManager.Instance.Dispatch(YogaEventType.Action_End, action, true);
AudioManager.Instance.PlayCVInQueue("End");
}
public void ActionHold(AvatarAction action)
public void ActionRecheck(AvatarAction action)
{
EventManager.Instance.Dispatch(YogaEventType.Action_End, action, false);
if (action == AvatarAction.Hold)
return;
var result = YogaManager.Instance.SamplingResult;
if (result != null && result == false)
{
AudioManager.Instance.PlayCVInQueue(action.ToString());
//AudioManager.Instance.PlayCVInQueue("And");
}
else
{
//AudioManager.Instance.PlayCVInQueue("Hold");
}
}
public void FinishCurrentLevel()
{
@ -20,11 +33,48 @@ public class RobotController : MonoBehaviour
public void ActionStart(AvatarAction action)
{
EventManager.Instance.Dispatch(YogaEventType.Action_Start, action, true);
AudioManager.Instance.PlayCVInQueue(action.ToString());
}
public void ActionBackStart(AvatarAction action)
public void ActionBackStart()
{
EventManager.Instance.Dispatch(YogaEventType.Action_Start, action, false);
AudioManager.Instance.PlayCVInQueue("Now");
AudioManager.Instance.PlayCVInQueue("Blank");
AudioManager.Instance.PlayCVInQueue("BackToPosition");
}
public void StartSampling()
{
EventManager.Instance.Dispatch(YogaEventType.Action_StartSampling);
}
public void EndSampling(AvatarAction action)
{
EventManager.Instance.Dispatch(YogaEventType.Action_EndSampling, action);
}
public void Evaluate()
{
EventManager.Instance.Dispatch(YogaEventType.Action_Evaluate);
}
public void PlaySE(string seName)
{
AudioManager.Instance.PlaySE(seName);
}
public void PlayCV(string cvName)
{
AudioManager.Instance.PlayCVInQueue(cvName);
}
public void PlayCountDownSE()
{
AudioManager.Instance.PlaySE("CountDown");
}
public void PlayCountDownEndSE()
{
AudioManager.Instance.PlaySE("CountDownEnd");
}
}
@ -43,5 +93,8 @@ public enum AvatarAction
HandsDown,
Stop,
Hold,
None
SitUpright,
Idle,
None,
LateralHead
}

View File

@ -18,6 +18,7 @@ public static class UILoadConfig
{ "MeditationVideoUI" , "UI/MeditationVideoPanel" },
{ "FaceDetectUI" , "UI/FaceDetectUI" },
{ "TestUI" , "UI/TestUI" },
{ "TestGuideUI" , "UI/TestGuideUI" },
};
public static string GetPath(string typeName)

View File

@ -14,9 +14,10 @@ public class YogaDataLoader
data[-1] = new YogaData()
{
VideoPath = "Video/Action3",
Action = AvatarAction.HeadShake,
Actions = new List<AvatarAction>() { AvatarAction.SitUpright, AvatarAction.SitUpright, AvatarAction.Nod },
Action = AvatarAction.Nod,
ModelType = ModelType.OpenPose,
MaxActionCount = 1000,
MaxCheckPointCount = 1000,
TotalSeconds = 20.0f,
RectCutRate = 0.2f,
MustPoints = new List<string>() { "Nose", /*"REye", "LEye", */"Neck" },
@ -26,9 +27,10 @@ public class YogaDataLoader
data[1] = new YogaData()
{
VideoPath = "Video/Action1",
Actions = new List<AvatarAction>() { AvatarAction.SitUpright, AvatarAction.SitUpright, AvatarAction.SitUpright, AvatarAction.HeadShake },
Action = AvatarAction.HeadShake,
ModelType = ModelType.OpenPose,
MaxActionCount = 4,
MaxCheckPointCount = 4,
TotalSeconds = 20.0f,
RectCutRate = 0.25f,
MustPoints = new List<string>() { "Nose", /*"REye", "LEye", */"Neck" }
@ -38,17 +40,17 @@ public class YogaDataLoader
VideoPath = "Video/Action2",
Action = AvatarAction.Nod,
ModelType = ModelType.OpenPose,
MaxActionCount = 4,
MaxCheckPointCount = 4,
TotalSeconds = 20.0f,
RectCutRate = 0.25f,
MustPoints = new List<string>() { "Nose", "REye", "LEye", "Neck" }
MustPoints = new List<string>() { "Nose",/* "REye", "LEye", */"Neck" }
};
data[3] = new YogaData()
{
VideoPath = "Video/Action3",
Action = AvatarAction.HandsUp,
Action = AvatarAction.LateralHead,
ModelType = ModelType.MediapipePose,
MaxActionCount = 4,
MaxCheckPointCount = 4,
TotalSeconds = 12.66f,
MustPoints = new List<string>() { "Nose", "RShoulder", "LShoulder", "RElbow", "LElbow" }
};
@ -67,9 +69,10 @@ public class YogaDataLoader
public class YogaData
{
public string VideoPath;
internal List<AvatarAction> Actions;
public AvatarAction Action;
public ModelType ModelType;
public int MaxActionCount;
public int MaxCheckPointCount;
public float TotalSeconds;
public float RectCutRate;
public List<string> MustPoints = new List<string>();

View File

@ -6,6 +6,7 @@
"com.unity.adaptiveperformance.samsung.android": "5.0.0",
"com.unity.feature.characters-animation": "1.0.0",
"com.unity.ide.visualstudio": "2.0.22",
"com.unity.memoryprofiler": "1.1.0",
"com.unity.render-pipelines.universal": "15.0.7",
"com.unity.textmeshpro": "3.0.6",
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.6",

View File

@ -68,6 +68,13 @@
},
"url": "https://packages.unity.cn"
},
"com.unity.editorcoroutines": {
"version": "1.0.0",
"depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.cn"
},
"com.unity.ext.nunit": {
"version": "2.0.3",
"depth": 2,
@ -112,6 +119,15 @@
"dependencies": {},
"url": "https://packages.unity.cn"
},
"com.unity.memoryprofiler": {
"version": "1.1.0",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.editorcoroutines": "1.0.0"
},
"url": "https://packages.unity.cn"
},
"com.unity.profiling.core": {
"version": "1.0.2",
"depth": 1,