Unity相机跟随详解

Unity知识总结系列(二):相机跟随人物的几种方式 
http://www.manew.com/thread-114711-1-1.html 

(出处: -【游戏蛮牛】-ar增强现实,虚拟现实,unity3d,unity3d教程下载首选u3d,unity3d官网)

相机跟随一般写在生命周期LateUpdate中

1、最简单,无代码,固定距离,固定视角

最简单的就是  直接  把主相机作为 Player 角色的子物体,并自行固定好相机的位置和角度

优点:使用方便

缺点:使用不灵活,相机转动死板,体验不好,相机瞬间移动位置

2、代码控制,固定距离,固定视角,对1进行改进

设置一个空的GameObject ,并且与 Player 的旋转和位置保持一致,然后将 主相机 设置成该 GameObject 的子对象。这种做法和方案  1  相似。

using  UnityEngine;

///   <summary>

///  创建一个空物体,

///  此空物体的位置信息始终与主角的位置信息保持一致,

///  主相机或主角相机给此空物体当子物体

///  当主角死亡时,空物体的位置信息更新为上一帧主角的位置信息

///   </summary>

public   class   CameraTest  :  MonoBehaviour {

     public   Transform  player;

     Vector3  tempPostion;

Quaternion tempRotation;

     void  Update (){

         if   ( player ){

            transform.position = player.position;

            transform.rotation = player.rotation;

         }

         else {

            transform.position = tempPostion;

            transform.rotation = tempRotation;

         }

        tempPostion = player.position;

        tempRotation = player.rotation;

     }


(这种做法好处在于  当模拟角色死亡倒地的时候不会获取不到人物信息,如果采用方案 1  ,只能是重新创建一个相机,因为角色倒地的时候,子物体相机也会视角倒地,所以效率肯定方案  2  高)

优点:使用方便,适合大部分游戏模式

缺点:使用不灵活,相机转动死板(强制位移),体验不好

3、代码控制,固定距离,固定视角,直接移动,不会旋转

使用代码获取到一个相机的初始位置与人物之间的 差值 向量, 在给相机赋值时再用这个差值向量与人物坐标求出相机的实时位置

using  UnityEngine;

public   class   CameraTest2  :  MonoBehaviour {

     public   Transform  player;

Vector3 distance;

     void  Start (){

        distance = transform.position - player.position;

     }

     void  LateUpdate (){

        transform.position = player.position + distance;

     }

}

优点:简单,方便,

缺点:无法一直跟随角色身后,适合固定视角游戏

4、代码控制,固定距离,固定视角,插值移动(因为Update和LateUpdate刷新率不同,会有抖动现象)

using  UnityEngine;

public   class   CameraTest2  :  MonoBehaviour {

     public   Transform  player;

     Vector3  distance;

     public   float  speed;

     void  Start (){

        distance = transform.position - player.position;

     }

     void  LateUpdate (){

        transform.position =  Vector3 .Lerp ( transform.position, player.position + distance,  Time .deltaTime * speed ) ;

     }

}

不建议使用

5、代码控制,固定距离,固定视角,平滑阻尼移动

using  UnityEngine;

public   class   CameraTest2  :  MonoBehaviour {

     public   Transform  player;

     Vector3  distance;

     public   float  speed;

Vector3 ve;

     void  Start (){

        distance = transform.position - player.position;

     }

     void  LateUpdate (){

        transform.position =  Vector3 .SmoothDamp ( transform.position, player.position + distance,  ref  ve, 0 ) ;

     }

}

代码实现相机跟随物体,可使用一个接口函数Vector3.SmoothDamp()  平滑阻尼 。   
函数介绍:随着时间的推移,逐渐改变一个向量朝向预期的目标(有点类似受阻力减速运动)  在官方的手册里也有推荐用此函数 来实现  平滑的相机跟随

public   static  Vector3 SmoothDamp(

Vector3 current, //当前物体位置

Vector3 target, //目标位置

ref Vector3 currentVelocity, //当前速度,这个值由你每次调用这个函数时被修改

//虽然使用ref关键字,不过函数运行时会自动修改

//一般传入参数值为0

float smoothTime, //到达目标的大约时间,较小的值将快速到达目标

float maxSpeed = Mathf.Infinity,//选择允许你限制的最大速度(默认为正无穷)

float deltaTime = Time.deltaTime//自上次调用这个函数的时间(默认为Time.deltaTime) );

6、代码控制,固定距离,跟随主角视角,平滑阻尼移动,看向主角

要使相机始终跟随主角身后,就要始终更新相机的位置在主角的Y 轴后面,于是手动设置设置相机相对于主角的距离

using  UnityEngine;

public   class   CameraTest2  :  MonoBehaviour {

     public   Transform  player;     //角色位置信息

     Vector3  off;                 //相机目标点位置信息

     Vector3  ve;                  //平滑阻尼的返回值

     Quaternion  angel;            //相机看向目标的旋转值

     public   float  hight;          //相机的高度

public float foward;        //相机在角色后的距离

     void  LateUpdate (){

        off = player.position + hight * player.up - foward * player.forward;

        transform.position =  Vector3 .SmoothDamp ( transform.position, off,  ref  ve, 0 ) ;

        transform.LookAt ( player.position ) ;

     }

}

这样的注视,相机移动还是太快

7、代码控制,固定距离,平滑的旋转相机,平滑阻尼移动,看向主角

using  UnityEngine;

public   class   CameraTest2  :  MonoBehaviour {

     public   Transform  player;     //角色位置信息

     Vector3  off;                 //相机目标点位置信息

     public   float  speed;          //相机移动速度

     Vector3  ve;                  //平滑阻尼的返回值

     Quaternion  angel;            //相机看向目标的旋转值

     public   float  hight;          //相机的高度

     public   float  foward;         //相机在角色后的距离

     void  LateUpdate (){

        off = player.position + hight * player.up - foward * player.forward;

        transform.position =  Vector3 .SmoothDamp ( transform.position, off,  ref  ve, 0 ) ;

//看向向量指向的方向

        angel =  Quaternion .LookRotation ( player.position - off ) ;

        transform.rotation =  Quaternion .Slerp ( transform.rotation, angel,  Time .deltaTime * speed ) ;

     }

}

8、代码控制,固定距离,平滑的旋转相机,平滑阻尼移动,看向主角,有物体遮挡(方法一)

using  UnityEngine;

///   <summary>

///  相机进行射线检测,如果检测不到主角,

///  就在起始点与结束点 ( 主角头顶的一个点 ) 之间寻找几个点,

///  直到找到可以看到主角的点

///   </summary>

public   class   CameraTest2  :  MonoBehaviour

{

     public   Transform  player;     //角色位置信息

     Vector3 []  v3;         //相机自动找寻的位置点

     public   int  num;              //相机临时点的个数

     public   Vector3  start;        //相机开始时的位置

     public   Vector3  end;          //相机没有找到主角时的位置

     Vector3  tagetPostion;        //相机看向的目标点

     Vector3  ve3;                 //平滑阻尼的ref参数

     Quaternion  angel;            //相机看向目标的旋转值

     public   float  speed;          //相机移动速度

     void  Start ()

     {

         //外界赋值数组长度

        v3 =  new   Vector3 [ num ] ;

     }

     void  LateUpdate ()

     {

         //记录相机初始位置

        start = player.position + player.up * 2.0f - player.forward * 3.0f;

         //记录相机最终位置

        end = player.position + player.up * 5.0f;

         //相机目标位置,开始等于初始位置

        tagetPostion = start;

        v3 [ 0 ]  = start;

        v3 [ num - 1 ]  = end;

         //动态获取相机的几个点

         for   ( int  i = 1; i < num; i++ )

         {

            v3 [ i ]  =  Vector3 .Lerp ( start, end, i / num ) ;

         }

         //判断相机在那个点可以看到主角

         for   ( int  i = 0; i < num; i++ )

         {

             if   ( Function ( v3 [ i ] ) )

             {

                tagetPostion = v3 [ i ] ;

                 break ;

             }

             if   ( i == num - 1 )

             {

                tagetPostion = end;

             }

         }

         //主角的移动和看向

        transform.position =  Vector3 .SmoothDamp ( transform.position, tagetPostion,  ref  ve3, 0 ) ;

        angel =  Quaternion .LookRotation ( player.position - tagetPostion ) ;

        transform.rotation =  Quaternion .Slerp ( transform.rotation, angel, speed ) ;

     }

     ///   <summary>

     ///  射线检测,相机是否能照到主角

     ///   </summary>

     ///   <param name=" v3 "> 计算射线发射的方向 </param>

     ///   <returns> 是否检测到 </returns>

     bool  Function ( Vector3  v3 )

     {

         RaycastHit  hit;

         if   ( Physics .Raycast ( v3, player.position - v3,  out  hit ) )

         {

             if   ( hit.collider.tag ==  "Player" )

             {

                 return   true ;

             }

         }

         return   false ;

     }

}

9、代码控制,固定距离,平滑的旋转相机,平滑阻尼移动,看向主角,有物体遮挡(方法二)

using  UnityEngine;

///   <summary>

///  从主角发射射线检测相机的位置

///  检测不到,就把相机移动到,射线的碰撞点的前面

///   </summary>

public   class   CameraTest2  :  MonoBehaviour

{

     public   Transform  player;             //角色头部(设置空物体)位置信息

     private   Vector3  tagetPostion;        //相机看向的目标点

     private   Vector3  ve3;                 //平滑阻尼的ref参数

     Quaternion  angel;                    //相机看向目标的旋转值

     public   float  speed;                  //相机移动速度

     public   float  upFloat;                //Y轴上升距离

     public   float  backFloat;              //Z轴与主角的距离

     void  LateUpdate ()

     {

         //记录相机初始位置

        tagetPostion = player.position + player.up * upFloat - player.forward * backFloat;

         [size=12.6667px]//刷新相机目标点的坐标

        tagetPostion = Function ( tagetPostion ) ;

         //主角的移动和看向

        transform.position =  Vector3 .SmoothDamp ( transform.position, tagetPostion,  ref  ve3, 0 ) ;

        angel =  Quaternion .LookRotation ( player.position - tagetPostion ) ;

        transform.rotation =  Quaternion .Slerp ( transform.rotation, angel, speed ) ;

     }

     ///   <summary>

     ///  射线检测,主角向后检测是否有相机跟随

     ///   </summary>

     ///   <param name=" v3 ">用来 计算射线发射的方向 </param>

     ///   <returns> 是否检测到 </returns>

     Vector3  Function ( Vector3  v3 )

     {

         RaycastHit  hit;

         if   ( Physics .Raycast ( player.position, v3 - player.position,  out  hit, 5.0f ) )

         {

             if   ( hit.collider.tag !=  "MainCamera" )

             {

                v3 = hit.point + transform.forward * 0.5f;

             }

         }

         return  v3;

     }

}

10、代码控制,固定距离,平滑的旋转相机,平滑阻尼移动,看向主角,有物体遮挡,结合手游中相机的旋转和复位

using  UnityEngine;

///   <summary>

///  相机进行射线检测,如果检测不到主角,

///  就在起始点与结束点之间寻找几个点,

///  直到找到可以看到主角的点

/// 在游戏中玩家可以用鼠标控制相机的旋转

///   </summary>

public   class   CameraTest2  :  MonoBehaviour

{

     public   Transform  player;     //角色位置信息

     Vector3 []  v3;         //相机自动找寻的位置点

     public   int  num;              //相机临时点的个数

     public   Vector3  start;        //相机开始时的位置

     public   Vector3  end;          //相机没有找到主角时的位置

     Vector3  tagetPostion;        //相机看向的目标点

     Vector3  ve3;                 //平滑阻尼的ref参数

     Quaternion  angel;            //相机看向目标的旋转值

     public   float  speed;          //相机移动速度

     void  Start ()

     {

         //外界赋值数组长度

        v3 =  new   Vector3 [ num ] ;

     }

     void  LateUpdate ()

     {

         //记录相机初始位置

        start = player.position + player.up * 2.0f - player.forward * 3.0f;

         //记录相机最终位置

        end = player.position + player.up * 5.0f;

         //鼠标控制相机的旋转

         if   ( Input .GetMouseButton ( 1 ) )

         {

             //记录相机的初始位置和旋转角度

             Vector3  pos = transform.position;

             Vector3  rot = transform.eulerAngles;

             //让相机绕着指定轴向旋转

            transform.RotateAround ( transform.position,  Vector3 .up,  Input .GetAxis ( "Mouse X" )  * 10 ) ;

            transform.RotateAround ( transform.position,  Vector3 .left, - Input .GetAxis ( "Mouse Y" )  * 10 ) ;

             //限制相机的绕X旋转的角度

             if   ( transform.eulerAngles.x < -60 || transform.eulerAngles.x > 60 )

             {

                transform.position = pos;

                transform.eulerAngles = rot;

             }

             return ;

         }

         //相机目标位置,开始等于初始位置

        tagetPostion = start;

        v3 [ 0 ]  = start;

        v3 [ num - 1 ]  = end;

         //动态获取相机的几个点

         for   ( int  i = 1; i < num; i++ )

         {

            v3 [ i ]  =  Vector3 .Lerp ( start, end, i / num ) ;

         }

         //判断相机在那个点可以看到主角

         for   ( int  i = 0; i < num; i++ )

         {

             if   ( Function ( v3 [ i ] ) )

             {

                tagetPostion = v3 [ i ] ;

                 break ;

             }

             if   ( i == num - 1 )

             {

                tagetPostion = end;

             }

         }

         //主角的移动和看向

        transform.position =  Vector3 .SmoothDamp ( transform.position, tagetPostion,  ref  ve3, 0 ) ;

        angel =  Quaternion .LookRotation ( player.position - tagetPostion ) ;

        transform.rotation =  Quaternion .Slerp ( transform.rotation, angel, speed ) ;

     }

     ///   <summary>

     ///  射线检测,相机是否能照到主角

     ///   </summary>

     ///   <param name=" v3 "> 计算射线发射的方向 </param>

     ///   <returns> 是否检测到 </returns>

     bool  Function ( Vector3  v3 )

     {

         RaycastHit  hit;

         if   ( Physics .Raycast ( v3, player.position - v3,  out  hit ) )

         {

             if   ( hit.collider.tag ==  "Player" )

             {

                 return   true ;

             }

         }

         return   false ;

     }

}

猜你喜欢

转载自blog.csdn.net/Star_MengMeng/article/details/122893945