본문 바로가기

Study/Unity Engine

[Unity] 오브젝트 검색 방법

https://waterglass0105.tistory.com/110

 

[Unity] Tag

Unity에서 Tag는 게임 오브젝트를 식별하고 분류하기 위한 문자열 라벨이다. Tag를 사용하면 특정 오브젝트 그룹에 쉽게 접근하거나 필터링할 수 있다.예를 들어, 적 오브젝트는 "Enemy" 태그를, 플레

waterglass0105.tistory.com

 

Tag 내용을 정리하면서, 지나친 Tag 사용, 잦은 Tag 기반 검색이 시스템에 좋지 않은 영향을 줄 수 있다고 언급하며 다른 검색 방법에 대해 소개한 바 있다. 이번에는 FindWithTag나 FindGameObjectsWithTag 대신 사용할 수 있는 대체 검색 방법들에 대해 알아보고자 한다.

 

1. Layer 기반 검색

https://waterglass0105.tistory.com/111

 

[Unity] Layer

https://docs.unity3d.com/kr/560/Manual/Layers.html 레이어 - Unity 매뉴얼레이어(Layers) 는 카메라 가 씬의 일부만 렌더링하고 광원 이 씬의 일부만 비추기 위해 가장 많이 사용됩니다. 그 외에도 콜라이더를

waterglass0105.tistory.com

 

특정 게임 오브젝트를 레이어로 구분한 후, 물리적 충돌 검사나 Physics 클래스를 활용하여 검색한다.

 

방법

  • 오브젝트에 특정 레이어를 설정하고, Physics.OverlapSphere, Physics.Raycast 등을 활용해 레이어 마스크를 사용한 필터링을 한다.

장점

  • 특정 영역 내의 오브젝트를 효율적으로 검색 가능.
  • 물리 연산 기반으로 필요한 데이터만 가져옴.
int layerMask = LayerMask.GetMask("Enemy");
Collider[] colliders = Physics.OverlapSphere(transform.position, searchRadius, layerMask);

foreach (Collider collider in colliders)
{
    Debug.Log(collider.gameObject.name);
}

 

위 코드와 같이, layerMask를 설정하고, Collider에 해당 layerMask와의 충돌을 검사하는 로직을 만들 수 있다.


2. 오브젝트 참조를 미리 저장

게임 오브젝트의 참조를 스크립트나 관리 클래스에서 미리 저장해두고 필요할 때 사용한다.

 

방법

  • Start나 Awake에서 필요한 오브젝트를 한 번 검색 후 캐싱.
  • 또는 Unity Editor를 통해 직접 참조를 드래그 앤 드롭 방식으로 연결.

장점

  • 검색을 매번 수행할 필요가 없어 매우 빠르고 효율적.
  • 자주 사용되는 오브젝트의 경우 특히 유용.
public GameObject player;

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

 

위 코드와 같이, Start 혹은 Awake에 필요한 오브젝트를 미리 캐싱하여 사용하면 빠르고 효율적으로 탐색이 가능하다. 하지만 이 경우, 런타임에 동적으로 생성된 객체에 대한 참조를 위해서는 별도의 로직이 요구된다.


3. Dictionary 또는 List를 활용한 관리

오브젝트를 직접 관리하는 컬렉션을 만들어 필요할 때 조회한다.

 

방법

  • 특정 오브젝트들이 생성/삭제될 때마다 리스트나 딕셔너리에 추가/제거.
  • 검색 시 컬렉션에서 바로 접근.

장점

  • O(1) 또는 O(n) 수준의 검색 속도를 제공.
  • 복잡한 검색 조건도 쉽게 처리 가능.
public static List<GameObject> enemies = new List<GameObject>();

void AddEnemy(GameObject enemy)
{
    enemies.Add(enemy);
}

void RemoveEnemy(GameObject enemy)
{
    enemies.Remove(enemy);
}

GameObject FindClosestEnemy(Vector3 position)
{
    GameObject closest = null;
    float closestDistance = Mathf.Infinity;

    foreach (GameObject enemy in enemies)
    {
        float distance = Vector3.Distance(position, enemy.transform.position);
        if (distance < closestDistance)
        {
            closestDistance = distance;
            closest = enemy;
        }
    }
    return closest;
}

4. Parent-Child 관계 활용

특정 오브젝트의 자식 오브젝트만 검색하여 범위를 줄인다.

 

방법

  • transform.Find 또는 GetComponentsInChildren을 사용.
  • 특정 부모 아래의 자식 오브젝트만 대상.

장점

  • 검색 범위를 크게 줄일 수 있음.
  • 계층 구조를 활용하면 검색이 더 효율적.
Transform child = transform.Find("ChildName");
if (child != null)
{
    Debug.Log(child.gameObject.name);
}

5. ScriptableObject로 데이터 관리

ScriptableObject를 사용하여 오브젝트 데이터나 참조를 중앙에서 관리한다.

 

방법

  • 게임 내 모든 오브젝트의 데이터를 ScriptableObject로 유지.
  • 이를 통해 필요한 오브젝트에 접근.

장점

  • 데이터 중심으로 관리가 가능해 확장성이 뛰어남.
  • 복잡한 오브젝트 간 관계를 쉽게 설정 가능.
[CreateAssetMenu(fileName = "EnemyManager", menuName = "Managers/EnemyManager")]
public class EnemyManager : ScriptableObject
{
    public List<GameObject> enemies;

    public void AddEnemy(GameObject enemy)
    {
        if (!enemies.Contains(enemy))
            enemies.Add(enemy);
    }

    public void RemoveEnemy(GameObject enemy)
    {
        if (enemies.Contains(enemy))
            enemies.Remove(enemy);
    }
}

6. Events & Delegates 활용

이벤트나 델리게이트를 사용하여 특정 상황에서만 필요한 오브젝트를 가져온다.

 

방법

  • 오브젝트 상태가 변경될 때 이벤트를 호출하여 필요한 오브젝트만 등록.

장점

  • 필요할 때만 처리되어 불필요한 연산을 줄임.
public delegate void OnEnemyAdded(GameObject enemy);
public static event OnEnemyAdded EnemyAdded;

public static void AddEnemy(GameObject enemy)
{
    EnemyAdded?.Invoke(enemy);
}

6-1. Collider 및 Physics 활용

동적 객체가 특정 범위 내에 있거나 특정 조건에 부합하는 경우, Physics.OverlapSphere 또는 Collider 이벤트를 활용해 탐색할 수 있다.

int enemyLayerMask = LayerMask.GetMask("Enemy");

Collider[] enemiesInRange = Physics.OverlapSphere(player.transform.position, 10f, enemyLayerMask);

foreach (Collider collider in enemiesInRange)
{
    Debug.Log($"Enemy in range: {collider.gameObject.name}");
}

 

이처럼, 게임의 구조와 요구사항에 따라 적절한 방법을 선택하여 성능 최적화를 도모할 수 있다.

특히, 자주 검색이 필요한 오브젝트참조 캐싱 또는 리스트/딕셔너리 관리를 적극적으로 활용하는 것이 가장 권장된다.

 

이 밖에도 다양한 검색 방법이 존재하지만 이 포스트에는 자리가 부족하여 남기지 않는다.

 

'Study > Unity Engine' 카테고리의 다른 글

[Unity] DLL과 PDB  (0) 2025.01.18
[Unity] 컴파일 과정  (0) 2025.01.18
[Unity] ScriptableObject  (0) 2025.01.18
[Unity] Layer  (0) 2025.01.18
[Unity] Tag  (0) 2025.01.17