Unity 분석

GameObject.Find()

지영7130 2023. 1. 4. 04:08

 GameObject.Find(string name) 함수는 찾고자 하는 오브젝트의 이름을 안에 넣으면 해당 이름을 가진 오브젝트를 찾아준다.

 

ex)

using UnityEngine;

public class Find : MonoBehaviour
{
    private GameObject player;

    private void Start()
    {
        player = GameObject.Find("Player");
    }
}

하지만 나는 이 GameObject.Find() 함수를 최대한 지양한다. 그 이유는 다음과 같다.

 

1. 오브젝트의 이름이 바뀌거나 중복되는 경우

 

 이 함수를 여러 스크립트에 남용을 했다가 개발도중에 해당 오브젝트의 이름이 바뀌는 경우가 생길 수 있다. 이런 경우 해당 함수를 썼던 스크립트를 모두 수정해야 한다. 이는 매우 귀찮은 일이다. (나도 알고싶지 않았다) 개발은 한사람이 하는 경우도 있지만 규모가 커질수록 여러 사람이 참여하게 된다. 만약 그중 한명의 개발자가 오브젝트의 이름을 바꾸는 경우 곳곳에서 오류가 튀어나온다. 또한 새로운 기능을 추가하거나 제거하는 도중에도  GameObject.Find() 함수가 발목을 잡을 수 있다.

 

 또한 같은 이름의 다른 오브젝트가 있을 경우 해당 오류가 발생할 수 있다.

 

 

2. 불필요한 연산을 하게된다.

 

 GameObject.Find()는 호출될 때 Hierarchy에 있는 모든 오브젝트의 이름들을 탐색한다. 아래 사진은 내 프로젝트중 하나를 실행시켰을 때 Hierarchy 내용이다. 나는 이 프로젝트에서 나무와 바위, 동물 등을 랜덤 스폰시키고 GameManager의 자식오브젝트로 담아두고 관리하고 있다. 그렇다보니 Hierarchy에는 수백개의 오브젝트들이 생성되어 있다. 만약 GameObject.Find()로 Hierarchy에서 이 GameManager 아래에 있는 오브젝트를 찾으려면 이 수백개가 넘는 오브젝트들의 이름을 하나하나 확인해야 한다. 이는 매우 비효율적이다.

 

 

 물론 이러한 작업을 Start나 Awake에서 프로젝트가 실행될 때 단 한번 호출하게 되면 이러한 문제를 어느정도 해결할 수 있다. 하지만 만약에 게임이 실행되는 도중 이러한 작업을 한다면 불필요한 연산을 하게 되어 성능에 문제가 생길 수 있다. 유니티 공식문서에서도 이러한 문제때문에 GameObject.Find()를 매 프레임마다 실행하지 말라고 나와있다.

(https://docs.unity3d.com/kr/current/ScriptReference/GameObject.Find.html)

 

 

3. 비활성화된 오브젝트는 찾을 수 없다.

 

 GameObject.Find()는 비활성화된 오브젝트는 감지하지 않는다. 따라서 GameObject.Find()에만 의지하던 스크립트가 해당 오브젝트가 비활성화 되면 고장나는 경우가 생길 수 있다. 이러한 경우 찾으려던 오브젝트의 부모오브젝트를 찾아 해결할 수 있다. 하지만 이전에는 잘 작동하던 스크립트가 새로운 기능이 추가되면서 갑자기 오류가 생기는 경우가 발생할 수 있다. GameObject.Find()에 의존하고 남발하게 되면 이러한 잠재적 오류 요소가 생길 수 있다.

 

 

 

 그렇다면 다른 오브젝트를 찾으려면 어떤 방법을 사용하면 좋을까?

 

 

1. public변수를 이용해 인스펙터창에서 할당을 해 해결을 한다.

 

 이는 특정 상황에서 GameObject.Find()보다 좋은 효과를 낼 수 있다. 하지만 이 역시 남발하게 되면 인스펙터창이 더러워질 수 있고 만약 프리팹 안에 있던 스크립트에서 다른 오브젝트를 찾는 경우에는 프리팹 밖에 있는 오브젝트를 가져오기 힘들다. 따라서 이러한 방법은 GameObject.Find()를 완전히 대체할 수 없다. 하지만 이를 이용해서 더 좋은 효과를 낼 수 있다면 GameObject.Find() 대신 사용해보자.

 

 

2. 자식오브젝트에 두고 transform.GetChild()를 사용한다.

 

 이는 찾고자 하는 오브젝트가 해당 오브젝트의 자식 오브젝트에 있을 경우 유용하게 쓰인다. 하지만 이 역시 특정 상황에서만 사용 가능하고 GameObject.Find()를 완전히 대체할 수 없다. 하지만 찾고자 하는 오브젝트를 자식오브젝트에 넣어두고 사용할 수 있는 경우 이를 이용해보자.

 

 

3. Singleton 이용

 

 Singleton은 여러 스크립트에서 한 스크립트에 접근해야 하는 경우 유용하게 쓰인다. 이를 이용하게 되면 굳이 해당 스크립트가 있는 오브젝트를 GameObject.Find()로 불러와서 GetComponent로 해당 스크립트를 불러오지 않아도 접근하고자 하는 스크립트에 쉽게 접근할 수 있다.

 

 하지만 Singleton을 남용하게 되면 여러 클래스간의 구조가 복잡해져 프로젝트의 규모가 커질수록 유지보수가 어려워 질 수 있다. 또한. Singleton을 이용해 저장한 데이터들은 게임이 실행되는 동안 계속 남아있어 메모리를 비효율적으로 사용할 수 있다. 차라리 그냥 GameObject.Find()를 사용하는 것이 더 나을 수 있으니 반듯이 여러 스크립트에서 한 스크립트에 접근해야 하는 경우 사용해보자. Singleton에 대해서는 나중에 더 자세히 다루겠다.

 

 

 

 

 나는 이러한 방식들로 GameObject.Find()를 최대한 지양해서 사용해 왔다. 하지만 상황에 따라 GameObject.Find()를 사용하는 것이 더 효율적일 경우도 많이 있따라서 스크립트에서 다른 오브젝트를 가져올 때 어떠한 방법을 사용하면 더 효율적으로 가져올 수 있을지 고민하면서 사용해보자.

'Unity 분석' 카테고리의 다른 글

Enum의 활용  (0) 2023.01.07
코루틴의 작동방식  (0) 2023.01.06
메모리 구조와 유니티 - GC에 대한 심층적 이해  (0) 2023.01.05
물체가 이동하면서 얇은 벽을 통과하는 경우  (0) 2023.01.04
FixedUpdate  (0) 2023.01.04