Unity知识总结系列(二):相机跟随人物的几种方式

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

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

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

1、最简单,无代码,固定距离,固定视角
最简单的就是  直接  把主相机作为 Player 角色的子物体,并自行固定好相机的位置和角度
优点:使用方便
缺点:使用不灵活,相机转动死板,体验不好,相机瞬间移动位置
2、代码控制,固定距离,固定视角,对1进行改进
设置一个空的GameObject ,并且与 Player 的旋转和位置保持一致,然后将 主相机 设置成该 GameObject 的子对象。这种做法和方案  相似。
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  ,只能是重新创建一个相机,因为角色倒地的时候,子物体相机也会视角倒地,所以效率肯定方案  高)
优点:使用方便,适合大部分游戏模式
缺点:使用不灵活,相机转动死板(强制位移),体验不好
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、代码控制,固定距离,固定视角,插值移动(因为UpdateLateUpdate刷新率不同,会有抖动现象)
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 ;
     }
}

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值