카테고리 없음

유니티 - Find 계열 함수 사용 지양해야 하는 이유

근본넘치는개발자 2024. 12. 11. 23:28

 

오늘은 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 사용에 관해 정리해 봤습니다.

 

이전에 학습하면서 알고 있던 내용이었는데, 면접 질문 대비하면서 이와 관련한 질문이 나오더군요.직접적으로 블로그에 쓴 적은 없는 것 같아 복습 겸 작성해 봤습니다.