using System.Threading.Tasks; using UnityEngine; using asap.core; namespace UI.PartnerGather.Mining { /// /// 事件合作伙伴挖矿角色控制器 /// 控制角色的移动、动画播放、挖矿行为等 /// /// 建议挂载在:角色模型的根对象上 /// 需要组件:CharacterController(必须) /// /// 场景结构建议: /// Character (挂载此脚本 + CharacterController) /// ├── Model (角色模型) /// │ └── Animator (动画控制器) /// └── Body (可选的身体Transform,用于旋转控制) /// [RequireComponent(typeof(CharacterController))] public class EventPartnerMiningCharacterController : MonoBehaviour { private static readonly int BasicMove = Animator.StringToHash("_basicMove"); private static readonly int BackToIdle = Animator.StringToHash("_backToIdle"); private static readonly int ToBasic = Animator.StringToHash("_toBasic"); private static readonly int BasicGathering = Animator.StringToHash("_basicGathering"); [Header("组件引用")] public Animator animator; public Transform body; public CharacterController characterController; [Header("移动配置")] public float moveSpeed = 2f; public float idleThreshold = 0.05f; public float rotationSpeed = 5f; [Header("模型配置")] [Tooltip("是否平滑旋转")] public bool smoothRotation = true; [Tooltip("旋转动画持续时间")] [Range(0.1f, 1f)] public float rotationDuration = 0.2f; [Header("调试配置")] public bool showDebugInfo = true; public bool showMovementPath = true; public Color targetPointColor = Color.red; public Color pathColor = Color.yellow; public Color directionColor = Color.green; [Header("动画参数")] public string runAnimParam = "run"; public string mineAnimParam = "mine"; public string idleAnimParam = "idle"; // 调试信息 private Vector3 _debugTargetPosition; private Vector3 _debugStartPosition; private bool _isMoving = false; private Vector3 _debugMoveDirection; private void Awake() { if (characterController == null) characterController = GetComponent(); if (body == null) body = transform; } void OnDrawGizmos() { if (body != null && showDebugInfo) { // 绘制角色位置和朝向 Gizmos.color = Color.green; Gizmos.DrawWireSphere(body.position, 0.5f); // 绘制前方向量(蓝色) Gizmos.color = Color.blue; Gizmos.DrawRay(body.position, body.forward * 2f); // 绘制右方向量(红色) Gizmos.color = Color.red; Gizmos.DrawRay(body.position, body.right * 1.5f); // 绘制上方向量(黄色,较短) Gizmos.color = Color.yellow; Gizmos.DrawRay(body.position, body.up * 1f); // === 新增:移动调试可视化 === if (_isMoving) { // 绘制目标点 Gizmos.color = targetPointColor; Gizmos.DrawWireSphere(_debugTargetPosition, 0.8f); Gizmos.DrawCube(_debugTargetPosition + Vector3.up * 0.5f, Vector3.one * 0.3f); // 绘制起始点 Gizmos.color = Color.cyan; Gizmos.DrawWireCube(_debugStartPosition, Vector3.one * 0.4f); if (showMovementPath) { // 绘制移动路径线 Gizmos.color = pathColor; Gizmos.DrawLine(_debugStartPosition, _debugTargetPosition); // 绘制当前位置到目标的连线 Gizmos.color = Color.white; Gizmos.DrawLine(body.position, _debugTargetPosition); // 绘制移动方向箭头 Vector3 directionArrow = _debugMoveDirection * 3f; Gizmos.color = directionColor; Gizmos.DrawRay(body.position + Vector3.up * 0.2f, directionArrow); // 绘制箭头头部 Vector3 arrowEnd = body.position + Vector3.up * 0.2f + directionArrow; Vector3 arrowSide1 = Quaternion.Euler(0, 30, 0) * (-directionArrow.normalized * 0.5f); Vector3 arrowSide2 = Quaternion.Euler(0, -30, 0) * (-directionArrow.normalized * 0.5f); Gizmos.DrawLine(arrowEnd, arrowEnd + arrowSide1); Gizmos.DrawLine(arrowEnd, arrowEnd + arrowSide2); } } // 显示四个主要方向(运行时) if (Application.isPlaying) { Gizmos.color = Color.cyan; // 显示四个主要方向 Gizmos.DrawRay(body.position + Vector3.up * 0.1f, Vector3.forward * 0.8f); // 前 Gizmos.DrawRay(body.position + Vector3.up * 0.1f, Vector3.back * 0.8f); // 后 Gizmos.DrawRay(body.position + Vector3.up * 0.1f, Vector3.left * 0.8f); // 左 Gizmos.DrawRay(body.position + Vector3.up * 0.1f, Vector3.right * 0.8f); // 右 } // 显示默认朝向(编辑器中) if (!Application.isPlaying) { Gizmos.color = Color.magenta; // Unity默认前方向量 Gizmos.DrawRay(body.position, Vector3.forward * 1.5f); } } #if UNITY_EDITOR // 在编辑器中显示文字信息 if (body != null && showDebugInfo) { UnityEditor.Handles.color = Color.white; string info = $"Current Rotation: {body.rotation.eulerAngles}\n"; info += $"Forward: {body.forward.ToString("F2")}\n"; info += $"Right: {body.right.ToString("F2")}"; if (_isMoving) { info += $"\n--- 移动调试 ---"; info += $"\n起点: {_debugStartPosition.ToString("F1")}"; info += $"\n目标: {_debugTargetPosition.ToString("F1")}"; info += $"\n当前: {body.position.ToString("F1")}"; info += $"\n方向: {_debugMoveDirection.ToString("F2")}"; float distance = Vector3.Distance(body.position, _debugTargetPosition); info += $"\n剩余距离: {distance:F2}"; } UnityEditor.Handles.Label(body.position + Vector3.up * 2f, info); } #endif } /// /// 移动到指定的3D位置 /// /// 目标位置 /// 移动速度,0表示使用默认速度 public async Task MoveToPosition(Vector3 targetPosition, float speed = 0f) { if (speed <= 0f) speed = moveSpeed; // 设置调试信息 _debugStartPosition = body.position; _debugTargetPosition = targetPosition; _isMoving = true; Vector3 startPos = body.position; Vector3 direction = (targetPosition - startPos); // 忽略Y轴方向,只考虑水平面移动 direction.y = 0f; _debugMoveDirection = direction.normalized; // float bodyForward = Mathf.Atan2(body.forward.x, body.forward.z) * Mathf.Rad2Deg; // 检查水平移动距离是否足够大 if (direction.magnitude > 0.01f) { Log($"开始移动: 从 {startPos} 到 {targetPosition}, 方向: {_debugMoveDirection}"); // 设置角色朝向目标方向 await SetCharacterDirectionVector(direction); } else { Log($"目标位置太近,跳过移动: 距离 {direction.magnitude:F3}"); _isMoving = false; return; } // return; // 开始移动动画 SetAnimationState("moving"); //TODO:LF 开发暂时停止,优先制作六边形场景,目前人物移动的配置还有问题,3D 模型上面的UI的结构要调整 // 移动到目标位置 var bodyStandPosition = body.position; bodyStandPosition.y = 0; while (Vector3.Distance(bodyStandPosition, targetPosition) > idleThreshold) { var moveDirection = (targetPosition - bodyStandPosition).normalized; moveDirection.y = 0f; _debugMoveDirection = moveDirection; // 更新当前移动方向 Vector3 moveVector = moveDirection * speed * Time.deltaTime; if (characterController && characterController.enabled) { // moveVector.y = -9.81f * Time.deltaTime; characterController.Move(moveVector); } else { Vector3 newPos = body.position + moveVector; newPos.y = body.position.y; body.position = newPos; } bodyStandPosition = body.position; bodyStandPosition.y = 0; await Awaiters.NextFrame; } // SetAnimationState(); // 精确定位 // animator.SetTrigger(BackToIdle); // animator.SetTrigger(gam); // SetAnimationState("gathering"); Vector3 finalPos = targetPosition; finalPos.y = body.position.y; body.position = finalPos; _ = SetCharacterDirectionVector(Vector3.right); Log($"移动完成: 到达 {body.position}"); // 停止移动动画 // SetAnimationState("gathering"); // 清除调试信息 _isMoving = false; } /// /// 设置角色朝向方向(基于方向向量) /// /// 目标方向向量 private async Task SetCharacterDirectionVector(Vector3 direction) { direction.y = 0f; // 检查方向向量是否有效(在标准化之前) if (direction.magnitude < 0.01f) return; direction.Normalize(); // 标准Unity旋转计算 float targetYRotation = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg; Quaternion targetRotation = Quaternion.Euler(0f, targetYRotation - 90, 0f); if (smoothRotation) { Quaternion startRotation = body.rotation; float rotationTime = 0f; while (rotationTime < rotationDuration) { rotationTime += Time.deltaTime; float t = rotationTime / rotationDuration; body.rotation = Quaternion.Slerp(startRotation, targetRotation, t); await Awaiters.NextFrame; } } body.rotation = targetRotation; Log($"朝向设置: 目标方向{direction} -> Y旋转{targetYRotation:F1}° -> 最终旋转{targetRotation.eulerAngles}"); } public async Task PlayMining( float duration) { SetAnimationState("gathering"); await Awaiters.Seconds(duration); animator.SetTrigger(BackToIdle); } public void SetIdle() { SetAnimationState("idle"); } private void SetAnimationState(string state) { if (animator == null) return; if (state == "moving") { animator.SetTrigger(ToBasic); } if (state == "gathering") { animator.SetTrigger(BasicGathering); } if (state == "idle") { animator.SetTrigger(BackToIdle); } // 重置所有动画状态 // animator.SetBool(runAnimParam, false); // animator.SetBool(idleAnimParam, false); // // switch (state.ToLower()) // { // case "moving": // animator.SetBool(runAnimParam, true); // break; // // case "mining": // animator.SetTrigger(mineAnimParam); // break; // // case "idle": // default: // animator.SetBool(idleAnimParam, true); // break; // } } // 获取当前是否在移动 public bool IsMoving() { return animator != null && animator.GetBool(runAnimParam); } // 强制停止所有动作 public void StopAllActions() { SetAnimationState("idle"); } /// /// 立即设置角色朝向(基于方向向量,不带动画) /// /// 目标方向向量 public void SetDirectionVectorImmediate(Vector3 direction) { direction.y = 0f; // 检查方向向量是否有效(在标准化之前) if (direction.magnitude < 0.01f) return; direction.Normalize(); // 标准Unity旋转计算 float targetYRotation = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg; body.rotation = Quaternion.Euler(0f, targetYRotation, 0f); Log($"立即朝向: 目标方向{direction} -> Y旋转{targetYRotation:F1}°"); } /// /// 立即朝向目标位置(不带动画) /// /// 目标位置 public void LookAtPositionImmediate(Vector3 targetPosition) { Vector3 direction = (targetPosition - body.position).normalized; SetDirectionVectorImmediate(direction); } /// /// 重置到默认朝向 /// public void ResetToDefaultRotation() { body.rotation = Quaternion.identity; } /// /// 获取当前面向的方向 /// /// 1为右,-1为左,0为其他方向 public float GetCurrentDirection() { Vector3 forward = body.forward; float dot = Vector3.Dot(forward, Vector3.right); if (dot > 0.5f) return 1f; if (dot < -0.5f) return -1f; return 0f; } #if UNITY_EDITOR /// /// 编辑器辅助:重置到默认朝向 /// [UnityEngine.ContextMenu("重置到默认朝向")] private void ResetToDefault() { ResetToDefaultRotation(); } /// /// 编辑器辅助:测试朝向前 /// [UnityEngine.ContextMenu("测试朝向前")] private void TestFaceForward() { SetDirectionVectorImmediate(Vector3.forward); } /// /// 编辑器辅助:测试移动到指定位置 /// [UnityEngine.ContextMenu("测试移动(右前方)")] private async void TestMoveToPosition() { Vector3 testTarget = body.position + new Vector3(5f, 0f, 5f); Debug.Log($"测试移动到位置: {testTarget}"); await MoveToPosition(testTarget, 3f); } /// /// 编辑器辅助:测试移动(向右) /// [UnityEngine.ContextMenu("测试移动(向右)")] private async void TestMoveRight() { Vector3 testTarget = body.position + new Vector3(3f, 0f, 0f); Debug.Log($"测试向右移动到: {testTarget}"); await MoveToPosition(testTarget, 2f); } /// /// 编辑器辅助:测试移动(向前) /// [UnityEngine.ContextMenu("测试移动(向前)")] private async void TestMoveForward() { Vector3 testTarget = body.position + new Vector3(0f, 0f, 3f); Debug.Log($"测试向前移动到: {testTarget}"); await MoveToPosition(testTarget, 2f); } /// /// 编辑器辅助:显示当前朝向信息 /// [UnityEngine.ContextMenu("显示当前朝向")] private void ShowCurrentDirection() { Debug.Log($"=== 角色朝向信息 ==="); Debug.Log($"当前旋转: {body.rotation.eulerAngles}"); Debug.Log($"Forward: {body.forward.ToString("F3")}"); Debug.Log($"Right: {body.right.ToString("F3")}"); Debug.Log($"Up: {body.up.ToString("F3")}"); } /// /// 编辑器辅助:验证旋转逻辑 /// [UnityEngine.ContextMenu("验证旋转逻辑")] private void ValidateRotationLogic() { Debug.Log($"=== 标准Unity旋转逻辑验证 ==="); // 测试四个主要方向 Vector3[] testDirections = { Vector3.right, // 向右 (1, 0, 0) Vector3.left, // 向左 (-1, 0, 0) Vector3.forward, // 向前 (0, 0, 1) Vector3.back // 向后 (0, 0, -1) }; string[] directionNames = { "右", "左", "前", "后" }; for (int i = 0; i < testDirections.Length; i++) { Vector3 direction = testDirections[i]; float expectedYRotation = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg; Debug.Log($"方向{directionNames[i]}: " + $"输入向量{direction} -> " + $"Y旋转{expectedYRotation:F1}°"); } } #endif private static void Log(object t) { Debug.Log($"EventPartnerMiningCharacterController-> {t} "); } } }