之前写过一个旋转相机的脚本,这个比那个增加了相机会移动到遮挡物体的前面。
TODO:如果距离物体过近的话,物体会改变成半透明。
using UnityEngine;
//第三人称相机.
public class ThirdPersonOrbitCamBasic : MonoBehaviour
{
public Transform player; // 玩家transform.
public Vector3 pivotOffset = new Vector3(0.0f, 1.0f, 0.0f); // 相机锚点.
public Vector3 camOffset = new Vector3(0.4f, 0.5f, -2.0f); // 相机相对玩家位置.
public float smooth = 10f; // 相机平滑值.
public float horizontalAimingSpeed = 6f; // 水平旋转速度.
public float verticalAimingSpeed = 6f; // 垂直旋转速度.
public float maxVerticalAngle = 30f; // 相机最大垂直角度.
public float minVerticalAngle = -60f; // 相机最小垂直角度.
public string XAxis = "Analog X"; // 水平轴名称.
public string YAxis = "Analog Y"; // 垂直轴名称.
private float angleH = 0;
private float angleV = 0;
private Transform cam; // 相机Transform.
private Vector3 relCameraPos; // 相机当前相对于物体的坐标.
private float relCameraPosMag; // 相机当前与物体的距离.
private Vector3 smoothPivotOffset;
private Vector3 smoothCamOffset;
private Vector3 targetPivotOffset;
private Vector3 targetCamOffset;
private float defaultFOV; // 相机默认FOV.
private float targetFOV; // 相机要修改成的目标FOV.
private float targetMaxVerticalAngle; // 自定义相机最大垂直角度.
// 获取相机垂直旋转角度值.
public float GetH { get { return angleH; } }
void Awake()
{
cam = transform;
// 设置相机默认位置.
cam.position = player.position + Quaternion.identity * pivotOffset + Quaternion.identity * camOffset;
cam.rotation = Quaternion.identity;
// 获取相机相对物体位置, 准备做射线检测.
relCameraPos = transform.position - player.position;
relCameraPosMag = relCameraPos.magnitude - 0.5f;
// 设置默认值.
smoothPivotOffset = pivotOffset;
smoothCamOffset = camOffset;
defaultFOV = cam.GetComponent<Camera>().fieldOfView;
angleH = player.eulerAngles.y;
ResetTargetOffsets ();
ResetFOV ();
ResetMaxVerticalAngle();
}
void Update()
{
// 相机环绕输入.
// 鼠标输入:
angleH += Mathf.Clamp(Input.GetAxis("Mouse X"), -1, 1) * horizontalAimingSpeed;
angleV += Mathf.Clamp(Input.GetAxis("Mouse Y"), -1, 1) * verticalAimingSpeed;
// 摇杆输入:
angleH += Mathf.Clamp(Input.GetAxis(XAxis), -1, 1) * 60 * horizontalAimingSpeed * Time.deltaTime;
angleV += Mathf.Clamp(Input.GetAxis(YAxis), -1, 1) * 60 * verticalAimingSpeed * Time.deltaTime;
// 垂直旋转限制.
angleV = Mathf.Clamp(angleV, minVerticalAngle, targetMaxVerticalAngle);
// 设置相机旋转.
Quaternion camYRotation = Quaternion.Euler(0, angleH, 0);
Quaternion aimRotation = Quaternion.Euler(-angleV, angleH, 0);
cam.rotation = aimRotation;
// 设置相机FOV.
cam.GetComponent<Camera>().fieldOfView = Mathf.Lerp (cam.GetComponent<Camera>().fieldOfView, targetFOV, Time.deltaTime);
// 碰撞检测 检查是否有物体夹在相机和物体中间.
// 如果碰到障碍物,就向物体方向移动0.5再进行一次检测,只到中间没有障碍物为止.
Vector3 baseTempPosition = player.position + camYRotation * targetPivotOffset;
Vector3 noCollisionOffset = targetCamOffset;
for(float zOffset = targetCamOffset.z; zOffset <= 0; zOffset += 0.5f)
{
noCollisionOffset.z = zOffset;
if (DoubleViewingPosCheck (baseTempPosition + aimRotation * noCollisionOffset, Mathf.Abs(zOffset)) || zOffset == 0)
{
break;
}
}
// 设置相机位置.
smoothPivotOffset = Vector3.Lerp(smoothPivotOffset, targetPivotOffset, smooth * Time.deltaTime);
smoothCamOffset = Vector3.Lerp(smoothCamOffset, noCollisionOffset, smooth * Time.deltaTime);
cam.position = player.position + camYRotation * smoothPivotOffset + aimRotation * smoothCamOffset;
}
// 把相机设置到自定义位置.
public void SetTargetOffsets(Vector3 newPivotOffset, Vector3 newCamOffset)
{
targetPivotOffset = newPivotOffset;
targetCamOffset = newCamOffset;
}
// 重置相机到初始值.
public void ResetTargetOffsets()
{
targetPivotOffset = pivotOffset;
targetCamOffset = camOffset;
}
// 设置相机的FOV.
public void SetFOV(float customFOV)
{
this.targetFOV = customFOV;
}
// 重置相机FOV.
public void ResetFOV()
{
this.targetFOV = defaultFOV;
}
// 设置相机最大垂直旋转角度.
public void SetMaxVerticalAngle(float angle)
{
this.targetMaxVerticalAngle = angle;
}
// 重置相机最大旋转角度.
public void ResetMaxVerticalAngle()
{
this.targetMaxVerticalAngle = maxVerticalAngle;
}
// 两个方向碰撞检测.
bool DoubleViewingPosCheck(Vector3 checkPos, float offset)
{
float playerFocusHeight = player.GetComponent<CapsuleCollider> ().height * 0.75f;
return ViewingPosCheck (checkPos, playerFocusHeight) && ReverseViewingPosCheck (checkPos, playerFocusHeight, offset);
}
// 相机到物体碰撞检测.
bool ViewingPosCheck (Vector3 checkPos, float deltaPlayerHeight)
{
Vector3 target = player.position + (Vector3.up * deltaPlayerHeight);
if (Physics.SphereCast(checkPos, 0.2f, target - checkPos, out RaycastHit hit, relCameraPosMag))
{
if(hit.transform != player && !hit.transform.GetComponent<Collider>().isTrigger)
{
return false;
}
}
return true;
}
// 物体到相机碰撞检测.
bool ReverseViewingPosCheck(Vector3 checkPos, float deltaPlayerHeight, float maxDistance)
{
Vector3 origin = player.position + (Vector3.up * deltaPlayerHeight);
if (Physics.SphereCast(origin, 0.2f, checkPos - origin, out RaycastHit hit, maxDistance))
{
if(hit.transform != player && hit.transform != transform && !hit.transform.GetComponent<Collider>().isTrigger)
{
return false;
}
}
return true;
}
public float GetCurrentPivotMagnitude(Vector3 finalPivotOffset)
{
return Mathf.Abs ((finalPivotOffset - smoothPivotOffset).magnitude);
}
}