- ToonPostProcess.shader: 횃불 고딕 스타일 후처리 쉐이더 (Built-in RP) - ToonCameraEffect.cs: 카메라 자동 부착 후처리 스크립트 - 중복 UI 스크립트 제거 (MenuIntroController, ToggleCustom) - 씬, 프리팹, 애니메이션 등 전체 업데이트 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
91 lines
4.9 KiB
C#
91 lines
4.9 KiB
C#
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<CinemachineVirtualCamera>(); // 캐싱할거에요 -> VirtualCamera 컴포넌트를
|
|
}
|
|
|
|
private void Start() // 시작 시 실행할거에요 -> 플레이어 탐색을
|
|
{
|
|
if (_vCam == null) return; // 방어할거에요 -> 카메라가 없으면
|
|
|
|
// 이미 Follow가 설정되어 있고 유효하면 스킵
|
|
if (_vCam.Follow != null) // 조건이 맞으면 실행할거에요 -> 이미 타겟이 있으면
|
|
{
|
|
Debug.Log("[CinemachineAutoTarget] Follow 타겟이 이미 설정되어 있음 — 스킵"); // 로그를 찍을거에요
|
|
return; // 중단할거에요
|
|
}
|
|
|
|
// 플레이어 즉시 탐색 시도
|
|
if (!TryFindAndAssignPlayer()) // 조건이 맞으면 실행할거에요 -> 즉시 못 찾으면
|
|
{
|
|
StartCoroutine(SearchPlayerCoroutine()); // 코루틴 시작할거에요 -> 반복 탐색을
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 플레이어를 찾아서 카메라에 연결 시도. 성공하면 true 반환.
|
|
/// </summary>
|
|
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; // 성공 반환
|
|
}
|
|
|
|
/// <summary>
|
|
/// 플레이어가 아직 로드 안 됐을 수 있으니 일정 간격으로 재탐색
|
|
/// (DontDestroyOnLoad 플레이어가 씬 전환 후 약간 늦게 활성화될 수 있음)
|
|
/// </summary>
|
|
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] 플레이어를 찾지 못했습니다! 태그를 확인해주세요."); // 경고 로그
|
|
}
|
|
}
|