using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using Kinect = Windows.Kinect;
public class WarmUpGame : MonoBehaviour
{
public enum ExerciseAction
{
ArmRaise, // 举双手
HeadShake, // 摇头
LegLift, // 抬脚
Jump, // 跳跃
RightBend, // 向右弯腰
Bow, // 鞠躬
Run, // 原地跑步
Squat // 深蹲
}
private KinectManager _kinectManager;
private ExerciseAction _currentAction;
private int _actionCount = 0;
private int _score = 0;
public float _timeRemaining = 30f;
private bool _gameActive = true;
public Animator _animator;
[Header("UI Elements")]
public Text actionText;
public Text countText;
public Text scoreText;
public Text timerText;
public Text debugText; // 新增调试信息显示
[Header("Animation Settings")]
public float animationSpeed = 1.0f;
[Header("Game Settings")]
public int targetCount = 5;
public float actionThreshold = 0.6f;
public int validationFrames = 10; // 动作确认所需连续帧数
// 新增灵敏度参数
[Header("Sensitivity Settings")]
public float headShakeSensitivity = 0.3f;
public float legLiftSensitivity = 0.7f;
public float jumpSensitivity = 0.5f;
public float bendSensitivity = 0.5f;
[Header("Sensitivity Settings")]
public float armRaiseAngleThreshold = 150f; // 手臂伸直角度阈值
public float bowAngleThreshold = 30f; // 鞠躬角度阈值
public float armHeightThreshold = 0.2f; // 手臂高度阈值(相对于头部)
public float headDropThreshold = 0.15f; // 头部下降阈值
public float spineBendThreshold = 25f; // 脊柱弯曲阈值
// 动作状态跟踪
private Dictionary<ExerciseAction, bool> _actionValidated = new Dictionary<ExerciseAction, bool>();
private Dictionary<ExerciseAction, int> _validationCounters = new Dictionary<ExerciseAction, int>();
private Queue<Vector3> _headPositionHistory = new Queue<Vector3>();
private Vector3 _lastSpineBasePosition;
private float _lastHeadRotation;
private bool _lastLegLiftState;
private Vector3 _initialHipPosition;
private Vector3 _lastFootPosition;
private Vector3 _initialHeadPosition;
private Vector3 _initialSpineShoulderPosition;
private Vector3 _initialSpineBasePosition;
public bool feetOffGround;
private float _lastBowDetectionTime;
public float jumpHeight;
public float headDrop;
public float shoulderHipHeightDiff;
private float _initialSpineLength;
public float spineAngle;
public Vector3 spineBase;
void Start()
{
_kinectManager = KinectManager.Instance;
if (_animator != null)
_animator.speed = animationSpeed;
InitializeActionSystems();
// 记录初始位置
if (_kinectManager.IsUserDetected())
{
long userId = _kinectManager.GetUserIdByIndex(0);
_initialHeadPosition = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.Head);
_initialSpineShoulderPosition = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineShoulder);
_initialSpineBasePosition = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineBase);
_initialHipPosition = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineBase);
}
if (_kinectManager.IsUserDetected())
{
long userId = _kinectManager.GetUserIdByIndex(0);
_lastSpineBasePosition = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineBase);
}
_lastSpineBasePosition = Vector3.zero;
_initialHipPosition = Vector3.zero;
_initialHeadPosition = Vector3.zero;
// 强制初始化计数器
foreach (var key in _validationCounters.Keys.ToList())
{
_validationCounters[key] = 0;
}
StartNewAction();
StartCoroutine(GameTimer());
}
void InitializeActionSystems()
{
foreach (ExerciseAction action in System.Enum.GetValues(typeof(ExerciseAction)))
{
_actionValidated[action] = false;
_validationCounters[action] = 0;
}
}
IEnumerator GameTimer()
{
while (_timeRemaining > 0 && _gameActive)
{
yield return new WaitForSeconds(1f);
_timeRemaining--;
timerText.text = $"时间: {_timeRemaining}s";
}
if (_gameActive)
{
_gameActive = false;
actionText.text = "游戏结束!";
if (_animator != null)
_animator.enabled = false;
}
}
void StartNewAction()
{
List<ExerciseAction> availableActions = new List<ExerciseAction>((ExerciseAction[])System.Enum.GetValues(typeof(ExerciseAction)));
if (availableActions.Count > 1 && availableActions.Contains(_currentAction))
availableActions.Remove(_currentAction);
_lastBowDetectionTime = Time.time - 2f; // 确保可以立即检测
_currentAction = availableActions[Random.Range(0, availableActions.Count)];
_actionCount = 0;
countText.text = $"0/{targetCount}";
actionText.text = GetActionName(_currentAction);
// 重置所有验证状态
foreach (var key in new List<ExerciseAction>(_validationCounters.Keys))
{
_validationCounters[key] = 0;
_actionValidated[key] = false;
}
// 重置初始位置记录
if (_kinectManager.IsUserDetected())
{
long userId = _kinectManager.GetUserIdByIndex(0);
_initialHipPosition = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.HipLeft);
}
if (_animator != null)
PlayActionAnimation(_currentAction);
if (_kinectManager.IsUserDetected())
{
long userId = _kinectManager.GetUserIdByIndex(0);
Vector3 spineShoulder = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineShoulder);
Vector3 spineBase = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineBase);
// 记录初始脊柱长度
_initialSpineLength = Vector3.Distance(spineShoulder, spineBase);
}
}
void PlayActionAnimation(ExerciseAction action)
{
foreach (ExerciseAction a in System.Enum.GetValues(typeof(ExerciseAction)))
{
_animator.SetBool(a.ToString(), false);
}
_animator.SetBool(action.ToString(), true);
}
string GetActionName(ExerciseAction action)
{
switch (action)
{
case ExerciseAction.ArmRaise: return "举双手";
case ExerciseAction.HeadShake: return "摇头";
case ExerciseAction.LegLift: return "抬左脚";
case ExerciseAction.Jump: return "跳跃";
case ExerciseAction.RightBend: return "向右弯腰";
case ExerciseAction.Bow: return "鞠躬";
case ExerciseAction.Run: return "原地跑步";
case ExerciseAction.Squat: return "深蹲";
default: return "未知动作";
}
}
void Update()
{
if (!_gameActive || !_kinectManager.IsUserDetected())
{
debugText.text = "等待用户...";
return;
}
long userId = _kinectManager.GetUserIdByIndex(0);
UpdateActionDetection(userId);
// 显示当前动作的调试信息
ShowDebugInfo(userId);
}
void UpdateActionDetection(long userId)
{
bool actionDetected = false;
switch (_currentAction)
{
case ExerciseAction.ArmRaise:
actionDetected = ValidateArmRaise(userId);
break;
case ExerciseAction.HeadShake:
actionDetected = ValidateHeadShake(userId);
break;
case ExerciseAction.LegLift:
actionDetected = ValidateLegLift(userId);
break;
case ExerciseAction.Jump:
actionDetected = ValidateJump(userId);
break;
case ExerciseAction.RightBend:
actionDetected = ValidateRightBend(userId);
break;
case ExerciseAction.Bow:
actionDetected = ValidateBow(userId);
break;
case ExerciseAction.Run:
actionDetected = ValidateRunning(userId);
break;
case ExerciseAction.Squat:
actionDetected = ValidateSquat(userId);
break;
}
if (actionDetected)
{
if (!_actionValidated[_currentAction])
{
_actionCount++;
countText.text = $"{_actionCount}/{targetCount}";
_actionValidated[_currentAction] = true;
if (_actionCount >= targetCount)
{
_score += 50;
scoreText.text = $"分数: {_score}";
StartNewAction();
}
}
}
else
{
_actionValidated[_currentAction] = false;
}
}
// 显示调试信息
void ShowDebugInfo(long userId)
{
string debugInfo = $"当前动作: {_currentAction}\n";
switch (_currentAction)
{
case ExerciseAction.HeadShake:
Vector3 headPosition = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.Head);
Vector3 neckPosition = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.Neck);
float headRotation = Vector3.Angle(Vector3.up, headPosition - neckPosition);
debugInfo += $"头部旋转: {headRotation:F1}°\n阈值: >20°";
break;
case ExerciseAction.LegLift:
Vector3 hipLeft = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.HipLeft);
Vector3 ankleLeft = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.AnkleLeft);
float liftHeight = ankleLeft.y - hipLeft.y;
debugInfo += $"抬腿高度: {liftHeight:F2}m\n阈值: >{legLiftSensitivity:F2}m";
break;
case ExerciseAction.Jump:
// 强制获取实时数据
Vector3 spineBaseNow = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineBase);
Vector3 initialHipNow = _initialHipPosition;
debugInfo = $"当前脊柱Y: {spineBaseNow.y:F3}m | 初始Y: {initialHipNow.y:F3}m\n";
debugInfo += $"高度差: {jumpHeight:F3}m | 离地: {feetOffGround}\n";
// 添加速度显示
if (_lastSpineBasePosition != Vector3.zero)
{
Vector3 velocity = (spineBaseNow - _lastSpineBasePosition) / Time.deltaTime;
debugInfo += $"速度Y: {velocity.y:F2}m/s\n";
}
debugInfo += $"计数器: {_validationCounters[_currentAction]}/2";
break;
case ExerciseAction.RightBend:
Vector3 shoulderCenter = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineShoulder);
Vector3 hipCenter = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineBase);
Vector3 spineVector = hipCenter - shoulderCenter;
float bendAngle = Vector3.Angle(spineVector, Vector3.up);
debugInfo += $"弯曲角度: {bendAngle:F1}°\n阈值: >20°";
break;
case ExerciseAction.Bow:
Vector3 spineShoulder = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineShoulder);
spineBase = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineBase);
Vector3 headPos = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.Head);
Vector3 neck = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.Neck);
float spineLength = Vector3.Distance(spineShoulder, spineBase);
float compression = 1 - (spineLength / _initialSpineLength);
debugInfo = $"脊柱弯曲: {spineAngle:F1}°\n";
debugInfo += $"头降量: {(neck.y - headPos.y):F2}m\n";
debugInfo += $"脊柱压缩: {compression * 100:F1}%";
break;
}
debugText.text = debugInfo;
}
// ===== 改进的动作检测算法 =====
private bool ValidateArmRaise(long userId)
{
// 获取必要关节位置
Vector3 leftHand = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.HandLeft);
Vector3 rightHand = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.HandRight);
Vector3 leftShoulder = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.ShoulderLeft);
Vector3 rightShoulder = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.ShoulderRight);
Vector3 head = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.Head);
// 简化的举双手检测 - 只关注手部是否高于肩膀
bool leftHandRaised = leftHand.y > leftShoulder.y + 0.1f; // 手高于肩膀10cm
bool rightHandRaised = rightHand.y > rightShoulder.y + 0.1f;
// 备选方案:手部高于头部
// bool leftHandRaised = leftHand.y > head.y;
// bool rightHandRaised = rightHand.y > head.y;
// 双手举起即视为成功
return leftHandRaised && rightHandRaised;
}
private bool ValidateHeadShake(long userId)
{
Vector3 headPosition = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.Head);
Vector3 neckPosition = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.Neck);
// 计算头部旋转角度
Vector3 headDirection = headPosition - neckPosition;
float currentRotation = Vector3.Angle(Vector3.up, headDirection);
// 记录历史旋转
_headPositionHistory.Enqueue(headPosition);
if (_headPositionHistory.Count > 30) _headPositionHistory.Dequeue();
// 检查旋转变化
bool rotationDetected = false;
if (_headPositionHistory.Count > 10)
{
Vector3[] positions = _headPositionHistory.ToArray();
float minAngle = float.MaxValue;
float maxAngle = float.MinValue;
for (int i = 0; i < positions.Length; i++)
{
Vector3 dir = positions[i] - neckPosition;
float angle = Vector3.Angle(Vector3.up, dir);
if (angle < minAngle) minAngle = angle;
if (angle > maxAngle) maxAngle = angle;
}
rotationDetected = (maxAngle - minAngle) > 20f; // 20度变化阈值
}
// 增加直接旋转检测
bool directRotation = currentRotation > 20f || Mathf.Abs(currentRotation - _lastHeadRotation) > 15f;
_lastHeadRotation = currentRotation;
return rotationDetected || directRotation;
}
// 改进的抬腿检测
private bool ValidateLegLift(long userId)
{
Vector3 hipLeft = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.HipLeft);
Vector3 kneeLeft = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.KneeLeft);
Vector3 ankleLeft = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.AnkleLeft);
// 计算腿部角度(髋-膝-踝)
float legAngle = Vector3.Angle(kneeLeft - hipLeft, ankleLeft - kneeLeft);
// 计算抬腿高度
float liftHeight = ankleLeft.y - hipLeft.y;
// 检测腿部运动状态变化
bool isLifted = liftHeight > legLiftSensitivity && legAngle < 140f;
bool stateChanged = isLifted && !_lastLegLiftState;
_lastLegLiftState = isLifted;
return stateChanged;
}
// 改进的跳跃检测
private bool ValidateJump(long userId)
{
// 数据验证代码...
// 初始化上一帧位置(首次执行时)
if (_lastSpineBasePosition == Vector3.zero)
{
_lastSpineBasePosition = spineBase;
_initialHipPosition = spineBase; // 同步初始化
return false;
}
// 计算速度(添加除零保护)
float deltaTime = Mathf.Max(Time.deltaTime, 0.001f); // 防止除零
Vector3 velocity = (spineBase - _lastSpineBasePosition) / deltaTime;
_lastSpineBasePosition = spineBase;
// 动态更新初始位置
if (_validationCounters[_currentAction] == 0)
{
_initialHipPosition = spineBase;
}
// 高度计算(添加容错)
jumpHeight = Mathf.Max(spineBase.y - _initialHipPosition.y, 0);
// 离地检测(使用绝对高度差)
Vector3 footLeft = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.FootLeft);
Vector3 footRight = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.FootRight);
feetOffGround = (footLeft.y > _initialHipPosition.y + 0.1f) ||
(footRight.y > _initialHipPosition.y + 0.1f);
// ==== 调试输出强制显示 ====
Debug.Log($"跳跃检测: 高度={jumpHeight} 速度Y={velocity.y} 离地={feetOffGround}");
// 检测逻辑(简化版)
if (jumpHeight > 0.05f && feetOffGround)
{
_validationCounters[_currentAction]++;
if (_validationCounters[_currentAction] >= 2) // 降低帧数要求
{
_validationCounters[_currentAction] = 0;
return true;
}
}
else
{
_validationCounters[_currentAction] = 0;
}
return false;
}
// 改进的右弯检测
private bool ValidateRightBend(long userId)
{
Vector3 shoulderCenter = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineShoulder);
Vector3 hipCenter = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineBase);
Vector3 shoulderLeft = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.ShoulderLeft);
Vector3 shoulderRight = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.ShoulderRight);
// 计算躯干倾斜角度
Vector3 spineVector = hipCenter - shoulderCenter;
float bendAngle = Vector3.Angle(spineVector, Vector3.up);
// 计算肩膀高度差
float shoulderHeightDiff = shoulderLeft.y - shoulderRight.y;
// 使用复合条件提高准确性
return (bendAngle < 148f );
}
private bool ValidateBow(long userId)
{
// 获取当前关节位置
Vector3 headPos = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.Head);
Vector3 spineShoulder = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineShoulder);
Vector3 spineMid = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineMid);
Vector3 spineBase = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.SpineBase);
Vector3 neck = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.Neck);
// 1. 计算脊柱弯曲角度(关键指标)
Vector3 upperSpine = spineShoulder - spineMid;
Vector3 lowerSpine = spineBase - spineMid;
spineAngle = Vector3.Angle(upperSpine, lowerSpine);
// 2. 相对头部下降量(基于颈部参考)
float headDrop = neck.y - headPos.y;
// 3. 脊柱长度变化检测
float spineLength = Vector3.Distance(spineShoulder, spineBase);
float spineCompression = 1 - (spineLength / _initialSpineLength);
// 检测条件(优先脊柱角度)
bool isBowing = spineAngle < 140f || // 脊柱弯曲角度阈值
headDrop > 0.15f || // 头部相对下降量
spineCompression > 0.1f; // 脊柱压缩率
// 冷却时间检查
bool canDetectAgain = (Time.time - _lastBowDetectionTime) > 0.5f;
if (isBowing && canDetectAgain)
{
_lastBowDetectionTime = Time.time;
return true;
}
return false;
}
private bool ValidateRunning(long userId)
{
Vector3 ankleLeft = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.AnkleLeft);
Vector3 ankleRight = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.AnkleRight);
// 检测腿部交替运动
float verticalMovement = Mathf.Abs(ankleLeft.y - ankleRight.y);
bool legsMoving = verticalMovement > actionThreshold * 0.5f;
// 位置变化检测
if (_lastFootPosition != Vector3.zero)
{
float positionChange = Vector3.Distance(ankleLeft, _lastFootPosition);
legsMoving |= positionChange > actionThreshold * 0.2f;
}
_lastFootPosition = ankleLeft;
return legsMoving;
}
private bool ValidateSquat(long userId)
{
Vector3 hipLeft = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.HipLeft);
Vector3 kneeLeft = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.KneeLeft);
Vector3 ankleLeft = _kinectManager.GetJointPosition(userId, (int)Kinect.JointType.AnkleLeft);
// 计算大腿-小腿夹角
Vector3 thighVector = kneeLeft - hipLeft;
Vector3 shinVector = ankleLeft - kneeLeft;
float kneeAngle = Vector3.Angle(thighVector, shinVector);
return kneeAngle < 100f;
}
}
使用以上代碼,脊柱压缩變成了-infinity