unity第三人称视角下使用手柄的摄像机控制及防穿墙

unity第三人称视角下使用手柄的摄像机控制及防穿墙

unity第三人称视角下使用手柄的摄像机控制及防穿墙

有关手柄的设置参考下面这个帖子,这里不再重复

要让相机跟随角色,首先可以让相机成为角色的子物体,或在初始时得到相机与角色的偏移量,在运动过程中让角色的位置加上这个偏移量即可。为了更好适应角色所处环境及实现其他功能,可以采用以下方法:

创建一个空物体Empty,在Empty下创建一个子物体Position,最后使相机成为Position的子物体。接下来我们需要设置这几个物体(在代码中),让Empty的position等于人物的position,让Position的位置等于人物的位置的Y方向加1.0f(其实可以随意设置)unity摄像机旋转,再把相机设置到合适的位置使之看向角色(设置相机可以在Scene模式下设置)。

创建一个C#脚本,将其挂载在Empty上,定义以下变量像素游戏素材,并在Start方法中获取刚才设置的物体的Transform组件以及相机与Postion的偏移量

private Transform charactor;//获取当前角色
    private Transform pos;//获取Empty的子物体pos
    private Vector3 offset;//获取初始时镜头相对于pos的偏移量
    private float R_H;//获取摇杆的返回值-水平轴
    private float R_V;//获取摇杆的返回值-垂直轴
    private float lookAngle;//镜头说水平旋转的角度
    private float tiltAngle;//镜头垂直旋转的角度(实质为父物体pos的垂直旋转角度)
    private float moveSpeed = 10f;//用于设置镜头跟随的速度
    private float turnSpeed = 1.5f;//用于设置镜头在两个方向上旋转的角度
    private Transform mainCamera;
    // Use this for initialization
    void Start()
    {
        charactor = GameObject.FindGameObjectWithTag("Charactor").GetComponent();
        pos = GameObject.FindGameObjectWithTag("Pos").GetComponent();
        mainCamera = GameObject.FindGameObjectWithTag("MainCamera").GetComponent();
        offset = mainCamera.position - pos.position;
    }

相机跟随角色可以采用以下方法:

private void FollowCharactor(float deltaTime)
    {
        //注意需要把offset转为pos的局部坐标
        mainCamera.position = Vector3.Lerp(mainCamera.position, pos.position + pos.TransformDirection(offset), deltaTime * moveSpeed);
    }

引入deltaTime参数和Lerp方法可以使镜头变换更加平滑顺畅

接下来是控制镜头左右和上下旋转,镜头的水平方向旋转由Empty控制,垂直方向的旋转由pos控制,这么做可以防止镜头注视角色的时候旋转出现问题,比如在自身Z轴上发生旋转

private void HandleCameraRotate()
    {
        transform.position = charactor.position;//设定水平旋转角度
        lookAngle += R_H * turnSpeed;
        transform.localEulerAngles = new Vector3(0, lookAngle, 0);//将得到的角度赋值给empty的localEulerAngles
        tiltAngle -= turnSpeed * R_V;//设定垂直旋转角度
        tiltAngle = Mathf.Clamp(tiltAngle, -80, 50);//对旋转角度加以限制
        pos.localEulerAngles = new Vector3(tiltAngle, pos.localEulerAngles.y, pos.localEulerAngles.z);//将得到的角度赋值给pos的localEulerAngles
        
    }

这样基本的控制就做完了,可以在Update()方法中调用(实测FixedUpdate和LateUpdate方法中调用效果不好)

void Update()
    {
        R_H = Input.GetAxis("Horizontal_Right");
        R_V = Input.GetAxis("Vertical_Right");
        HandleCameraRotate();
        FollowCharactor(Time.deltaTime);
    }

对于防镜头穿墙的方法,这是我个人想出来的可能算是比较简单的一种写法2d素材,在Update中调用即可

从pos的位置开始unity摄像机旋转,创建一条指向相机的射线,长度为offset,判断射线碰撞到的物体的标签

private void AvoidCrossWall()
    {
        RaycastHit hit;
        if (Physics.Raycast(pos.position, mainCamera.position - pos.position, out hit, offset.magnitude))
        {
            if (hit.collider.tag == "Obstacle")
            {
                mainCamera.position = hit.point;
            }
        }
    }

本方法需要把不想让墙穿过的所有物体的标签设置为Obstacle

文章来源:https://blog.csdn.net/qq_45919090/article/details/109393562