实现移动可以用transform.Translate、rigidbody.velocity及最简单的改变position。但在人物移动中,往往会遇到一些坡度(slope)或者楼梯,这时候使用unity提供的CharacterController组件会简单快捷。

下面示例实现了一个较简单的人物控制器,功能有移动,跑、跳跃

这边我简单的搭建了一个场景。创建了一个空物体作为角色(FPS Player),将主相机拉到空物体下调整到合适的第一人称视角。同时创建一个圆柱体方便我们观察,最后再创建一个空物体(GroundCheck)拉到我们角色的底部(相当于脚的位置)后面地面检测时需要用到。

unity3d 第一人称控制器_Time


给我们的角色(FPS Player),添加上CharacterController组件和PlayerMovement脚本。给摄像机(Main Camera)添加上MouseLock脚本

unity3d 第一人称控制器_unity3d_02


unity3d 第一人称控制器_unity3d_03

接下来开始编写代码

PlayerMovement

定义相关的变量

//角色控制器
    public CharacterController controller;

    //获得GroundCheck的位置
    public Transform groundCheck;
    //GroundCheck检测半径
    public float groundDistance = 0.4f;
    //检测的LayerMask层
    public LayerMask groundMask;

    //移动速度
    public float speed = 12f;
    //奔跑速度
    public float runSpeed = 20f;
    //重力
    public float gravity = -9.81f;
    //跳跃高度
    public float jumpHeight = 3f;

    //仿重力vector3
    private Vector3 velocity;
    //是否在地面
    private  bool isGrounded;

采用Physics.CheckSphere进行地面检测。
这边可以使用OnDrawGizmos()方法可视化检测范围

private void OnDrawGizmos()
    {
        Gizmos.color = Color.blue;
        Gizmos.DrawWireSphere(groundCheck.position, groundDistance); 
    }

使用CharacterController的Move方法实现移动
由速度随位移的变化规律:2gH=Vt²-V0²,跳跃向上的初速度会等于√-2gH

void Update()
    {
        //地面检测,如果踩在地面返回true否则返回false
        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);

        if (isGrounded && velocity.y < 0)
        {
            //如果在地面,将向下的重力改为2
            velocity.y = -2f;
        }

        //获得键盘输入
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");
        
        Vector3 move = transform.right * x + transform.forward * z;
        //安住左shift跑
        if (Input.GetKey(KeyCode.LeftShift))
            controller.Move(move * runSpeed * Time.deltaTime);
        else
            controller.Move(move * speed * Time.deltaTime);

        //跳跃
        if (Input.GetButtonDown("Jump"))
        {
            //跳跃高度为jumpHeight的向上初速度
            velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity); 
        }

        //时时刻刻都受到重力影响
        velocity.y += gravity * Time.deltaTime;
        controller.Move(velocity * Time.deltaTime);
    }

拉取对应的物体,然后调整参数值,同时记得将能走的地方的Layer层和你选择的GroundMask层设为一致。

unity3d 第一人称控制器_unity3d_04


unity3d 第一人称控制器_unity3d_05

MouseLock
//灵敏度
    public float mouseSensitivity = 100f;
    //角色Transform
    public Transform playerBody;

    float xRotation = 0f;
    // Start is called before the first frame update
    void Start()
    {
        //锁定隐藏鼠标
        Cursor.lockState = CursorLockMode.Locked;
    }

    // Update is called once per frame
    void Update()
    {
        float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
        float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;

        //获得鼠标上下移动的值
        xRotation -= mouseY;
        //设置鼠标向上向下范围
        xRotation = Mathf.Clamp(xRotation, -90f, 90f);

        //旋转摄像机(向上向下)
        transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
        //鼠标左右移动改变人物旋转
        playerBody.Rotate(Vector3.up * mouseX);
    }

拉取角色组件,调整合适参数

unity3d 第一人称控制器_ci_06

全部调整好就是一个简单的第一人称角色了,如果楼梯或者坡度上不去可以去调整角色CharacterController对应的值。有模糊的地方可以查询Unity相关文档。