You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中使用CharacterController跳跃时旋转Y值归零问题求解

问题原因分析

你遇到的旋转Y值归零问题,核心原因是跳跃时moveDirection的X/Z分量为0,但Y分量不为0,导致moveDirection.magnitude >= 0.1f的条件成立,此时Mathf.Atan2(0,0)计算出的targetAngle是0,平滑旋转逻辑会把角色Y轴旋转强制拉到0度。

修复方案

把旋转逻辑和移动逻辑的触发条件彻底分开:旋转只在有水平/垂直输入时执行,而移动(包括重力、跳跃的Y轴移动)始终执行,不受方向输入影响。修改后的完整代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    public CharacterController controller;

    public float turnSmoothTime = 0.1f;
    float turnSmoothVelocity;
    public float Speed = 10f;

    private Vector3 moveDirection;

    public float gravity = -9.81f;
    public float jumpPower = 3.5f;
    public float directionY;

    public Animator anim;
    public Transform cam;


    private void Update()
    {
        float horizontal = Input.GetAxisRaw("Horizontal");
        float vertical = Input.GetAxisRaw("Vertical");

        // 处理地面检测与跳跃逻辑
        if (controller.isGrounded)
        {
            directionY = Input.GetKeyDown(KeyCode.Space) ? jumpPower : 0;
        }
        else
        {
            directionY += gravity * Time.deltaTime;
        }

        // 处理方向输入与角色旋转
        Vector3 inputDirection = new Vector3(horizontal, 0f, vertical).normalized;
        if (inputDirection.magnitude >= 0.1f)
        {
            float targetAngle = Mathf.Atan2(inputDirection.x, inputDirection.z) * Mathf.Rad2Deg;
            // 如果需要跟随相机视角旋转,取消下面这行注释
            // targetAngle += cam.eulerAngles.y;
            
            float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
            transform.rotation = Quaternion.Euler(0f, angle, 0f);

            // 将输入方向转换为世界空间下的移动方向
            moveDirection = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
            moveDirection *= Speed;
        }
        else
        {
            // 无方向输入时,仅保留Y轴的重力/跳跃力,X/Z方向停止移动
            moveDirection.x = 0;
            moveDirection.z = 0;
        }

        // 应用Y轴的重力/跳跃力
        moveDirection.y = directionY;

        // 执行移动(始终调用,确保跳跃和重力生效)
        controller.Move(moveDirection * Time.deltaTime);

        // 动画状态更新(可选)
        bool isWalking = !Mathf.Approximately(horizontal, 0f) || !Mathf.Approximately(vertical, 0f);
        anim.SetBool("IsWalking", isWalking);
    }
}

关键修改点

  • 拆分inputDirection(仅存储X/Z轴的玩家输入方向)与moveDirection(最终移动方向,包含Y轴的重力/跳跃力),旋转逻辑仅依赖inputDirection,彻底避免Y轴分量干扰旋转判断
  • 将controller.Move改为始终调用,确保跳跃、重力的Y轴移动不受方向输入影响
  • 无方向输入时,强制将moveDirection的X/Z分量设为0,避免无输入时的无效移动

内容的提问来源于stack exchange,提问作者Unityabcd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 14:20:40