使用方法 |
介绍 |
Vector3.Lerp | 修改float值得到A,B两个值的插值 |
方法思路
先获取摄像机和玩家的移动向量,从移动向量中得到距离从而用Lerp得到5个在移动向量中的 点储存进摄像机数组中,再从每个点判断该点射出一点射线是否可以射中玩家碰撞体再从射 线碰撞检测器中得到,如果射中的是玩家然后让相机插值移动过去。
注意
使用Lerp获得线段所有点的时候使用的点是摄像机观察线段的顶点和终点,如果使用摄像机坐标和玩家坐标的话可能会出现摄像机卡顿(玩家在摄像机范围内摄像机不会将玩家聚焦) 使用顶点和终点的话摄像机每帧的顶点和终点都会改变所以会一直动态改变摄像角度
借用别的博主实例(Vector3详情)
voidStart () {undefined
print(Mathf.Lerp(0.0f,100.0f, 0.0f).ToString());
print(Mathf.Lerp(0.0f,100.0f, 0.1f).ToString());
print(Mathf.Lerp(0.0f,100.0f, 0.2f).ToString());
print(Mathf.Lerp(0.0f,100.0f, 0.3f).ToString());
print(Mathf.Lerp(0.0f,100.0f, 0.4f).ToString());
print(Mathf.Lerp(0.0f,100.0f, 0.5f).ToString());
print(Mathf.Lerp(0.0f,100.0f, 0.6f).ToString());
print(Mathf.Lerp(0.0f,100.0f, 0.7f).ToString());
print(Mathf.Lerp(0.0f,100.0f, 0.8f).ToString());
print(Mathf.Lerp(0.0f,100.0f, 0.9f).ToString());
print(Mathf.Lerp(0.0f,100.0f, 1.0f).ToString());
}
得到的效果图
操作代码
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
[Header("总档位数量")]
public int gear = 5;
[Header("移动速度")]
public float moveSpeed = 3f;
[Header("旋转速度")]
public float turnSpeed = 2f;
// 跟随的目标
private Transform followTarget;
// 摄像机跟随目标的方向向量
private Vector3 dir;
// 射线碰撞检测器
private RaycastHit hit;
private void Awake()
{
followTarget = GameObject.FindWithTag(GameConsts.PLAYER).transform;
}
private void Start()
{
// 计算初始方向向量
dir = followTarget.position + Vector3.up * GameConsts.PLAYER_BODY_OFFSET -
transform.position;
}
private void Update()
{
// 最好位置
Vector3 bestPos = followTarget.position + Vector3.up *
GameConsts.PLAYER_BODY_OFFSET - dir;
// 最差位置
Vector3 worstPos = followTarget.position + Vector3.up *
GameConsts.PLAYER_BODY_OFFSET
+ Vector3.up * (dir.magnitude + GameConsts.WATCH_OFFSET);
// 观察点数组
Vector3[] watchPositions = new Vector3[gear];
// 设置观察点数组的起点
watchPositions[0] = bestPos;
// 设置观察点数组的终点
watchPositions[watchPositions.Length - 1] = worstPos;
// 设置中间的观察点坐标
for (int i = 1; i < watchPositions.Length-1; i++)
{
// 求中间每个点的坐标
watchPositions[i] = Vector3.Lerp(bestPos, worstPos, (float)i / (gear - 1));
}
// 从数组中挑选尽可能好的点,且可以看到玩家
// 最合适的点
Vector3 fitPos = bestPos;
// 从0开始遍历所有的点
for (int i = 0; i < watchPositions.Length; i++)
{
// 这个点可以看到玩家
if (CanSeeTarget(watchPositions[i]))
{
// 该点就是最合适的点
fitPos = watchPositions[i];
// 跳出循环,不再去判断后面的点了
break;
}
}
// 插值移动过去
transform.position = Vector3.Lerp(transform.position, fitPos, moveSpeed *
Time.deltaTime);
// 摄像机低头看向玩家
Vector3 lookDir = followTarget.position + Vector3.up *
GameConsts.PLAYER_BODY_OFFSET - transform.position;
// 转换成四元数
Quaternion targetQua = Quaternion.LookRotation(lookDir);
// Lerp过去
transform.rotation = Quaternion.Lerp(transform.rotation, targetQua, turnSpeed *
Time.deltaTime);
// 欧拉角修正
// 获取当前摄像机的欧拉角
Vector3 eularAngles = transform.eulerAngles;
// 设置,y和z都为0,保证视角不会偏移
eularAngles = new Vector3(eularAngles.x, 0, 0);
// 修正后,设置回去
transform.eulerAngles = eularAngles;
}
private bool CanSeeTarget(Vector3 pos)
{
// 此时的观察点指向玩家的方向向量
Vector3 currentDir = followTarget.position + Vector3.up *
GameConsts.PLAYER_BODY_OFFSET - pos;
// 射线检测到了碰撞体
if (Physics.Raycast(pos, currentDir, out hit))
{
// 射线检测到的碰撞体是玩家
if (hit.collider.CompareTag(GameConsts.PLAYER))
{
// 说明中间没有障碍物,可以看见玩家
return true;
}
}
// 其他情况都是,看不到玩家
return false;
}
}