using UnityEngine; // 임포트할거에요 -> Unity 엔진 기본 기능을 using Cinemachine; // 임포트할거에요 -> Cinemachine 카메라 시스템을 // ══════════════════════════════════════════════════════════════════════ // CinemachineAutoTarget — 씬 로드 시 플레이어 자동 추적 // // DontDestroyOnLoad로 플레이어가 씬을 넘어올 때, // 새 씬의 Cinemachine 카메라가 자동으로 플레이어를 찾아 Follow/LookAt 설정 // // 사용법: 보스 씬(또는 모든 씬)의 CinemachineVirtualCamera 오브젝트에 부착 // playerTag에 플레이어 오브젝트의 태그를 설정 (기본: "Player") // ══════════════════════════════════════════════════════════════════════ public class CinemachineAutoTarget : MonoBehaviour // 클래스를 정의할거에요 -> 카메라 자동 타겟 연결기를 { [Header("플레이어 탐색 설정")] [Tooltip("플레이어 오브젝트의 태그 (기본: Player)")] [SerializeField] private string playerTag = "Player"; // 변수를 선언할거에요 -> 플레이어 태그를 [Tooltip("Follow와 LookAt 둘 다 설정할지 여부")] [SerializeField] private bool setLookAt = true; // 변수를 선언할거에요 -> LookAt도 설정할지 여부를 [Tooltip("플레이어 탐색 재시도 간격 (초)")] [SerializeField] private float retryInterval = 0.5f; // 변수를 선언할거에요 -> 재시도 간격을 [Tooltip("최대 탐색 시간 (초) — 이 시간 안에 못 찾으면 포기")] [SerializeField] private float maxSearchTime = 10f; // 변수를 선언할거에요 -> 최대 탐색 시간을 private CinemachineVirtualCamera _vCam; // 변수를 선언할거에요 -> 가상 카메라 캐시를 private void Awake() // 초기화 시 실행할거에요 -> 카메라 캐싱을 { _vCam = GetComponent(); // 캐싱할거에요 -> VirtualCamera 컴포넌트를 } private void Start() // 시작 시 실행할거에요 -> 플레이어 탐색을 { if (_vCam == null) return; // 방어할거에요 -> 카메라가 없으면 // 이미 Follow가 설정되어 있고 유효하면 스킵 if (_vCam.Follow != null) // 조건이 맞으면 실행할거에요 -> 이미 타겟이 있으면 { Debug.Log("[CinemachineAutoTarget] Follow 타겟이 이미 설정되어 있음 — 스킵"); // 로그를 찍을거에요 return; // 중단할거에요 } // 플레이어 즉시 탐색 시도 if (!TryFindAndAssignPlayer()) // 조건이 맞으면 실행할거에요 -> 즉시 못 찾으면 { StartCoroutine(SearchPlayerCoroutine()); // 코루틴 시작할거에요 -> 반복 탐색을 } } /// /// 플레이어를 찾아서 카메라에 연결 시도. 성공하면 true 반환. /// private bool TryFindAndAssignPlayer() // 함수를 정의할거에요 -> 플레이어 탐색 + 연결을 { GameObject player = GameObject.FindGameObjectWithTag(playerTag); // 찾을거에요 -> 플레이어 태그를 가진 오브젝트를 if (player == null) return false; // 못 찾으면 false 반환 _vCam.Follow = player.transform; // 설정할거에요 -> Follow 타겟을 플레이어로 if (setLookAt) // 조건이 맞으면 실행할거에요 -> LookAt도 설정하라고 했으면 _vCam.LookAt = player.transform; // 설정할거에요 -> LookAt 타겟을 플레이어로 Debug.Log($"[CinemachineAutoTarget] 플레이어 자동 연결 완료: {player.name}"); // 로그를 찍을거에요 return true; // 성공 반환 } /// /// 플레이어가 아직 로드 안 됐을 수 있으니 일정 간격으로 재탐색 /// (DontDestroyOnLoad 플레이어가 씬 전환 후 약간 늦게 활성화될 수 있음) /// private System.Collections.IEnumerator SearchPlayerCoroutine() // 코루틴을 정의할거에요 -> 반복 탐색을 { float elapsed = 0f; // 초기화할거에요 -> 경과 시간을 while (elapsed < maxSearchTime) // 반복할거에요 -> 최대 시간까지 { yield return new WaitForSeconds(retryInterval); // 대기할거에요 -> 재시도 간격만큼 elapsed += retryInterval; // 더할거에요 -> 경과 시간에 if (TryFindAndAssignPlayer()) // 조건이 맞으면 실행할거에요 -> 찾았으면 yield break; // 코루틴 종료 } Debug.LogWarning("[CinemachineAutoTarget] 플레이어를 찾지 못했습니다! 태그를 확인해주세요."); // 경고 로그 } }