오늘은 Find 함수 사용과 관련해 정리하고자 합니다.
Find 계열 함수들은 이름을 통해 해당 오브젝트를 찾아주는 기능을 제공합니다. 
편리해 보여서 자주 사용할 것 같지만 대부분 사용을 지양하더군요.
왜일까요?
1. 
Find 계열 함수들은 씬(Scene) 전체를 순회하면서 해당 이름을 검색하는 문자열과 비교합니다.
이 과정에서 성능적으로 문제가 발생할 수 있습니다.
2. 
여러 개의 같은 이름(혹은 타입 등)의 오브젝트가 있을 경우 의도치 않은 결과가 발생 수 있습니다.
3.
컴파일 - 코드 - 에서 확인할 수 있는 게 아니라 
런타임 도중에 이름이 변경되거나 변동이 생기면 오류가 나기 쉽습니다.
이러한 이유로 사용을 지양하고 있는 듯합니다.
그러면 특정 오브젝트를 찾으려면 어떻게 하는 게 좋을까요?
Find 계열의 함수를 대체 할 수 있는 5가지 방법을 소개하고자 합니다.
Find 사용을 대체 할 수 있는 방법들
1. Inpector에서 직접 할당하는 방법 
public class PlayerController : MonoBehaviour 
{
    [SerializeField] private GameObject target;     
    [SerializeField] private Transform targetTransform;
    [SerializeField] private Camera mainCamera;
    private void Update() 
    {
        if (target != null) {
            // target 사용
        }
    }
}
2. 컴포넌트를 캐싱하는 방법
public class WeaponController : MonoBehaviour 
{
    private Animator animator;
    private Rigidbody rb;
    private ParticleSystem particleSystem;
    private void Awake() 
    {
        // 시작할 때 한 번만 캐싱, 이후엔 해당 변수로 재사용
        animator = GetComponent<Animator>();
        rb = GetComponent<Rigidbody>();
        particleSystem = GetComponent<ParticleSystem>();
    }
}
3. 인스턴스화 시 참조 저장하는 방법
public class ObjectSpawner : MonoBehaviour 
{
    [SerializeField] private GameObject prefab;
    private List<GameObject> spawnedObjects = new List<GameObject>();
    public GameObject SpawnObject(Vector3 position) 
    {
        // 생성과 동시에 참조 저장
        GameObject newObject = Instantiate(prefab, position, Quaternion.identity);
        spawnedObjects.Add(newObject);
        return newObject;
    }
    public void DestroyAllSpawned() 
    {
        foreach (var obj in spawnedObjects) 
        {
            if (obj != null) 
            {
                Destroy(obj);
            }
        }
        spawnedObjects.Clear();
    }
}
4. 싱글톤 패턴 활용 
public class GameManager : MonoBehaviour 
{
    public static GameManager Instance { get; private set; }
    
    public int Score { get; private set; }
    public bool IsGameOver { get; private set; }
    private void Awake() 
    {
        if (Instance == null) 
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else 
        {
            Destroy(gameObject);
        }
    }
    // 다른 스크립트에서 사용
    // GameManager.Instance.Score 처럼 접근
}
5. 이벤트 시스템 활용 
public class EventManager : MonoBehaviour 
{
    public static event System.Action<int> OnScoreChanged;
    public static event System.Action OnGameOver;
    public void UpdateScore(int newScore) 
    {
        OnScoreChanged?.Invoke(newScore);
    }
    public void GameOver() 
    {
        OnGameOver?.Invoke();
    }
}
// 다른 스크립트에서 이벤트 구독
private void OnEnable() 
{
    EventManager.OnScoreChanged += HandleScoreChanged;
    EventManager.OnGameOver += HandleGameOver;
}
private void OnDisable() 
{
    EventManager.OnScoreChanged -= HandleScoreChanged;
    EventManager.OnGameOver -= HandleGameOver;
}
마무리
오늘은 간단하게 Find 사용에 관해 정리해 봤습니다.
이전에 학습하면서 알고 있던 내용이었는데, 면접 질문 대비하면서 이와 관련한 질문이 나오더군요.직접적으로 블로그에 쓴 적은 없는 것 같아 복습 겸 작성해 봤습니다.