最近需要实现一个功能:相机跟随玩家并实现鼠标可以控制相机环绕玩家旋转,按住鼠标右键在屏幕左右滑动,可以使相机绕玩家左右旋转;按住鼠标右键在屏幕上下滑动,可以使相机绕玩家上下旋转,鼠标滚轮拉近拉远相机和玩家的距离.因为我对unity中物体环绕一直不甚了解,趁此机会研究了一下,如有谬误或者更简洁的方法,欢迎指正.
既然需要鼠标控制,自然就获知鼠标在屏幕上的位置等信息,先声明几个元素:

Vector3 start = new Vector3(0, 0, 0);//鼠标在屏幕上的起始位置
    Vector3 end = new Vector3(0, 0, 0);//鼠标在屏幕上的位置

然后我们获取鼠标的信息:

if (Input.GetMouseButtonDown(1))
        {
             start = Input.mousePosition;
        }
        if(Input.GetMouseButton(1)) {
             end = Input.mousePosition;
        }
        float LeftAndRight = end.x - start.x;//鼠标在屏幕上的左右移动距离(像素)
        float UpAndDown = end.y - start.y;//鼠标在屏幕上的上下移动距离(像素)
         if (Input.GetMouseButtonUp(1))//当鼠标右键抬起时,归零
        {
            LeftAndRight = 0;
            UpAndDown = 0;
            start = new Vector3(0, 0, 0);
            end = new Vector3(0, 0, 0);
        }

好了,这时我们已经获取到了鼠标在屏幕上的滑行距离了,接下来就是根据这些数据控制相机移动了.
相机环绕玩家进行左右移动是最简单的,因为它没有距离和角度上的各种限制,可以无限旋转

/*因为相机需要跟随玩家移动,所以我将相机设为了玩家的子物体*/
        transform.RotateAround(transform.root.position, Vector3.up,LeftAndRight*0.1f *Time.deltaTime);//以玩家所在位置为中心,世界坐标系的向上方向为轴向(此时强调为世界坐标系,是因为玩家角色并不能保证一直处于正常的站立模式,如果是玩家自身坐标系的话,一旦玩家角色发生歪斜,相机的环绕就会出现问题),进行环绕

因为玩家必须一直都要在镜头内,所以我们只需要使用LookAt函数使相机实时对着玩家即可.
接下来我们将控制相机进行上下环绕,思路与上面是相同的,但因为相机是不可能进入到地下的,所以我们需要设置一个相机与玩家的最小角度值,在此我设置为10度.那么我们需不需要设置一个最大值呢?如果你亲自试一下就会觉得很有必要,在此我也就不再赘述了,此处我设置的角度为80度.
贴上代码:

if (transform.rotation.x<=80f&&transform.rotation.x>=10f)
        {
            transform.RotateAround(transform.root.position, transform.right, UpAndDown * 0.1f * Time.deltaTime);//以玩家位置为中心,以相机自身x轴为轴向旋转
        }

如果这时你运行的话,就会发现根本不行!!坑一就是transform.rotation这个东西了!虽然我们在Inspector面板中看到的rotation是由我们最熟悉的x,y,z欧拉角构成,但实际上它是四元数!如果此时你打印出transform.rotation.x,就会发现跟面板中显示的根本不一样!

Unity 人物朝向鼠标 unity鼠标移动控制角色旋转_unity


Unity 人物朝向鼠标 unity鼠标移动控制角色旋转_Time_02


至于四元数是什么鬼以及四元数与欧拉角的换算我也不甚明了,感兴趣的朋友可以搜下其他的帖子.但是问题还得解决,怎么获取Inspector中x的角度呢?用transform.localEulerAngles.x就OK了.所以代码就成了这样

if (transform.localEulerAngles.x <= 80f &&transform.localEulerAngles.x >=10f)
        {
            transform.RotateAround(transform.root.position, transform.right, UpAndDown * 0.1f * Time.deltaTime);
        }

如果这时你运行的话,高兴不了3秒就又发现问题了!坑二就是你会发现随着你鼠标的操作transform.localEulerAngles.x有可能会大于80,或者小于10,一旦这样你的相机上下环绕就会失效,动不了了!怎么办呢?我的第一反应很简单,我们只需添加一个if语句,当x的值大于80(或者小于10)我们就使x的值等于80(或者10)就行了.但是当实际操作时就会发现并没如人所愿,因为lookAt函数会覆盖掉对x值的修改~~然后,我就抖了个小机灵,我的思路是这样的:我们可以将相机的上下环绕分离开,当x>=10时,只负责相机的向下环绕;当x<=80时,只负责相机的向上环绕.

if (transform.localEulerAngles.x <= 80f && UpAndDown > 0)
        {

            transform.RotateAround(transform.root.position, transform.right, UpAndDown * 0.1f * Time.deltaTime);
        }
        else
        if (transform.localEulerAngles.x >= 10 && UpAndDown < 0)
        {
            transform.RotateAround(transform.root.position, transform.right, UpAndDown * 0.1f * Time.deltaTime);
        }

完美解决!

好了,剩下最后一个问题:鼠标滚轮控制相机距离玩家的远近.大致思路是这样的:根据滚轮的数据,使相机在自身z轴的方向上,在一定距离内平移.

float speed = 80;//相机距离玩家远近的调节速度
    float maxVidiconToPlayer = 22f;//相机距离玩家的最远距离
    float minVidiconToPlayer = 5f;//相机距离玩家的最近距离
     float dic = Input.GetAxis("Mouse ScrollWheel");//鼠标滑轮的滑动距离;
        if (Mathf.Abs(transform.position.z - transform.root.position.z) >= minVidiconToPlayer && dic >0)
        {
            transform.Translate(Vector3.forward * Time.deltaTime *dic*speed , Space.Self);
        }
        else if (Mathf.Abs(transform.position.z - transform.root.position.z) <= maxVidiconToPlayer&&dic<0)
        {
            transform.Translate(Vector3.forward * Time.deltaTime * dic* speed, Space.Self);
        }

至此,大功告成!