WX-Game1/Assets/Scripts/CharacterController.cs

783 lines
33 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems; // 添加AI系统的引用
public class CharacterController : MonoBehaviour
{
// 移动状态枚举
public enum MoveState
{
Idle, // 空闲状态
Moving, // 移动中
Arrived, // 已到达
Stuck // 卡住状态
}
public float moveSpeed = 5f; // 角色移动速度
public Camera mainCamera; // 主相机
public float cameraFollowSpeed = 5f; // 相机跟随速度
public float rotationSpeed = 3f; // 角色转向速度
private Vector3 targetPosition; // 目标位置
private bool isMoving = false; // 是否正在移动
private Vector3 startPosition; // 移动开始时的位置
private int moveStartFrame; // 移动开始的帧数
private float moveStartTime; // 移动开始的时间
private Quaternion startRotation; // 移动开始时的朝向
private bool shouldSmoothRotation = true; // 是否启用平滑转向
private float originalYRotation; // 保存原始的Y轴朝向
// 添加NavMeshAgent组件引用
private NavMeshAgent agent; // 导航网格代理组件
// 添加Animation组件引用
public Animation characterAnimation; // 角色动画组件
// 小球预制体引用
public GameObject ballPrefab; // 小球预制体
// 点击拦截的图层命中这些Layer将不触发点击移动
public LayerMask blockedClickLayers;
// 移动状态管理
private MoveState currentMoveState = MoveState.Idle;
public MoveState CurrentMoveState => currentMoveState; // 公共属性,供外部访问
// 相机跟随相关
private Vector3 initialCameraOffset; // 保存相机相对于角色的初始位置偏移
void Start()
{
// 获取NavMeshAgent组件
agent = GetComponent<NavMeshAgent>();
if (agent == null)
{
// 如果没有NavMeshAgent组件自动添加一个
agent = gameObject.AddComponent<NavMeshAgent>();
}
// 检查场景是否有NavMesh
if (!NavMesh.SamplePosition(transform.position, out NavMeshHit hit, 1.0f, NavMesh.AllAreas))
{
// Debug.LogWarning("警告角色当前位置不在NavMesh上请确保场景已烘焙导航网格");
}
// 配置NavMeshAgent参数
// agent.speed = moveSpeed; // 设置移动速度
// agent.angularSpeed = 30f; // 设置旋转速度,让角色转向更加平滑自然
// agent.acceleration = 5f; // 设置加速度,让移动更平滑
agent.stoppingDistance = 0.1f; // 设置停止距离,减少精确调整导致的绕圈
//
// // 优化路径计算质量,减少绕行
// agent.obstacleAvoidanceType = ObstacleAvoidanceType.HighQualityObstacleAvoidance;
// agent.radius = 0.5f; // 设置角色半径,影响路径计算
// agent.height = 2.0f; // 设置角色高度
//
// // 优化朝向行为,让角色先移动再调整朝向
agent.updateRotation = false; // 暂时禁用NavMeshAgent的自动旋转
// agent.updateUpAxis = false; // 禁用上轴更新
// 保存原始的Y轴朝向用于朝向保护
originalYRotation = transform.rotation.eulerAngles.y;
// 确保朝向值在合理范围内
if (originalYRotation < 0)
originalYRotation += 360f;
// 获取Animation组件
// characterAnimation = GetComponent<Animation>();
// if (characterAnimation == null)
// {
// // 如果没有Animation组件自动添加一个
// characterAnimation = gameObject.AddComponent<Animation>();
// Debug.Log("已自动添加Animation组件到角色上");
// }
// 保存相机相对于角色的初始位置偏移,用于后续跟随
if (mainCamera != null)
{
initialCameraOffset = mainCamera.transform.position - transform.position;
}
else
{
}
// 检查必要的动画片段是否存在
CheckRequiredAnimations();
}
/// <summary>
/// 检查必要的动画片段是否存在
/// </summary>
private void CheckRequiredAnimations()
{
if (characterAnimation != null)
{
bool hasRunning = characterAnimation.GetClip("Running") != null;
bool hasStand = characterAnimation.GetClip("Stand") != null;
if (!hasRunning)
{
}
if (!hasStand)
{
}
if (hasRunning && hasStand)
{
}
}
}
// 公共方法:手动设置移动目标
public void SetMoveTarget(Vector3 target)
{
if (agent != null && agent.isOnNavMesh)
{
// 检查目标位置是否过近,只有极近距离才不触发移动
float distanceToTarget = Vector3.Distance(transform.position, target);
if (distanceToTarget <= 0.3f) // 增加最小移动距离到0.3米
{
Debug.Log($"手动设置目标位置过近 ({distanceToTarget:F2}m),不触发移动");
return;
}
else if (distanceToTarget < 0.5f)
{
Debug.Log($"手动设置目标位置较近 ({distanceToTarget:F2}m),但距离足够,允许移动");
}
targetPosition = target;
bool pathSet = agent.SetDestination(target);
if (pathSet)
{
// 手动设置目标时也立即转向,不使用平滑转向
shouldSmoothRotation = false;
SetImmediateRotation(target);
// 检查路径是否合理,避免绕行
if (agent.path.corners.Length > 2)
{
Debug.Log($"检测到复杂路径,路径点数: {agent.path.corners.Length},尝试优化");
// 如果路径过于复杂,尝试直接移动
// agent.ResetPath();
Vector3 directTarget = Vector3.Lerp(transform.position, target, 0.8f);
agent.SetDestination(directTarget);
}
isMoving = true;
currentMoveState = MoveState.Moving;
startPosition = transform.position; // 记录移动开始位置
moveStartFrame = Time.frameCount; // 记录移动开始帧数
moveStartTime = Time.time; // 记录移动开始时间
startRotation = transform.rotation; // 记录移动开始时的朝向
// shouldSmoothRotation 已在上面设置为 false手动设置目标时立即转向
// 播放跑步动画
if (characterAnimation != null)
{
characterAnimation.Play("Running");
Debug.Log("开始播放跑步动画 Running");
}
Debug.Log($"手动设置移动目标: {target},直接距离: {distanceToTarget:F2}m开始位置: {startPosition},已立即转向目标方向");
}
else
{
Debug.LogWarning($"无法设置移动目标: {target}");
}
}
}
// 公共方法:停止移动
public void StopMoving()
{
if (agent != null)
{
agent.ResetPath();
isMoving = false;
currentMoveState = MoveState.Idle;
shouldSmoothRotation = false; // 停止平滑转向
// 停止跑步动画
if (characterAnimation != null)
{
characterAnimation.Stop(); // 停止所有动画
Debug.Log("手动停止移动,停止所有动画");
// 播放Stand动画
if (characterAnimation.GetClip("Stand") != null)
{
characterAnimation.Play("Stand");
Debug.Log("开始播放Stand动画");
}
}
// 强制恢复正确的朝向,避免角色面朝地下
RestoreCorrectRotation();
Debug.Log("角色停止移动,朝向已恢复,动画已停止");
}
}
// 公共方法:获取当前移动状态
public MoveState GetMoveState()
{
return currentMoveState;
}
// 公共方法:检查是否正在移动
public bool IsMoving()
{
return isMoving;
}
// 恢复正确的朝向,避免角色面朝地下
private void RestoreCorrectRotation()
{
Vector3 currentEuler = transform.rotation.eulerAngles;
// 只恢复X轴朝向为0水平保持当前的Y轴朝向允许转向
Vector3 correctedEuler = new Vector3(0, currentEuler.y, 0);
Quaternion correctedRotation = Quaternion.Euler(correctedEuler);
transform.rotation = correctedRotation;
Debug.Log($"已恢复水平朝向X轴: 0°, Y轴: {currentEuler.y:F1}°, 允许角色转向");
}
void Update()
{
if (EventSystem.current.IsPointerOverGameObject())
return;
if (Input.touchCount > 0)
{
// 获取第一个触摸点
Touch touch = Input.GetTouch(0);
// 检查触摸阶段是否为触摸开始
if (touch.phase == TouchPhase.Began)
{
if (EventSystem.current.IsPointerOverGameObject())
{
Debug.Log($"检测到触摸空白处!触摸位置: {touch.position}, 触摸ID: {touch.fingerId}");
return;
}
// 输出触摸调试信息
}
}
HandleInput();
MoveCharacter();
FollowCamera();
}
// 处理输入,检测点击位置
void HandleInput()
{
// 如果角色正在移动,不处理新的输入
if (isMoving)
{
return;
}
// 如果角色状态不是Idle重置为Idle状态
if (currentMoveState != MoveState.Idle)
{
currentMoveState = MoveState.Idle;
Debug.Log("重置角色状态为Idle准备接受新的移动指令");
}
if (Input.GetMouseButtonDown(0)) // 如果鼠标点击(或触摸屏上的点击)
{
Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition); // 将鼠标位置转换为射线
RaycastHit hit;
if (Physics.Raycast(ray, out hit)) // 检测射线是否与地面碰撞
{
// 如果点击到的是需要拦截的Layer则不触发移动
if (hit.collider != null)
{
int hitLayer = hit.collider.gameObject.layer;
if ((blockedClickLayers.value & (1 << hitLayer)) != 0)
{
Debug.Log($"点击命中在拦截图层内的物体:{hit.collider.name} (Layer: {hitLayer}),本次点击不触发移动");
return;
}
}
targetPosition = hit.point; // 获取点击的世界坐标
// 在点击位置创建小球
CreateBallAtPosition(targetPosition);
// 检查目标位置是否过近,只有极近距离才不触发移动
float distanceToTarget = Vector3.Distance(transform.position, targetPosition);
if (distanceToTarget <= 0.3f) // 增加最小移动距离到0.3米
{
Debug.Log($"目标位置过近 ({distanceToTarget:F2}m),不触发移动");
return;
}
else if (distanceToTarget < 0.5f)
{
Debug.Log($"目标位置较近 ({distanceToTarget:F2}m),但距离足够,允许移动");
}
// 使用NavMeshAgent设置目标位置
if (agent != null && agent.isOnNavMesh)
{
// 设置导航目标
bool pathSet = agent.SetDestination(targetPosition);
if (pathSet)
{
// 点击时立即转向目标方向,不使用平滑转向
shouldSmoothRotation = false;
SetImmediateRotation(targetPosition);
// 检查路径是否合理,避免绕行
if (agent.path.corners.Length > 2)
{
Debug.Log($"检测到复杂路径,路径点数: {agent.path.corners.Length},尝试优化");
// 如果路径过于复杂,尝试直接移动
//agent.ResetPath();
Vector3 directTarget = Vector3.Lerp(transform.position, targetPosition, 0.8f);
agent.SetDestination(directTarget);
}
isMoving = true; // 设置为正在移动
currentMoveState = MoveState.Moving; // 更新移动状态
startPosition = transform.position; // 记录移动开始位置
moveStartFrame = Time.frameCount; // 记录移动开始帧数
moveStartTime = Time.time; // 记录移动开始时间
startRotation = transform.rotation; // 记录移动开始时的朝向
// shouldSmoothRotation 已在上面设置为 false点击时立即转向
// 播放跑步动画
if (characterAnimation != null)
{
characterAnimation.Play("Running");
Debug.Log("开始播放跑步动画 Running");
}
// Debug.Log($"角色开始移动到目标位置: {targetPosition},直接距离: {distanceToTarget:F2}m开始位置: {startPosition}已立即转向目标方向NavMeshAgent状态: {agent.isOnNavMesh}");
}
else
{
currentMoveState = MoveState.Stuck; // 更新为卡住状态
Debug.LogWarning("无法设置导航路径,目标位置可能不在导航网格上");
}
}
else
{
currentMoveState = MoveState.Stuck; // 更新为卡住状态
Debug.LogWarning("NavMeshAgent不可用或不在导航网格上");
}
}
}
}
// 移动角色
void MoveCharacter()
{
if (isMoving && agent != null)
{
// 计算直接距离到目标
float directDistanceToTarget = Vector3.Distance(transform.position, targetPosition);
// 简化的到达检测逻辑 - 只基于直接距离判断
float actualMovedDistance = Vector3.Distance(transform.position, startPosition);
// 检查是否真正到达目标位置 - 基于直接距离
bool hasReachedTarget = false;
// 直接距离检查 - 当直接距离很小时认为已到达
if (directDistanceToTarget <= 0.1f)
{
hasReachedTarget = true;
Debug.Log($"已到达目标位置,直接距离: {directDistanceToTarget:F2}m实际移动: {actualMovedDistance:F2}m");
}
// 备用到达检测当NavMeshAgent报告已到达时
else if (agent.hasPath && !float.IsInfinity(agent.remainingDistance) && agent.remainingDistance <= agent.stoppingDistance)
{
hasReachedTarget = true;
Debug.Log($"NavMeshAgent报告已到达剩余距离: {agent.remainingDistance:F2}m直接距离: {directDistanceToTarget:F2}m");
}
// 特殊处理当直接距离很小且速度为0时认为已到达
else if (directDistanceToTarget <= 0.3f && agent.velocity.magnitude < 0.01f)
{
hasReachedTarget = true;
Debug.Log($"特殊到达检测:直接距离: {directDistanceToTarget:F2}m速度: {agent.velocity.magnitude:F2}m/s认为已到达");
}
if (hasReachedTarget)
{
// 角色已到达目标位置,停止移动
isMoving = false;
agent.ResetPath(); // 重置导航路径
currentMoveState = MoveState.Arrived; // 更新为已到达状态
shouldSmoothRotation = false; // 停止平滑转向
// 强制停止所有动画,避免动画状态混乱
if (characterAnimation != null)
{
characterAnimation.Stop(); // 停止所有动画
// Debug.Log("已到达目的地,停止所有动画");
// 播放Stand动画
if (characterAnimation.GetClip("Stand") != null)
{
characterAnimation.Play("Stand");
// Debug.Log("开始播放Stand动画");
}
else
{
//Debug.LogWarning("未找到Stand动画片段请确保动画组件中有名为'Stand'的动画");
}
}
// 强制恢复正确的朝向,避免角色面朝地下
RestoreCorrectRotation();
//Debug.Log($"角色已到达目标位置,停止移动,直接距离: {directDistanceToTarget:F2}m实际移动: {actualMovedDistance:F2}m");
// 重置移动相关变量,确保下次移动正常
targetPosition = Vector3.zero;
startPosition = Vector3.zero;
moveStartFrame = 0;
moveStartTime = 0f;
startRotation = Quaternion.identity;
}
// 改进的卡住检测:当速度很低且移动距离很小时,认为角色卡住
// 添加启动缓冲给角色至少3秒时间开始移动
else if (agent.velocity.magnitude < 0.01f && actualMovedDistance < 0.1f && directDistanceToTarget > 2.0f && Time.time - moveStartTime > 3.0f)
{
// 角色可能卡住了,强制停止移动
isMoving = false;
agent.ResetPath();
currentMoveState = MoveState.Stuck; // 更新为卡住状态
shouldSmoothRotation = false; // 停止平滑转向
// 强制停止所有动画
if (characterAnimation != null)
{
characterAnimation.Stop(); // 停止所有动画
Debug.Log("角色卡住,强制停止移动和动画");
// 播放Stand动画
if (characterAnimation.GetClip("Stand") != null)
{
characterAnimation.Play("Stand");
Debug.Log("开始播放Stand动画");
}
}
// 强制恢复正确的朝向
RestoreCorrectRotation();
Debug.LogWarning($"角色卡住,强制停止移动,直接距离: {directDistanceToTarget:F2}m实际移动: {actualMovedDistance:F2}m速度: {agent.velocity.magnitude:F2}m/s路径状态: {agent.pathStatus}");
}
else if (agent.pathStatus == NavMeshPathStatus.PathInvalid)
{
// 路径无效,停止移动
isMoving = false;
agent.ResetPath();
currentMoveState = MoveState.Stuck; // 更新为卡住状态
shouldSmoothRotation = false; // 停止平滑转向
// 强制停止所有动画,避免动画状态混乱
if (characterAnimation != null)
{
characterAnimation.Stop(); // 停止所有动画
Debug.Log("路径无效,停止所有动画");
// 播放Stand动画
if (characterAnimation.GetClip("Stand") != null)
{
characterAnimation.Play("Stand");
Debug.Log("开始播放Stand动画");
}
}
// 强制恢复正确的朝向,避免角色面朝地下
RestoreCorrectRotation();
Debug.LogWarning("导航路径无效,停止移动");
}
// 处理PathPartial状态当路径不完整时如果距离很近就认为已到达
else if (agent.pathStatus == NavMeshPathStatus.PathPartial && directDistanceToTarget <= 0.2f)
{
// 检查角色是否仍在移动,如果速度很低则停止
if (agent.velocity.magnitude < 0.1f)
{
// 路径不完整但距离很近且角色已停止移动,认为已到达
isMoving = false;
agent.ResetPath();
currentMoveState = MoveState.Arrived; // 更新为已到达状态
shouldSmoothRotation = false; // 停止平滑转向
// 强制停止所有动画,避免动画状态混乱
if (characterAnimation != null)
{
characterAnimation.Stop(); // 停止所有动画
Debug.Log("路径不完整但已接近目标,停止所有动画");
// 播放Stand动画
if (characterAnimation.GetClip("Stand") != null)
{
characterAnimation.Play("Stand");
Debug.Log("开始播放Stand动画");
}
}
// 强制恢复正确的朝向,避免角色面朝地下
RestoreCorrectRotation();
Debug.Log($"路径不完整但已接近目标,停止移动,直接距离: {directDistanceToTarget:F2}m");
// 重置移动相关变量,确保下次移动正常
targetPosition = Vector3.zero;
startPosition = Vector3.zero;
moveStartFrame = 0;
moveStartTime = 0f;
startRotation = Quaternion.identity;
}
else
{
// 角色仍在移动,继续移动直到速度降低
Debug.Log($"路径不完整但角色仍在移动,继续移动,直接距离: {directDistanceToTarget:F2}m速度: {agent.velocity.magnitude:F2}m/s");
// 如果距离很近但路径不完整,尝试直接移动到目标(最终冲刺)
if (directDistanceToTarget <= 0.3f && agent.velocity.magnitude < 0.5f)
{
// 使用直接移动来弥补最后的距离差
Vector3 directMove = Vector3.MoveTowards(transform.position, targetPosition, 0.1f * Time.deltaTime);
transform.position = directMove;
Debug.Log($"执行最终冲刺,直接移动到目标,剩余距离: {Vector3.Distance(transform.position, targetPosition):F2}m");
}
}
}
else
{
// 正常移动中,确保角色真正在移动
currentMoveState = MoveState.Moving;
}
// 输出移动状态信息(调试用)- 只在状态变化时输出
if (isMoving)
{
float distanceFromStart = Vector3.Distance(transform.position, startPosition);
// 移动中的朝向处理 - 始终面向前进方向(转弯时也要朝向转弯方向)
// 优先使用 NavMeshAgent 的 steeringTarget 来确定下一转向目标
Vector3 lookDirection = Vector3.zero;
if (agent.hasPath)
{
lookDirection = agent.steeringTarget - transform.position; // 指向下一个转向点
}
// 如果steeringTarget方向过小则回退到期望速度方向
if (lookDirection.sqrMagnitude < 0.0001f)
{
lookDirection = agent.desiredVelocity; // 使用期望速度方向
}
// 再次回退:若仍旧过小,使用实际速度方向
if (lookDirection.sqrMagnitude < 0.0001f)
{
lookDirection = agent.velocity; // 使用实际速度方向
}
// 仅在有效方向下进行旋转并忽略Y轴保持水平朝向
lookDirection.y = 0f;
if (lookDirection.sqrMagnitude > 0.0001f)
{
lookDirection.Normalize();
Quaternion targetRot = Quaternion.LookRotation(lookDirection);
// 只旋转Y轴保持X/Z为0避免低头或仰头
Vector3 targetEuler = targetRot.eulerAngles;
Quaternion flatTargetRot = Quaternion.Euler(0f, targetEuler.y, 0f);
// 使用平滑旋转让转向自然
transform.rotation = Quaternion.Slerp(
transform.rotation,
flatTargetRot,
Mathf.Clamp01(Time.deltaTime * rotationSpeed)
);
}
// 只在每30帧输出一次状态信息减少日志量
if (Time.frameCount % 30 == 0)
{
// 获取当前动画状态信息
string currentAnimation = "无";
if (characterAnimation != null && characterAnimation.isPlaying)
{
currentAnimation = characterAnimation.clip != null ? characterAnimation.clip.name : "未知";
}
// 计算直接距离到目标
float currentDirectDistance = Vector3.Distance(transform.position, targetPosition);
// Debug.Log($"角色移动中,直接距离: {currentDirectDistance:F2}m, 速度: {agent.velocity.magnitude:F2}m/s, 从起点移动: {distanceFromStart:F2}m, 状态: {currentMoveState}, 当前朝向: {transform.rotation.eulerAngles.y:F1}°, 当前动画: {currentAnimation}, 路径状态: {agent.pathStatus}");
}
}
}
else if (!isMoving && currentMoveState != MoveState.Idle)
{
// 如果没有在移动,重置状态为空闲
currentMoveState = MoveState.Idle;
// 确保动画状态与移动状态一致
EnsureAnimationStateConsistency();
}
// 添加对Arrived状态的处理确保能转换为Idle状态
else if (currentMoveState == MoveState.Arrived)
{
// 到达状态后,延迟一帧转换为空闲状态,确保动画播放完成
currentMoveState = MoveState.Idle;
Debug.Log("状态转换Arrived -> Idle角色准备接受新的移动指令");
}
}
/// <summary>
/// 在指定位置创建小球
/// </summary>
/// <param name="position">小球创建位置</param>
private void CreateBallAtPosition(Vector3 position)
{
try
{
if (ballPrefab != null)
{
// 在点击位置创建小球
GameObject ball = Instantiate(ballPrefab, position, Quaternion.identity);
Debug.Log($"在位置 {position} 创建了小球");
}
else
{
// 如果没有预制体,尝试创建一个简单的球体
// WebGL环境中可能不支持CreatePrimitive需要使用try-catch
try
{
GameObject ball = GameObject.CreatePrimitive(PrimitiveType.Sphere);
ball.transform.position = position;
ball.transform.localScale = Vector3.one * 0.1f; // 设置小球大小为0.1
ball.name = "ClickBall"; // 设置名称
// 添加一个简单的材质颜色
Renderer renderer = ball.GetComponent<Renderer>();
if (renderer != null)
{
renderer.material.color = Color.red; // 设置为红色
}
Debug.Log($"在位置 {position} 创建了默认小球");
}
catch (System.Exception ex)
{
// WebGL环境中CreatePrimitive可能失败如SphereCollider不存在
Debug.LogWarning($"无法使用CreatePrimitive创建球体: {ex.Message},请使用预制体或跳过创建小球");
// 可选创建一个简单的GameObject作为替代
// GameObject ball = new GameObject("ClickBall");
// ball.transform.position = position;
// Debug.Log($"在位置 {position} 创建了占位小球(仅用于调试)");
}
}
}
catch (System.Exception ex)
{
// 捕获所有其他可能的异常
Debug.LogWarning($"创建小球时发生异常: {ex.Message},位置: {position}");
}
}
/// <summary>
/// 立即设置角色朝向到目标位置
/// </summary>
/// <param name="targetPos">目标位置</param>
private void SetImmediateRotation(Vector3 targetPos)
{
// 计算水平方向的目标方向忽略Y轴变化
Vector3 horizontalDirection = (targetPos - transform.position);
horizontalDirection.y = 0; // 忽略Y轴变化只计算水平方向
if (horizontalDirection.magnitude > 0.01f)
{
horizontalDirection.Normalize();
// 直接设置朝向,不使用插值
Quaternion targetRotation = Quaternion.LookRotation(horizontalDirection);
// 保持X轴和Z轴为0只改变Y轴朝向
Vector3 targetEuler = targetRotation.eulerAngles;
Vector3 finalEuler = new Vector3(0, targetEuler.y, 0);
Quaternion finalRotation = Quaternion.Euler(finalEuler);
transform.rotation = finalRotation;
Debug.Log($"角色立即转向目标方向Y轴朝向: {finalEuler.y:F1}°");
}
}
/// <summary>
/// 确保动画状态与移动状态一致
/// </summary>
private void EnsureAnimationStateConsistency()
{
if (characterAnimation != null)
{
// 检查当前播放的动画
string currentClipName = characterAnimation.clip != null ? characterAnimation.clip.name : "";
// 如果当前是空闲状态但动画不是Stand则强制播放Stand动画
if (currentMoveState == MoveState.Idle && currentClipName != "Stand")
{
// 只有在动画确实在播放且不是Stand时才强制切换
if (characterAnimation.isPlaying && characterAnimation.GetClip("Stand") != null)
{
characterAnimation.Stop(); // 停止当前动画
characterAnimation.Play("Stand");
Debug.Log($"动画状态不一致强制播放Stand动画当前动画: {currentClipName}");
}
}
// 如果当前是移动状态但动画不是Running则强制播放Running动画
else if (currentMoveState == MoveState.Moving && currentClipName != "Running")
{
// 只有在动画确实在播放且不是Running时才强制切换
if (characterAnimation.isPlaying && characterAnimation.GetClip("Running") != null)
{
characterAnimation.Stop(); // 停止当前动画
characterAnimation.Play("Running");
Debug.Log($"动画状态不一致强制播放Running动画当前动画: {currentClipName}");
}
}
}
}
// 相机跟随角色
void FollowCamera()
{
// 相机跟随角色,保持相对位置关系,只做简单平移
if (mainCamera != null)
{
// 计算目标位置:角色当前位置 + 初始相对偏移
Vector3 targetCameraPos = transform.position + initialCameraOffset;
// 计算当前相机到目标位置的距离
float distanceToTarget = Vector3.Distance(mainCamera.transform.position, targetCameraPos);
// 如果距离很小,直接设置位置,避免卡顿
if (distanceToTarget < 0.1f)
{
mainCamera.transform.position = targetCameraPos;
}
else
{
// 使用可配置的跟随速度,确保平滑跟随
mainCamera.transform.position = Vector3.MoveTowards(mainCamera.transform.position, targetCameraPos, cameraFollowSpeed * Time.deltaTime);
}
// 完全不碰相机的旋转,保持你调整好的角度
}
}
}