using System; using UnityEngine; using UnityEngine.UIElements; [System.Serializable] public class CameraFollowSetting { [Header("位置跟随")] public Vector3 localOffset = new Vector3(0, 0, 0); public float positionSmoothTime = 0.15f; public float verticalSmoothTime = 0.1f; public float maxFollowSpeed = 500f; public bool usePositionPrediction = true; public float predictionFactor = 0.15f; [Header("视角控制")] public bool isTPS = true; public Vector3 TPS_localOffset = new Vector3(0, 0, 0); public float rotationSmoothTime = 0.1f; public float pitchSpeed = 200f; public float minPitch = -30f; public float maxPitch = 80f; [Header("目标转向")] public bool enableTargetRotationFollow = true; public float targetRotationSmoothTime = 0.2f; public float maxRotationSpeed = 360f; } public class ThirthCamera : MonoBehaviour { public Transform target; public CameraFollowSetting settings; // 位置跟踪 private Vector3 positionVelocity; private Vector3 lastTargetPosition; private Vector3 targetVelocity; // 旋转跟踪 private float yRotationVelocity; private float targetRotationVelocity; private float currentYRotation; private float currentPitch; private Rigidbody targetRigidbody; void Start() { // 保持编辑器设置的初始位置和旋转 float offsetX = MathF.Abs(transform.position.x - target.position.x); float offsetY = MathF.Abs(transform.position.y - target.position.y); float offsetZ = MathF.Abs(transform.position.z - target.position.z); if (offsetX > offsetZ) { settings.localOffset = new Vector3(0,offsetY,-offsetX); } else if(offsetX < offsetZ) { settings.localOffset = new Vector3(0, offsetY, -offsetZ); } Debug.Log(offsetX + ":" + offsetY + ":" + offsetZ); Debug.Log(transform.position - target.position); settings.TPS_localOffset = settings.localOffset; currentYRotation = transform.eulerAngles.y; currentPitch = transform.eulerAngles.x; if (target != null) { targetRigidbody = target.GetComponent<Rigidbody>(); if (targetRigidbody != null) { targetRigidbody.interpolation = RigidbodyInterpolation.Interpolate; } lastTargetPosition = target.position; } } void LateUpdate() { if (target == null) return; HandlePersonTransformation(); UpdateTargetVelocity(); HandleCameraInput(); UpdateCamera(); } void HandlePersonTransformation() { if (!settings.isTPS) { settings.localOffset = new Vector3(0, 0, 0); } else { settings.localOffset = settings.TPS_localOffset; } } void UpdateTargetVelocity() { targetVelocity = (target.position - lastTargetPosition) / Time.deltaTime; lastTargetPosition = target.position; } void HandleCameraInput() { if (Input.GetMouseButton(0)) { float mouseX = Input.GetAxis("Mouse X"); float mouseY = Input.GetAxis("Mouse Y"); currentYRotation += mouseX * settings.pitchSpeed * Time.deltaTime; currentPitch = Mathf.Clamp( currentPitch - mouseY * settings.pitchSpeed * Time.deltaTime, settings.minPitch, settings.maxPitch ); } } void UpdateCamera() { UpdatePosition(); UpdateRotation(); SyncTargetRotation(); } void UpdatePosition() { if (!settings.isTPS) { // 第一人称模式下直接设置摄像机位置,禁用平滑和预测 transform.position = target.TransformPoint(settings.localOffset); return; } Vector3 predictedPosition = GetPredictedPosition(); ApplyAxisSmoothing(predictedPosition); } Vector3 GetPredictedPosition() { Vector3 baseOffset = target.TransformPoint(settings.localOffset); if (settings.usePositionPrediction) { Vector3 effectiveVelocity = targetRigidbody != null ? targetRigidbody.velocity : targetVelocity; return baseOffset + effectiveVelocity * settings.predictionFactor; } return baseOffset; } void ApplyAxisSmoothing(Vector3 targetPos) { // 水平方向 Vector3 horizontalTarget = new Vector3( targetPos.x, transform.position.y, targetPos.z ); horizontalTarget = Vector3.SmoothDamp( transform.position, horizontalTarget, ref positionVelocity, settings.positionSmoothTime, settings.maxFollowSpeed ); // 垂直方向 Vector3 verticalTarget = new Vector3( transform.position.x, targetPos.y, transform.position.z ); verticalTarget = Vector3.SmoothDamp( transform.position, verticalTarget, ref positionVelocity, settings.verticalSmoothTime, settings.maxFollowSpeed ); // 合并结果 transform.position = new Vector3( horizontalTarget.x, verticalTarget.y, horizontalTarget.z ); } void UpdateRotation() { float smoothedY = Mathf.SmoothDampAngle( transform.eulerAngles.y, currentYRotation, ref yRotationVelocity, settings.rotationSmoothTime ); transform.rotation = Quaternion.Euler( currentPitch, smoothedY, 0 ); } void SyncTargetRotation() { if (!settings.enableTargetRotationFollow) return; float targetDesiredY = currentYRotation; float currentTargetY = target.eulerAngles.y; float smoothedTargetY = Mathf.SmoothDampAngle( currentTargetY, targetDesiredY, ref targetRotationVelocity, settings.targetRotationSmoothTime, settings.maxRotationSpeed ); ApplyTargetRotation(smoothedTargetY); } void ApplyTargetRotation(float yRotation) { Quaternion newRotation = Quaternion.Euler(0, yRotation, 0); if (targetRigidbody != null) { targetRigidbody.MoveRotation(newRotation); } else { target.rotation = newRotation; } } } |