Files
Net.Like.Xue.Tokyo/Packages-Local/Com.Project.B.Unity/World/RagdollAutoConfigurator.cs

148 lines
4.6 KiB
C#
Raw Normal View History

2025-06-24 23:49:13 +08:00
namespace Net.Project.B.World
{
using UnityEngine;
using UnityEngine;
public class RagdollConfigurator : MonoBehaviour
{
void Start()
{
foreach (var joint in GetComponentsInChildren<ConfigurableJoint>())
{
ConfigureJointAxis(joint);
ApplyJointLimits(joint);
}
Destroy(this);
}
/// <summary>
/// 自动配置 ConfigurableJoint 的 axis 和 secondaryAxis
/// </summary>
void ConfigureJointAxis(ConfigurableJoint joint)
{
Transform jointTransform = joint.transform;
HumanBodyBones boneType = GetBoneType(jointTransform);
if (boneType == HumanBodyBones.LastBone) return;
Vector3 primaryAxis;
Vector3 secondaryAxis;
switch (boneType)
{
case HumanBodyBones.Hips:
case HumanBodyBones.Spine:
primaryAxis = jointTransform.right;
secondaryAxis = jointTransform.up;
break;
case HumanBodyBones.LeftUpperArm:
case HumanBodyBones.RightUpperArm:
primaryAxis = jointTransform.forward; // 手臂通常绕前后旋转
secondaryAxis = jointTransform.up;
break;
case HumanBodyBones.LeftLowerArm:
case HumanBodyBones.RightLowerArm:
primaryAxis = jointTransform.forward;
secondaryAxis = jointTransform.right;
break;
case HumanBodyBones.LeftUpperLeg:
case HumanBodyBones.RightUpperLeg:
primaryAxis = jointTransform.right;
secondaryAxis = jointTransform.up;
break;
case HumanBodyBones.LeftLowerLeg:
case HumanBodyBones.RightLowerLeg:
primaryAxis = jointTransform.right;
secondaryAxis = jointTransform.forward;
break;
default:
primaryAxis = jointTransform.right;
secondaryAxis = jointTransform.up;
break;
}
joint.axis = primaryAxis;
joint.secondaryAxis = secondaryAxis;
//Debug.Log($"{boneType} -> Axis: {primaryAxis}, SecondaryAxis: {secondaryAxis}");
}
/// <summary>
/// 自动配置关节角度限制
/// </summary>
void ApplyJointLimits(ConfigurableJoint joint)
{
Transform jointTransform = joint.transform;
HumanBodyBones boneType = GetBoneType(jointTransform);
if (boneType == HumanBodyBones.LastBone) return;
int muscleIndex = HumanTrait.MuscleFromBone((int)boneType, 0);
if (muscleIndex < 0) return;
// 获取默认角度范围,并限制在合理范围内
float minLimit = Mathf.Clamp(HumanTrait.GetMuscleDefaultMin(muscleIndex), -60f, 60f);
float maxLimit = Mathf.Clamp(HumanTrait.GetMuscleDefaultMax(muscleIndex), -60f, 60f);
float limitRange = Mathf.Abs(maxLimit - minLimit) * 0.5f;
// 配置关节限制
SoftJointLimit limit = new SoftJointLimit { limit = limitRange };
SoftJointLimitSpring spring = new SoftJointLimitSpring { spring = 50f, damper = 10f };
joint.lowAngularXLimit = limit;
joint.highAngularXLimit = limit;
joint.angularYLimit = limit;
joint.angularZLimit = limit;
joint.angularXLimitSpring = spring;
joint.angularYZLimitSpring = spring;
joint.angularXMotion = ConfigurableJointMotion.Limited;
joint.angularYMotion = ConfigurableJointMotion.Limited;
joint.angularZMotion = ConfigurableJointMotion.Limited;
// 额外优化
joint.targetRotation = Quaternion.identity;
joint.configuredInWorldSpace = false;
joint.enablePreprocessing = false;
// 设置刚体质量
Rigidbody rb = joint.GetComponent<Rigidbody>();
if (rb != null)
{
rb.mass = boneType == HumanBodyBones.Hips ? 8f : 2f;
}
//Debug.Log($"{boneType} 关节设置完毕: 限制角度 {limitRange}");
}
/// <summary>
/// 通过 Transform 获取 Humanoid 骨骼类型
/// </summary>
HumanBodyBones GetBoneType(Transform jointTransform)
{
Animator animator = GetComponent<Animator>();
if (animator == null || !animator.isHuman) return HumanBodyBones.LastBone;
foreach (HumanBodyBones bone in System.Enum.GetValues(typeof(HumanBodyBones)))
{
if (bone == HumanBodyBones.LastBone) continue;
if (animator.GetBoneTransform(bone) == jointTransform)
{
return bone;
}
}
return HumanBodyBones.LastBone;
}
}
}