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

如何设置Unity第一人称角色控制器基于Rigidbody Velocity的移动功能

第一人称Rigidbody角色控制器修复方案

原代码核心问题

  • 物理属性(Rigidbody.velocity)赋值放在Update中执行,和Unity物理更新周期不同步,导致移动卡顿、表现不稳定
  • 每帧重复调用GameObject.Find、GetComponent接口,无对象缓存,性能损耗极高
  • 胶囊体朝向逻辑错误:调用LookAt对准相机位置,导致胶囊体前向完全和预期相反,移动方向匹配错误
  • 无输入时未清空velocity,角色松开按键后会继续滑行
  • 输入判断逻辑重复冗余,多处重复计算输入向量的模长,可读性差

前置Inspector设置

首先需要给玩家胶囊体的Rigidbody组件勾选「Freeze Rotation」下的X、Y、Z三个选项,避免物理碰撞导致胶囊体倾倒。

修复后完整代码

using UnityEngine;

public class characterController : MonoBehaviour {
    [Header("移动参数")]
    public float moveSpeed = 5f;
    public Vector3 cameraOffset = new Vector3(0, 1.8f, 0); // 相机高度偏移,适配正常第一人称视角高度

    [Header("状态标记")]
    public bool reteleporing = false;
    public bool walking = false;
    
    // 缓存引用,避免每帧查找
    private Rigidbody _rb;
    private Camera _mainCam;
    private Transform _spawnPos;
    private Vector2 _moveInput;

    void Start () {
        // 一次性缓存所有需要的引用
        _rb = GetComponent<Rigidbody>();
        _mainCam = Camera.main;
        _spawnPos = GameObject.Find("spawnpos").transform;
    }
    
    // 输入检测、逻辑更新放Update
    void Update (){
        // 收集输入
        _moveInput = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
        walking = _moveInput.magnitude > 0.01f;

        // 掉落传送逻辑
        if (transform.position.y < -100)
        {
            reteleporing = true;
        }
        if (reteleporing)
        {
            transform.position = _spawnPos.position;
            if (transform.position.y > 2.4f)
            {
                reteleporing = false;
            }
        }

        // 相机位置同步
        _mainCam.transform.position = transform.position + cameraOffset;
    }

    // 物理相关操作统一放FixedUpdate
    private void FixedUpdate()
    {
        if (reteleporing) return;
        
        // 胶囊体Y轴旋转和相机保持一致,保证前向匹配视角方向
        transform.rotation = Quaternion.Euler(0, _mainCam.transform.eulerAngles.y, 0);

        if (walking)
        {
            // 计算水平方向的移动向量,跟随相机视角
            Vector3 camForward = Vector3.Scale(_mainCam.transform.forward, new Vector3(1, 0, 1)).normalized;
            Vector3 moveDir = camForward * _moveInput.y + _mainCam.transform.right * _moveInput.x;
            // 直接赋值velocity,保留Y轴重力
            _rb.velocity = new Vector3(moveDir.x * moveSpeed, _rb.velocity.y, moveDir.z * moveSpeed);
        }
        else
        {
            // 无输入时清空水平方向速度,避免滑行
            _rb.velocity = new Vector3(0, _rb.velocity.y, 0);
        }
    }
}

关键修改说明

  • 所有Rigidbody相关操作移至FixedUpdate执行,匹配Unity物理更新周期,移动稳定性大幅提升
  • 新增引用缓存逻辑,所有频繁调用的对象仅在Start中查找一次,性能优化明显
  • 修正朝向逻辑:胶囊体Y轴旋转直接同步相机的Y轴旋转,保证移动方向完全匹配玩家视角
  • 保留velocity直接赋值的实现方式,Y轴速度保留原有重力值,无需额外处理重力逻辑
  • 新增无输入时水平速度归零逻辑,解决松开按键后角色滑行的问题
  • 优化重复代码,输入仅每帧收集一次,状态判断逻辑简化

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 01:27:08