using System; using JetBrains.Annotations; using UnityEngine; namespace Camera { public class CameraFollow : MonoBehaviour { [CanBeNull] public static CameraFollow Current; private Transform _followTarget; private float _defaultYaw; private bool _enableMove; private float _height; [CanBeNull] public Transform followTarget { get => _followTarget; set { if (_followTarget == value) return; _followTarget = value; if (_followTarget != null) OnFollowTargetChanged(value); else OnFollowTargetLost(); } } private void Awake() { _defaultYaw = rotationYaw.eulerAngles.y; if (Current != null) Debug.LogWarning("Duplicate CameraFollow Found!"); Current = this; followTarget = defaultFollowTarget; } [Header("Parameters")] [SerializeField] private bool enableYaw; [SerializeField] private Transform defaultFollowTarget; [SerializeField] [Range(0.015f, 1f)] private float yawRotationLerp; [SerializeField] [Range(0.015f, 1f)] private float positionLerp; [SerializeField] [Range(0.015f, 1f)] private float heightLerp; [SerializeField] private LayerMask heightCheckLayerMask; [Header("Bindings")] [SerializeField] private Transform rotationYaw; [SerializeField] private Transform rotationPitch; [SerializeField] private Transform positionCamera; [SerializeField] private Transform positionHeight; private void OnFollowTargetChanged([CanBeNull] Transform target) { Debug.Log($"Follow target: {target?.name}"); _enableMove = target != null; } private void OnFollowTargetLost() { Debug.Log("Follow target lost"); _enableMove = false; } private void FixedUpdate() { FixedUpdateHeight(); if (_enableMove) { try { FixedUpdateMoveCamera(); } catch (NullReferenceException) { OnFollowTargetLost(); } } } private void FixedUpdateMoveCamera() { var transformYaw = _followTarget.rotation.eulerAngles.y; var transformPosition = _followTarget.position; var targetYaw = transformYaw; var targetYawRotation = Quaternion.Euler(0, enableYaw ? targetYaw : _defaultYaw, 0); var targetPosition = new Vector3(transformPosition.x, 0, transformPosition.z); transform.position = Vector3.Lerp(transform.position, targetPosition, positionLerp); rotationYaw.rotation = Quaternion.Lerp(rotationYaw.rotation, targetYawRotation, yawRotationLerp); positionHeight.position = new Vector3( transformPosition.x, Mathf.Lerp(positionHeight.position.y, _height, heightLerp), transformPosition.z ); } private void FixedUpdateHeight() { var transformPosition = transform.position; var start = transformPosition + Vector3.up * 100; var end = transformPosition + Vector3.down * 100; Physics.Linecast(start, end, out RaycastHit hit, heightCheckLayerMask); if (hit.collider == null) _height = transformPosition.y; else _height = hit.point.y; } private void OnDestroy() { if (Current == this) Current = null; } } }