153 lines
4.5 KiB
C#

using UnityEngine;
namespace Streamingle.Utils
{
/// <summary>
/// 타겟 오브젝트를 부드럽게 따라가는 컴포넌트
/// </summary>
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
);
}
/// <summary>
/// 타겟을 런타임에 변경
/// </summary>
public void SetTarget(Transform newTarget)
{
target = newTarget;
}
/// <summary>
/// 즉시 타겟 위치로 이동 (보간 없이)
/// </summary>
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);
}
}
/// <summary>
/// 초기 위치로 복귀
/// </summary>
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
}
}