148 lines
4.6 KiB
C#
148 lines
4.6 KiB
C#
![]() |
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
}
|