修改运作流程
This commit is contained in:
parent
b3d8d06b12
commit
a2437a89c9
|
@ -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
|
@ -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
|
@ -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
Binary file not shown.
|
@ -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.
|
@ -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.
|
@ -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.
|
@ -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.
|
@ -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.
|
@ -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:
|
Binary file not shown.
|
@ -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.
|
@ -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.
|
@ -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.
|
@ -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:
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e6f7e153e2ce17c4eb052426e8aae456
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -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.
|
@ -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
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7dc7f9ac2c5716c45aab1a02191adfa5
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 998f5cf7179256648b9d7e1487bd0fdd
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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; //重新检测
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) //副驾,主驾位跳过
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6f85606217bc2de4ba8e53c63820220c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 47eb13eda73bb7e4eac717169eb64f1d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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;
|
||||
|
@ -80,8 +103,8 @@ 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); //速度语音提示
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: acc96f5678272bb43bc70fd7c1737ede
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,4 +92,9 @@ public enum YogaEventType
|
|||
Action_SpeedTooSlow,
|
||||
Action_MoveDistanceNotAccurate,
|
||||
UI_LevelFinished,
|
||||
Sound_CountDownAudio,
|
||||
Sound_CountDownEndAudio,
|
||||
Action_StartSampling,
|
||||
Action_EndSampling,
|
||||
Action_Evaluate,
|
||||
}
|
|
@ -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; }
|
||||
|
|
|
@ -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)
|
||||
|
||||
private void OnSamplingStart()
|
||||
{
|
||||
//如果上一次动作还未结束
|
||||
if (_isActionRunning)
|
||||
{
|
||||
//结束上一次动作
|
||||
OnActionEnd();
|
||||
}
|
||||
|
||||
if (args == null || args.Length < 2)
|
||||
{
|
||||
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;
|
||||
}
|
||||
//获取开始时间标记戳
|
||||
ActionStartTime = DateTime.Now;
|
||||
_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()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a97e4ec7287092d42b7a85cd01a0b49a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5f47dab2c015c444b9f6ed1cd99a9c2f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 147592cc6d14ae1439dfaa25f80d242e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,11 +1,25 @@
|
|||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
GuideMgr.Play(Enum.GetName(typeof(AvatarAction), animeType));
|
||||
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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue