U3D摄像机视角
U3D的可以通过设置摄像机来实现第一人称,第三人称等不同游戏视角。
1第一人称视角
四元数转化成欧拉角 Vector3 v3=transform.rotation.eulerAngles;
欧拉角转换成四元数 Quaternion rotation = Quaternion.Euler(v3);
需要实现的效果:鼠标上下左右移动镜头跟着移动;人物移动和跳跃(这里我们人物移动使用的是CharacterController组件的Move和SimpleMove方法);
//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跟着移动;如果人物和摄像机之间被挡到,摄像机会跳到挡到点处;同样是摄像机带动人物旋转
脚本一
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);
}
}
}