It can be rotated and zoomed, and the displacement when detecting the collision to try to keep the object from being occluded. Not much to say, go directly to the code
using UnityEngine; using UnityStandardAssets.CrossPlatformInput; [AddComponentMenu("Zetan/Third Person Camera Follow")] public class CameraFollow : MonoBehaviour { public Transform target; public Vector3 headOffset = Vector3.zero; public bool smooth; public float smoothLevel = 0.5f; Vector3 direction; public float rotateSpeed = 10.0f; public float zoomSpeed = 5f; public float minDistance = 3.0f; public float maxDistance = 15.0f; public float maxLookUpAngle = 80.0f; public float maxLookDownAngle = 30.0f; [SerializeField] float OriginDistance; [SerializeField] float currentDistance; Vector3 visibleEuler; // Use this for initialization void Start() { ResetView(); } // Update is called once per frame void Update() { visibleEuler = ConvertEulerAngle(transform.rotation.eulerAngles); } private void LateUpdate() { float h = CrossPlatformInputManager.GetAxis("Mouse X"); float v = CrossPlatformInputManager.GetAxis("Mouse Y"); float zoom = CrossPlatformInputManager.GetAxis("Mouse ScrollWheel"); Translate(zoom); Rotate(h, v); } void Translate(float zoom) { OriginDistance -= zoom * zoomSpeed; OriginDistance = Mathf.Clamp(OriginDistance, minDistance, maxDistance); RaycastHit hit; if (Physics.Raycast(target.position + headOffset, transform.position - target.position - headOffset, out hit, OriginDistance, ~(1 << LayerMask.NameToLayer("Water") | 1 << LayerMask.NameToLayer("Player")), QueryTriggerInteraction.Ignore))//The detection layer is changed according to requirements { currentDistance = hit.distance; } else { currentDistance = OriginDistance; } Vector3 disOffset = direction.normalized * currentDistance; if(smooth)transform.position = Vector3.Lerp(transform.position, target.position + headOffset + disOffset, smoothLevel);//Smooth movement, but the cumulative difference will cause the camera to gradually return to a certain perspective, with a slight jitter else transform.position = target.position + headOffset + disOffset;//There is a slight freeze when rotating transform.LookAt(target); } void Rotate(float h, float v) { float finallyRotateV = v * rotateSpeed; if (finallyRotateV + visibleEuler.x >= maxLookUpAngle) { finallyRotateV = visibleEuler.x + finallyRotateV - maxLookUpAngle; } else if (finallyRotateV + visibleEuler.x <= -maxLookDownAngle) { finallyRotateV = visibleEuler.x + finallyRotateV + maxLookDownAngle; } //rotate left and right transform.RotateAround(target.position + headOffset, transform.up, h * rotateSpeed); // rotate up and down transform.RotateAround(target.position + headOffset, transform.right, -finallyRotateV); transform.LookAt(target.position + headOffset); direction = (transform.position - target.position - headOffset).normalized; } public float ConvertAngle(float value) { float angle = value - 180; if (angle > 0) return angle - 180; return angle + 180; } public Vector3 ConvertEulerAngle(Vector3 euler) { return new Vector3(ConvertAngle(euler.x), ConvertAngle(euler.y), ConvertAngle(euler.z)); } public void ResetView() { if(minDistance > maxDistance) { maxDistance += minDistance; minDistance = maxDistance - minDistance; maxDistance -= minDistance; } direction = -target.forward; Vector3 disOffset = direction * (minDistance + maxDistance) / 2; transform.position = target.position + headOffset + disOffset; OriginDistance = disOffset.magnitude; } private void OnDrawGizmos() { Gizmos.color = Color.red; Gizmos.DrawLine(target.position + headOffset, transform.position); Gizmos.color = Color.yellow; Gizmos.DrawWireSphere(target.position + headOffset, minDistance); Gizmos.DrawLine(target.position + headOffset + target.forward * minDistance, target.position + headOffset + target.forward * maxDistance); Gizmos.DrawLine(target.position + headOffset - target.forward * minDistance, target.position + headOffset - target.forward * maxDistance); Gizmos.DrawLine(target.position + headOffset + target.up * minDistance, target.position + headOffset + target.up * maxDistance); Gizmos.DrawLine(target.position + headOffset - target.up * minDistance, target.position + headOffset - target.up * maxDistance); Gizmos.DrawLine(target.position + headOffset + target.right * minDistance, target.position + headOffset + target.right * maxDistance); Gizmos.DrawLine(target.position + headOffset - target.right * minDistance, target.position + headOffset - target.right * maxDistance); Gizmos.DrawWireSphere(target.position + headOffset, maxDistance); } }