diff options
Diffstat (limited to 'Assets/Scripts/PlayerLocomotion.cs')
| -rw-r--r-- | Assets/Scripts/PlayerLocomotion.cs | 166 |
1 files changed, 140 insertions, 26 deletions
diff --git a/Assets/Scripts/PlayerLocomotion.cs b/Assets/Scripts/PlayerLocomotion.cs index 9f058b0..8b77c06 100644 --- a/Assets/Scripts/PlayerLocomotion.cs +++ b/Assets/Scripts/PlayerLocomotion.cs @@ -4,110 +4,224 @@ using System.Collections.Generic; using Unity.Mathematics; using UnityEngine; - namespace DS { + /// <summary> + /// 玩家角色移动/旋转控制器 + /// 负责处理玩家的移动、旋转,并与输入系统、动画系统、物理系统进行交互 + /// </summary> public class PlayerLocomotion : MonoBehaviour { - // 是否使用根动画 + // ============================================================ + // 根运动混合参数 + // ============================================================ + /// <summary> + /// 根运动(Root Motion)与程序化移动的混合比例。 + /// 0 = 完全使用程序化移动(手动计算位移), + /// 1 = 完全使用动画中的根运动(由动画驱动位移)。 + /// 建议在跑步、行走等需要动画精细控制位移时使用根运动; + /// 在需要响应式操控(如闪避、冲刺)时可降低此值。 + /// </summary> [Range(0, 1)] public float rootMotionBlending = 1f; + /// <summary> + /// 便捷属性:将 rootMotionBlending 映射为布尔值。 + /// true = 使用根运动(blending > 0.5), + /// false = 使用程序化移动(blending <= 0.5)。 + /// </summary> public bool usingRootMotion { get => rootMotionBlending > 0.5f; set => rootMotionBlending = value ? 0 : 1; } - - [HideInInspector] public Vector3 rootMotion; - private Transform _cameraObject; //存储Camera的位置 - private InputHandler _inputHandler; - private Vector3 _moveDirection; + // ============================================================ + // 公开字段 + // ============================================================ + /// <summary> + /// 当前帧从动画中提取的根运动位移向量(由 AnimatorHandler 提供)。 + /// 单位:米/帧。 + /// </summary> + [HideInInspector] public Vector3 rootMotion; + + /// <summary> + /// 当前角色的 Transform 引用(缓存避免重复查找)。 + /// </summary> [HideInInspector] public Transform myTransform; + + /// <summary> + /// 动画处理器引用(负责驱动 Animator 参数和根运动提取)。 + /// </summary> [HideInInspector] public AnimatorHandler animatorHandler; + /// <summary> + /// 角色的 Rigidbody 组件引用(用于物理驱动移动)。 + /// 使用 new 关键字隐藏父类 Rigidbody 字段以避免混淆。 + /// </summary> public new Rigidbody rigidbody; - public GameObject normalCamera; //引用Camera - - [Header("Stats")] - [SerializeField] private float movementSpeed = 5; - [SerializeField] private float rotationSpeed = 10; + /// <summary> + /// 常规第三人称摄像机对象的引用(用于旋转跟随等逻辑)。 + /// </summary> + public GameObject normalCamera; + + // ============================================================ + // 私有字段 + // ============================================================ + private Transform _cameraObject; // 主摄像机的 Transform 缓存 + private InputHandler _inputHandler; // 输入处理器引用 + private Vector3 _moveDirection; // 计算出的移动方向向量 + private Vector3 _normalVector; // 地面法线向量(用于投影移动方向到地面) + private Vector3 _targetPosition; // 目标位置(当前未使用,保留备用) + + // ============================================================ + // 参数配置 + // ============================================================ + [Header("Stats")] + [SerializeField] private float movementSpeed = 5; // 移动速度(单位:米/秒) + [SerializeField] private float rotationSpeed = 10; // 旋转速度(单位:度/秒,实际用于 Slerp 插值) + + // ============================================================ + // 初始化 + // ============================================================ private void Start() { + // 获取并缓存 Rigidbody 组件 rigidbody = GetComponent<Rigidbody>(); + + // 获取并缓存输入处理器 _inputHandler = GetComponent<InputHandler>(); + + // 在子物体中查找 AnimatorHandler 组件并缓存 animatorHandler = GetComponentInChildren<AnimatorHandler>(); + + // 缓存主摄像机的 Transform _cameraObject = Camera.main.transform; + + // 缓存当前物体的 Transform myTransform = transform; + + // 初始化 AnimatorHandler(例如获取 Animator 组件引用等) animatorHandler.Initialize(); } + // ============================================================ + // 每帧更新(使用 Update 处理移动逻辑,因为需要与输入同步) + // ============================================================ private void Update() { UpdateCharacterMovement(); } + // ============================================================ + // 固定更新(当前未使用,但保留以备未来物理相关逻辑) + // ============================================================ private void FixedUpdate() { - + // 当前未在此处处理逻辑 + // 若需要基于物理的移动,可将 rigidbody.velocity 赋值移到这里 } + // ============================================================ + // 角色移动更新(核心逻辑) + // ============================================================ private void UpdateCharacterMovement() { - float delta = Time.deltaTime; + float delta = Time.deltaTime; // 获取帧时间 + + // 处理输入(读取水平/垂直输入值) _inputHandler.TickInput(delta); + // ---------------------------------------------------------- + // 1. 计算移动方向(基于摄像机朝向) + // ---------------------------------------------------------- + // 前方向量 = 摄像机正方向 * 垂直输入(W/S) _moveDirection = _cameraObject.forward * _inputHandler.vertical; + // 侧方向量 = 摄像机右方向 * 水平输入(A/D) _moveDirection += _cameraObject.right * _inputHandler.horizontal; + // 归一化,确保对角线移动时速度不叠加(保持长度 1) _moveDirection.Normalize(); + // 将 y 分量置 0,确保移动只在水平面上 _moveDirection.y = 0; + // ---------------------------------------------------------- + // 2. 应用移动速度 + // ---------------------------------------------------------- float speed = movementSpeed; - _moveDirection *= speed; - + _moveDirection *= speed; // 现在 _moveDirection 是速度向量(单位:米/秒) + + // ---------------------------------------------------------- + // 3. 混合根运动与程序化移动 + // ---------------------------------------------------------- + // 根据 rootMotionBlending 在根运动位移和程序化速度之间做线性插值 var baseVelocity = Vector3.Lerp(rootMotion, _moveDirection, rootMotionBlending); + + // 将速度向量投影到地面法线平面上(防止角色飞起或陷入地面) Vector3 projectedVelocity = Vector3.ProjectOnPlane(baseVelocity, _normalVector); + + // 设置 Rigidbody 速度(物理驱动移动) rigidbody.velocity = projectedVelocity; - - animatorHandler.UpdateAnimatorValues(_inputHandler.moveAmount,0); + // ---------------------------------------------------------- + // 4. 更新动画参数 + // ---------------------------------------------------------- + // 将玩家的移动量(0~1)传递给 Animator,用于混合行走/奔跑动画 + animatorHandler.UpdateAnimatorValues(_inputHandler.moveAmount, 0); + + // ---------------------------------------------------------- + // 5. 处理旋转(仅在允许旋转时执行) + // ---------------------------------------------------------- if (animatorHandler.canRotate) { HandleRotation(delta); } } + // ============================================================ + // 移动与旋转相关方法 + // ============================================================ #region Movement - private Vector3 _normalVector; - private Vector3 _targetPosition; - + /// <summary> + /// 处理角色旋转逻辑。 + /// 根据输入方向和摄像机朝向,平滑旋转角色面向移动方向。 + /// </summary> + /// <param name="delta">帧时间(秒)</param> private void HandleRotation(float delta) { - Vector3 targetDir = Vector3.zero; + Vector3 targetDir = Vector3.zero; // 目标朝向向量 + // 注意:当前未使用 moveOverride,保留备用 float moveOverride = _inputHandler.moveAmount; + // ---------------------------------------------------------- + // 1. 根据输入计算目标朝向 + // ---------------------------------------------------------- + // 目标朝向 = 摄像机正方向 * 垂直输入 + 摄像机右方向 * 水平输入 targetDir = _cameraObject.forward * _inputHandler.vertical; targetDir += _cameraObject.right * _inputHandler.horizontal; + // 归一化并置平 Y 轴 targetDir.Normalize(); targetDir.y = 0; + // 如果没有输入(目标方向为零向量),则保持当前面向不变 if (targetDir == Vector3.zero) { targetDir = myTransform.forward; } - float rs = rotationSpeed; - Quaternion tr = Quaternion.LookRotation(targetDir); + // ---------------------------------------------------------- + // 2. 通过 Slerp 平滑旋转至目标方向 + // ---------------------------------------------------------- + float rs = rotationSpeed; // 旋转速度 + Quaternion tr = Quaternion.LookRotation(targetDir); // 目标旋转四元数 + // 使用球形插值(Slerp)实现平滑旋转 Quaternion targetRotation = Quaternion.Slerp(myTransform.rotation, tr, rs * delta); + // 应用旋转 myTransform.rotation = targetRotation; } - #endregion } } - |
