U3D摄像机视角

U3D的可以通过设置摄像机来实现第一人称,第三人称等不同游戏视角。

1第一人称视角

四元数转化成欧拉角 Vector3 v3=transform.rotation.eulerAngles;
欧拉角转换成四元数 Quaternion rotation = Quaternion.Euler(v3);

需要实现的效果:鼠标上下左右移动镜头跟着移动;人物移动和跳跃(这里我们人物移动使用的是CharacterController组件的Move和SimpleMove方法);

unity移动视角 unity3d第一视角移动_unity移动视角


unity移动视角 unity3d第一视角移动_System_02

//player.cs   人物移动代码
//使用CharacterController组件控制人物移动,simpleMove和Move两种方法的区别是:Move需要自己定义重力,如下:
using UnityEngine;
using System.Collections;

/// <summary>
/// CharacterController控制移动
/// 1:SimpleMove(自动应用重力效果)
/// 2:Move(不会应用重力效果,需要自己去实现)
/// </summary>
public class PlayerMove : MonoBehaviour {
private CharacterController cc;//角色控制器,控制物体的移动
private float speed = 4.0f;//移动速度
private float gravity = 10.0f;//重力
private Vector3 moveDir = Vector3.zero;//移动方向
void Start () 
{
   cc = this.GetComponent<CharacterController>();
}

void Update () 
{
   //模拟重力效果
   //一开始y方向速度为正,表示再上升即跳起来;当y为负时,开始下降,且下降速度越来越快
   if (moveDir.y > -gravity)
   {
       moveDir.y -= gravity * Time.deltaTime;
       print(moveDir);
   }
   cc.Move(moveDir * Time.deltaTime);//首先必須保證moveDir为负数,不能为0,只有是负数,才能算是isGrounded
   if (cc.isGrounded)//在地上
   {
       if (Input.GetKeyDown(KeyCode.Space))//按空格起跳
       {
           moveDir.y = speed;
       }
       else
       {
           float h = Input.GetAxis("Horizontal")*speed;
           float v = Input.GetAxis("Vertical")*speed;
           Vector3 dir = new Vector3(h, 0, v);//水平面方向的移动
           dir *= speed;
           if (Input.GetKey(KeyCode.LeftShift))
           {
               dir *= 2;
           }
           //cc.SimpleMove(transform.TransformDirection(dir));//不需要乘以deltaTime,把当前方向转换到世界空间中
           cc.Move(transform.TransformDirection(dir) * Time.deltaTime);//需要乘以deltaTime
       }
   }
   else {//在空中的运动状态控制
       if (Input.GetKey("w"))
       {
           Vector3 zDir = transform.TransformDirection(Vector3.forward);
           if (Input.GetKey(KeyCode.LeftShift))
           {
               cc.Move(zDir * speed * Time.deltaTime * 2);
           }
           else
           {
               cc.Move(zDir * speed * Time.deltaTime);
           }
       }     
   }
}
}

MouseLook.cs
摄像机旋转带动角色旋转
//作用是当鼠标移动时,player跟着转向,player分为两部分构成:body和head两部分,body负责左右转,head负责上下转
//再body对象中,摄像机旋转类型为MouseX;
再head对象中,摄像机旋转类型为MouseY;

using UnityEngine;
using System.Collections;

public class MouseLook : MonoBehaviour {
public enum ERotationAxis//摄像机的旋转类型
{ 
    MouseXY,//水平和垂直方向的旋转
    MouseX,//只是X方向上的移动
    MouseY//Y方向上的移动

}
public float sensitivityX = 20.0f;//X方向上移动的灵敏度
public float sensitivityY = 15.0f;
public float minAngleY = -60.0f;//鼠标在Y轴方向移动摄像机角度观看范围
public float maxAngleY = 60.0f;
public ERotationAxis axis = ERotationAxis.MouseXY;
private float rotationY;
void Start () 
{
    if (GetComponent<Rigidbody>())
    {
        GetComponent<Rigidbody>().freezeRotation = true;
    }
}

void Update () 
{
    float x = Input.GetAxis("Mouse X");//鼠标的左右移动
    float y = Input.GetAxis("Mouse Y");//鼠标的上下移动
    switch (axis)
    {
   case ERotationAxis.MouseXY:
        float rotationX = transform.localEulerAngles.y + x * sensitivityX;
        rotationY += y * sensitivityY;
        rotationY = Mathf.Clamp(rotationY, minAngleY, maxAngleY);//夹值
        transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0);
        break;
  case ERotationAxis.MouseX:
        transform.Rotate(0,x*sensitivityX,0);//body执行这个
        break;
  case ERotationAxis.MouseY:
       rotationY += y * sensitivityY;
       rotationY = Mathf.Clamp(rotationY, minAngleY, maxAngleY);//夹值
       transform.localEulerAngles = new Vector3(-rotationY,                  transform.localEulerAngles.y, 0);//head执行这个
            //transform.Rotate(-y * sensitivityY, 0, 0);这个也能用
            break;
    }
}
}
第三人称视角

实现效果:点鼠标右键移动摄像机,player跟着移动;如果人物和摄像机之间被挡到,摄像机会跳到挡到点处;同样是摄像机带动人物旋转

unity移动视角 unity3d第一视角移动_右键_03


脚本一

ThirdPlayer.cs

using UnityEngine;
using System.Collections;

public class ThirdPlayer : MonoBehaviour {
    public CharacterController cc;
    public float moveSpeed = 3.0f;
    public Camera camera;
	// Use this for initialization
	void Start () {
	    cc=this.GetComponent<CharacterController>();
        camera=Camera.main;
        this.transform.rotation = camera.transform.rotation;//角色跟着相机旋转
	}
	
	// Update is called once per frame
	void Update () {
        float vx = Input.GetAxis("Horizontal") * moveSpeed;
        float vy = Input.GetAxis("Vertical")*moveSpeed;
        Vector3 cmEuler = camera.transform.eulerAngles;
        cmEuler.x = cmEuler.z = 0;
        this.transform.eulerAngles = cmEuler;
        cc.SimpleMove(transform.TransformDirection(new Vector3(vx,0,vy)));
	}
}

CameraFollow.cs
相机跟随脚本

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

public class CameraFollow : MonoBehaviour {
 public const float DISTANCE_DEAFULT = 8.0f;//默认主角和摄像机的距离
 private float distance = 0.0f;//运行时的距离
 private Transform transTarget;//摄像机跟随目标(主角)
 public float target_offsety = 0.5f;//盯着目标往上偏移值

 private Vector3 vLooker;//摄像机盯着的位置
 private Vector3 rotateXY;//保存X,Y方向的旋转,鼠标移动的时候会发生改变
 private float speedAngelX = 200;//x方向的旋转速度
 private float speedAngelY = 100;//y方向的旋转速度
 public float minAngleAtY = -90.0f;       //摄像机在Y方向的角度的最小值
 public float maxAngleAtY = 90.0f;       //摄像机在Y方向的角度的最大值
 Quaternion rotation;//摄像机的旋转角度

void Start () {
     distance = DISTANCE_DEAFULT;
     transTarget = GameObject.FindGameObjectWithTag("Player").transform;
     vLooker = new Vector3(transTarget.position.x, transTarget.position.y + target_offsety, transTarget.position.z);//
     rotation = transform.rotation;
     rotateXY.y = transform.eulerAngles.x;//摄像机转x欧拉角,会发现主相机上下动
     rotateXY.x = transform.eulerAngles.y;//摄像机转y欧拉角,会发现相机左右动
     transform.position = transTarget.position + rotation * Vector3.back * distance; //四元数乘以向量的意义,重点
     transform.LookAt(vLooker);//一直看着某个点
}
 void Update()
 {
     vLooker = transTarget.position;
     vLooker.y += 0.5f;
    // transform.position = transTarget.position + rotation * Vector3.back * distance; ;
     //按下鼠标右键
     if (Input.GetMouseButton(1))//0:左键,1:右键,2:中键
     {
         float x = Input.GetAxis("Mouse X");//鼠标在X方向上的移动,控制Y轴的旋转
         float y = Input.GetAxis("Mouse Y");//鼠标在Y方向上的移动,控制X轴的旋转
         rotateXY.x += speedAngelX * Time.deltaTime * x;//容易理解鼠标左右,上下移动时候的数据改变
         rotateXY.y -= speedAngelY * Time.deltaTime * y;
         rotateXY.y = Mathf.Clamp(rotateXY.y, minAngleAtY, maxAngleAtY);//在最小值和最大值之间取值,因为抬头低头总会有角度限制的
         rotation = Quaternion.Euler(rotateXY.y, rotateXY.x, 0);//值又交换回来了。
         transform.rotation = rotation;
     }
     transform.position = transTarget.position + rotation * Vector3.back * distance;
}
 void LateUpdate()//射线的碰撞检测
 {
     if (transTarget)
     {
         //vLooker = transTarget.position;
         //vLooker.y += 0.5f;
         //transform.position = transTarget.position + rotation * Vector3.back * distance; ;
         按下鼠标右键
         //if (Input.GetMouseButton(1))//0:左键,1:右键,2:中键
         //{
         //    float x = Input.GetAxis("Mouse X");//鼠标在X方向上的移动,控制Y轴的旋转
         //    float y = Input.GetAxis("Mouse Y");//鼠标在Y方向上的移动,控制X轴的旋转
         //    rotateXY.x += speedAngelX * Time.deltaTime * x;
         //    rotateXY.y -= speedAngelY * Time.deltaTime * y;
         //    rotateXY.y = Mathf.Clamp(rotateXY.y, minAngleAtY, maxAngleAtY);//在最小值和最大值之间取值
         //    rotation = Quaternion.Euler(rotateXY.y, rotateXY.x, 0);
         //    transform.rotation = rotation;
         //    transform.position = transTarget.position + rotation * Vector3.back * distance; ;
         //}
  RaycastHit[] hits = Physics.RaycastAll(new Ray(vLooker, (transform.position - vLooker).normalized));
         distance = DISTANCE_DEAFULT;
         List<RaycastHit> listHits=new List<RaycastHit>(hits);
         foreach (RaycastHit hit in listHits)
         {
             if (hit.collider.gameObject.tag == "Player")
             {
                 listHits.Remove(hit);
                 break;
             }
         }
         if (listHits.Count > 0)
         {
             RaycastHit stand = listHits[0];//剔除人物身上点之后,距离人最近的点
             foreach (RaycastHit hit in listHits)
             {
                 //if (hit.collider.gameObject.tag == "terrain")
                 //{
                 //    if (hit.distance < stand.distance)
                 //    {
                 //        stand = hit;
                 //    }
                 //}
                 if (hit.distance < stand.distance)
                 {
                     stand = hit;
                 }
             }
             Debug.Log(stand.point + " " + stand.collider.gameObject.tag);
             string tag = stand.collider.gameObject.tag;
             distance = Vector3.Distance(stand.point, vLooker);
             if (distance > DISTANCE_DEAFULT)
             {
                 distance = DISTANCE_DEAFULT;
             }
         }
         Debug.DrawRay(vLooker, transform.position - vLooker, Color.red);
         Vector3 position = transTarget.position + rotation * Vector3.back * distance;
         position.y += 1.5f;//为了不让摄像机看到地下的东西
         transform.position = Vector3.Lerp(transform.position, position, 0.3f);
         transform.LookAt(vLooker);
     }
 }
}