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

Unity CharacterController跳跃时无法保持水平移动问题求助

问题原因

你代码中moveDirection *= moveSpeed的逻辑被包裹在if(isGrounded)判断分支内,角色离开地面后该逻辑不再执行,moveDirection仅保留输入轴返回的-1到1的原始数值,没有乘以实际移动速度,所以表现为跳跃时水平移动中断、原地起跳。

修复方案
  • 调整逻辑执行顺序:先判断行走/奔跑状态完成moveSpeed赋值,再给moveDirection乘以移动速度
  • 将moveDirection *= moveSpeed移出if(isGrounded)判断块,保证空中也能正常计算水平移动速度
修正后完整代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Movementcontroller : MonoBehaviour
{
    //VARIABLES
    [SerializeField] private float moveSpeed;
    [SerializeField] private float walkSpeed;
    [SerializeField] private float runSpeed;

    private Vector3 moveDirection;
    private Vector3 velocity;

    [SerializeField] private bool isGrounded;
    [SerializeField] private float groundCheckDistance;
    [SerializeField] private LayerMask groundMask;
    [SerializeField] private float gravity;

    [SerializeField] private float jumpHeight;


    //REFERENCES

    private CharacterController controller;

    private void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    private void Update()
    {
        Move();
    }
     
    private void Move()
    {
        isGrounded = Physics.CheckSphere(transform.position, groundCheckDistance, groundMask);

        if(isGrounded && velocity.y < 0)
        {
            velocity.y = -2f;
        }

        float moveZ = Input.GetAxis("Vertical");
        float moveX = Input.GetAxis("Horizontal");

        moveDirection = new Vector3(moveX, 0, moveZ);
        moveDirection = transform.TransformDirection(moveDirection);

        // 先判断移动状态,确定moveSpeed数值
        if(moveDirection != Vector3.zero && !Input.GetKey(KeyCode.LeftShift))
        {
            Walk();
        }
        else if(moveDirection != Vector3.zero && Input.GetKey(KeyCode.LeftShift))
        {
            Run();
        }
        else if(moveDirection == Vector3.zero)
        {
            Idle();
        }

        // 移动速度赋值放到isGrounded判断外,空中也生效
        moveDirection *= moveSpeed;

        if(isGrounded)
        {
            if(Input.GetKeyDown(KeyCode.Space))
            {
                Jump();
            }
        }

        controller.Move(moveDirection * Time.deltaTime);

        velocity.y += gravity * Time.deltaTime;
        controller.Move(velocity * Time.deltaTime);
    }
    private void Idle()
    {

    }

    private void Walk()
    {
        moveSpeed = walkSpeed;
    }

    private void Run()
    {
        moveSpeed = runSpeed;
    }

    private void Jump()
    {
        velocity.y = Mathf.Sqrt(jumpHeight * -2 * gravity);
    }

}
可选优化

如果需要区分地面和空中的移动灵敏度,可以额外定义一个[SerializeField] private float airControlRate = 0.8f;的系数,在空中时给moveDirection额外乘以该系数,即可实现更符合直觉的空中阻尼效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 20:24:03