using UnityEngine; namespace Streamingle.Utils { /// /// 타겟 오브젝트를 부드럽게 따라가는 컴포넌트 /// public class SmoothFollow : MonoBehaviour { [Header("Target")] [Tooltip("따라갈 대상 Transform")] public Transform target; [Header("Follow Settings")] [Tooltip("위치 따라가기 활성화")] public bool followPosition = true; [Tooltip("회전 따라가기 활성화")] public bool followRotation = false; [Header("Smoothing")] [Tooltip("위치 보간 속도 (낮을수록 더 부드럽게)")] [Range(0.01f, 20f)] public float positionSmoothSpeed = 5f; [Tooltip("회전 보간 속도 (낮을수록 더 부드럽게)")] [Range(0.01f, 20f)] public float rotationSmoothSpeed = 5f; [Header("Offset")] [Tooltip("타겟으로부터의 위치 오프셋 (로컬 기준)")] public Vector3 positionOffset = Vector3.zero; [Tooltip("타겟으로부터의 회전 오프셋")] public Vector3 rotationOffset = Vector3.zero; [Header("Constraints")] [Tooltip("X축 위치 고정")] public bool freezePositionX = false; [Tooltip("Y축 위치 고정")] public bool freezePositionY = false; [Tooltip("Z축 위치 고정")] public bool freezePositionZ = false; private Vector3 _initialPosition; private Quaternion _initialRotation; private Vector3 _velocity = Vector3.zero; private void Awake() { _initialPosition = transform.position; _initialRotation = transform.rotation; } private void LateUpdate() { if (target == null) return; if (followPosition) { UpdatePosition(); } if (followRotation) { UpdateRotation(); } } private void UpdatePosition() { // 타겟 위치 + 로컬 오프셋 계산 Vector3 targetPosition = target.TransformPoint(positionOffset); // 부드러운 보간 Vector3 smoothedPosition = Vector3.Lerp( transform.position, targetPosition, positionSmoothSpeed * Time.deltaTime ); // 축 고정 적용 if (freezePositionX) smoothedPosition.x = _initialPosition.x; if (freezePositionY) smoothedPosition.y = _initialPosition.y; if (freezePositionZ) smoothedPosition.z = _initialPosition.z; transform.position = smoothedPosition; } private void UpdateRotation() { Quaternion targetRotation = target.rotation * Quaternion.Euler(rotationOffset); transform.rotation = Quaternion.Slerp( transform.rotation, targetRotation, rotationSmoothSpeed * Time.deltaTime ); } /// /// 타겟을 런타임에 변경 /// public void SetTarget(Transform newTarget) { target = newTarget; } /// /// 즉시 타겟 위치로 이동 (보간 없이) /// public void SnapToTarget() { if (target == null) return; if (followPosition) { Vector3 targetPosition = target.TransformPoint(positionOffset); if (freezePositionX) targetPosition.x = _initialPosition.x; if (freezePositionY) targetPosition.y = _initialPosition.y; if (freezePositionZ) targetPosition.z = _initialPosition.z; transform.position = targetPosition; } if (followRotation) { transform.rotation = target.rotation * Quaternion.Euler(rotationOffset); } } /// /// 초기 위치로 복귀 /// public void ResetToInitial() { transform.position = _initialPosition; transform.rotation = _initialRotation; } #if UNITY_EDITOR private void OnDrawGizmosSelected() { if (target == null) return; Gizmos.color = Color.cyan; Vector3 targetPos = target.TransformPoint(positionOffset); Gizmos.DrawLine(transform.position, targetPos); Gizmos.DrawWireSphere(targetPos, 0.1f); } #endif } }