之前写过一个旋转相机的脚本,这个比那个增加了相机会移动到遮挡物体的前面。
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); } }