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} ");
}
}
}