原理
首先,将相机与角色之间的距离分为多个等级,每次手动调整相机距离后,就记录偏好的距离等级。从相机处向人发射一条射线,如果检测到相机与人之间有物体,就把相机自动往前移动一级,直到相机不再被遮挡为止。随后计算偏好距离等级的相机位置是否被遮挡,如果没有被遮挡了,就恢复到原来的相机距离。
效果
代码
/*
相机距离分级调整
取初始距离为单位长度,随后每次调整都以此为单位
用单位向量乘以单位长度即可得到位移矢量
*/
//单位长度
float unit;
void ScrollToAdjustView()
{
if (Input.GetAxis("Mouse ScrollWheel") > 0)
{
ViewPlus();
preferdLevel = currentLevel;
}
else if (Input.GetAxis("Mouse ScrollWheel") < 0)
{
ViewMinus();
preferdLevel = currentLevel;
}
}
void ViewPlus()
{
if (RelativePosition.magnitude <= MinViewDistance) return;
transform.Translate(-RelativePosition.normalized * unit, Space.World);
RelativePosition = transform.position - focus.position;
currentLevel--;
}
void ViewMinus()
{
if (RelativePosition.magnitude >= MaxViewDistance) return;
transform.Translate(RelativePosition.normalized * unit, Space.World);
RelativePosition = transform.position - focus.position;
currentLevel++;
}
/*-----------------视野遮挡处理------------------*/
/*
如果视野被遮挡,就逐级拉近相机的距离
如果原机位不再被遮挡,则恢复原机位
*/
//当前视角级别
int currentLevel = 1;
//偏好视野级别
int preferdLevel = 1;
//是否需要恢复原机位
bool resumable = false;
void OcclusionJudge()
{
if (Physics.Raycast(transform.position, -RelativePosition.normalized, RelativePosition.magnitude - unit)) //如果机位被遮挡
{
resumable = true;
while (Physics.Raycast(transform.position, -RelativePosition.normalized, RelativePosition.magnitude - unit))
{
ViewPlus();
}
}
if (!resumable) return; //如果不需要恢复
Vector3 PositionToResume = focus.position + RelativePosition.normalized * unit * preferdLevel; //计算偏好距离所在位置
if (resumable && !Physics.Raycast(PositionToResume, -RelativePosition.normalized, (preferdLevel - 1) * unit)) //原机位没被遮挡,恢复原位
{
while (currentLevel != preferdLevel)
{
ViewMinus();
}
resumable = false;
}
}