一、实现效果
二、函数介绍
实现这个效果主要运用到Vector3的Lerp函数以及Quaternion的Slerp函数、LookRotation函数。
1.Lerp
有时,我们在做游戏时会发现有些跟随动作不够圆滑或者需要一个缓冲的效果,这时,一般会考虑到插值。所以对插值的理解是必需的。(比如摄像机跟随主角)
插值是数学上的一个概念,在这里用公式表示就是:from + (to - from) * t;这也就是Lerp的返回值(用这个公式分别算出x,y,z)。
static function Lerp (from : Vector3, to : Vector3, t : float) : Vector3
from 是起始的位置,to是目标位置,按照数字t在from到to之间插值。这句话比较难理解,下面举个例子。
这和我们用公式算出来的如出一辙。现在我们再看一个具体的例子
//在1秒时间动画位置移动从from开始到to结束。(这是官方的例子)
using UnityEngine;
using System.Collections;
public class example : MonoBehaviour {
public Transform start;
public Transform end;
void Update() {
transform.position = Vector3.Lerp(start.position, end.position, Time.time);
}
}
位置移动从start开始到end结束,这好理解,但是为什么是1秒呢?
Time.time是从0开始随时间增加的。
例1的t是一个固定的值,返回一个固定的向量。此时t是变量,在不断增加。那么:
当Time.time = 0时--->transform.position = start.position,位置没有变化;
当Time.time从0趋向于1时--->transform.position 不断接近start.position,该脚本是挂在start物体上的,所以start会不断靠近end。
那么问题来了,当Time.time>1的时候,会怎么样呢?额(⊙o⊙)…我们说不会。
由上面的公式from + (to - from) * t可知,当t=1时,to - from = 0,此时t就无效了。
例1是从静态角度看,例2是从动态角度看的(两个变量,一个是时间在变化,一个是位置在变化)。
想一想例2,如果不是Time.time,而是0.5,会怎么样?(只看一个变量)
由图易知:A物体会不断以0.5的比例无限接近于B
2.LookRotation
Quaternion.LookRotation注释旋转。创建一个旋转,沿着forward(z轴)并且头部沿着upward(y轴)的约束注视,也就是建立一个旋转,使z轴朝着view,y轴朝着up
3.Slerp
Slerp球形插值,通过t值from向to之间插值,参数取值范围【0,1】
三、如何实现
CameraMove脚本文件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraMove : MonoBehaviour
{
//设置参数
//摄像机要看人物的高度是多少
public float bodyHeight;
//相机相对人物每个方向所偏移的量
public Vector3 offsetPos = Vector3.zero;
//相机相对于目标计算出来的坐标位置
public Vector3 cameraPos;
//相机相对于目标计算出来旋转的四元素
public Quaternion cameraRoration;
///目标的位置
public Transform target;
//相机的移动速度和旋转速度
public float moveSpeed = 4;
public float rorationSpeed = 4;
private void Start()
{
print($"transform.position:{transform.position}");//相机起始的大概位置
}
private void Update()
{
//更新相机的位置和旋转角度
//target.forward*z向当前z轴移动坐标,Vector3.forward *z。是相对于世界坐标向z轴移动坐标
cameraPos = target.position + target.forward * offsetPos.z +
target.right * offsetPos.x+Vector3.up*offsetPos.y;
//相机需要线性变化的过程
transform.position = Vector3.Lerp(transform.position,cameraPos,Time.deltaTime*moveSpeed);
//第三个参数表示进度变化(0-1)到1的时候到达了目的地。以后在增加会一直在目标点不会移动了,
//如果每一帧的进度值越大越快
cameraRoration = Quaternion.LookRotation(target.position + Vector3.up * bodyHeight - cameraPos);
//print($"bodyHeight:{bodyHeight}");
//让角度也有线性变化的过程
transform.rotation = Quaternion.Slerp(transform.rotation, cameraRoration, Time.deltaTime * rorationSpeed);
}
//改变目标的方法
public void updateTarget(Transform targetTrans)
{
//在选择完场景后,跳转对应场景,在heropoint脚本中通过获取当前的主摄像机的组件来对应获取到挂在主摄像机上的脚本,
//通过点的方式可以调用updateTarget方法,把当前克隆的人物赋值给当前的target。
target = targetTrans;
}
}
heroPoint脚本文件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class heroPoint : MonoBehaviour
{
// 拿到当前的英雄信息
RoleInfo nowRoleInfo;
//当前目标
GameObject target;
private void Awake()
{
nowRoleInfo = GameDataMgr.Instance.playerData.selectedRole;
}
void Start()
{
if (Resources.Load<GameObject>(nowRoleInfo.res) != null)
{
//克隆英雄
target = Instantiate(Resources.Load<GameObject>(nowRoleInfo.res),this.transform.position,this.transform.rotation);
}
//拿到相机
Camera.main.transform.GetComponent<CameraMove>().updateTarget(target.transform);
}
}
heroPoint脚本文件实现的是,在场景中有一个heroPoint点位。当跳转场景的时候会自动加载这个点位,同时也要加载挂载的脚本文件,克隆好角色后,调用CameraMove脚本文件的updateTarget方法,将克隆的角色赋值给CameraMove的target。
需要注意的是,transform.position表示的是当前脚本文件所挂载到哪个物体的位置。