角色控制器开发日志

创作人 Leo


编辑时间 Fri Jul 29,2022 at 19:47


Unity 角色控制开发日志

踩过的坑:
1. 关于使用character controller无法使用重力的问题
2. Unity position和localposition

相关资料:
1. 点积
2. Unity教程:详解Character Controller角色移动控制

需求:
1. 角色静止状态,滑动鼠标已用户为轴心旋转摄像头,使之能浏览角色
2. 当角色行走,立即将摄像头回到角色背后,并保持位置(角色向前走,摄像头始终保持在角色后方)
3. WASD控制行走时,摄像头位置保持不变,角色模型跟随方向键进行旋转展示

实现效果:

代码:

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

public class CharacterCtrl : MonoBehaviour
{
    [SerializeField]
    Camera mainCamera;

    [SerializeField]
    Transform mainRole;

    CharacterController cc;

    bool ctrlEnable = false;

    Vector3 cameraDefaultPosition;
    Quaternion cameraDefaultRotation;

    // Start is called before the first frame update
    void Start()
    {
        //mainCamera = Camera.main;
        cc = GetComponent<CharacterController>();

        cameraDefaultPosition = mainCamera.transform.localPosition;
        cameraDefaultRotation = mainCamera.transform.localRotation;
    }

    // Update is called once per frame
    void Update()
    {
        keyListen();
        
        if (ctrlEnable)
            update2();
    }

    void keyListen()
    {
        if (Input.GetKeyDown(KeyCode.Mouse0))
        {
            ctrlEnable = true;
            Cursor.lockState = CursorLockMode.Locked;
            Cursor.visible = false;
        }

        if (Input.GetKeyDown(KeyCode.Escape))
        {
            ctrlEnable = false;
            Cursor.lockState = CursorLockMode.None;
            Cursor.visible = true;
        }
    }

    // 2. rotate character it self
    void update2()
    {
        float horizontalInput = Input.GetAxis("Horizontal"); // 获取左右移动值
        float verticalInput = Input.GetAxis("Vertical"); // 获取上下移动值
        float mx = Input.GetAxis("Mouse X"); // 获取鼠标左右移动值

        // 物体是否在地面上判断,修改 y 轴
        float _vertSpeed = 0;
        if (!cc.isGrounded)
        {
            _vertSpeed += -9.8f * 5 * Time.deltaTime; 
            if (_vertSpeed < -10.0f)
            {
                _vertSpeed = -10.0f;
            }
        }

        // 角色原地不动,鼠标左右摆动为摄像机绕角色旋转,
        if (horizontalInput == 0f && verticalInput == 0f)
        {
            mainCamera.transform.RotateAround(transform.position, Vector3.up, mx);
            cc.Move((new Vector3(0f, _vertSpeed, 0f)) * 0.1f);
            return;
        }

        // 纵坐标向上的向量
        Vector2 norVecOrig = new Vector3(0f, 1.0f);
        // 合并 x y 移动为一个向量
        Vector2 norVec = new Vector3(horizontalInput, verticalInput);

        // 在计算两个向量相交角度时需要先算两个向量的模,而取模时每个值都是被平方的,所以没有负数,结果没有负角度
        // 所以它最大就是180度
        // 二象限和三象限需要通过判断水平x方向输入值为正负来确定是向左侧转角还向右侧转角
        float dir = 1.0f;
        if (horizontalInput < 0)
        {
            dir = -1.0f; 
        }

        // 计算参与角度计算的两个向量的模
        float mVecOrig = Mathf.Sqrt(Mathf.Pow(norVecOrig.x, 2) + Mathf.Pow(norVecOrig.y, 2));
        float mVec = Mathf.Sqrt(Mathf.Pow(norVec.x, 2) + Mathf.Pow(norVec.y, 2));

        // 计算两向量角度:向前的基础向量 (0, 1) , 角色移动的方向向量 (inputX, inputY)
        // cos(C) = (a * b) / (|a| * |b|) 
        // C = acos((a * b) / (|a| * |b|))
        float angel = Mathf.Acos(Vector2.Dot(norVecOrig, norVec) / (mVecOrig * mVec));        
        
        // 旋转角色模型
        mainRole.localRotation = Quaternion.Euler(0f, angel * Mathf.Rad2Deg * dir, 1f);

        // 摄像头位置移动重置,处理角色站立时摄像头的移动
        // TODO 应该是角色移动方向自动调整为摄像机看的方向
        mainCamera.transform.localPosition = cameraDefaultPosition;
        mainCamera.transform.localRotation = cameraDefaultRotation;

        // 鼠标左右移动选择角色并带动摄像机旋转
        transform.Rotate(Vector3.up, mx);

        Vector3 newVec = transform.forward * verticalInput + transform.right * horizontalInput ;
        newVec.y = _vertSpeed; // 角色始终落地

        cc.Move(newVec*0.1f);
    }

}


阅读:52
搜索
  • Linux 高性能网络编程库 Libevent 简介和示例 2288
  • Mac系统编译PHP7【20190929更新】 2186
  • Hadoop 高可用集群搭建 (Hadoop HA) 1852
  • Linux 常用命令 1837
  • zksync 和 layer2 1832
  • 安徽黄山游 1817
  • Windows 安装Swoole 1794
  • Hadoop 高可用YARN 配置 1750
  • 小白鼠问题 1707
  • 使用 Java+Thrift 实现异步事件处理服务 1627
简介
不定期分享软件开发经验,生活经验