상세 컨텐츠

본문 제목

[Unity] 유니티 특정 오브젝트 찾기 관련

게임엔진관련/유니티 엔진

by AlrepondTech 2019. 7. 1. 01:33

본문

반응형

 

 

 

=================================

=================================

=================================

 

 

 

 

 

 

 

 

출처: https://treeofimaginary.tistory.com/114

 

몇번 언급했지만 유니티는 게임오브젝트 찾는방법이 좀 까다롭다.

 

가~장 기본적으로 주어지는 메소드는 GameObject.Find(오브젝트이름).

 

문제는 이게 비활성화(Inactive) 상태의 오브젝트는 못찾아준다는거다.

 

 

비활성화 오브젝트를 찾는걸로 Transform.FindChild(오브젝트 이름)이 있지만 이건 해당 트랜스폼의 자식들에 대해서로 탐색범위가 한정되어있다. 심지어 자기 자식의 자식은 이걸로 찾아지지도 않는단다.

 

 

결국 내가 임시로 생각해둔 방법은

 

 

1) 게임내 탐색이 요구될법한 모든 오브젝트를 루트 오브젝트(GameManager)에 귀속시킨다.

2) GameManager 스크립트는 Awake시 자신의 자식들을 순회하면서 Dictionary에 추가하고, 만약 자식들한테 추가자식이 있을경우 함수를 재귀해 다시 탐색한다.

 

3)이후 필요할때마다 GameManager의 FindTransform(오브젝트 이름)을 호출해 원하는 객체를 가져온다.

 

 

...편하긴하다. GameManager는 무슨일이 있어도 비활성화되지 않도록 설정했고, 탐색도 this.transform.root로 바로 접근할수있다.

 

문제는...

 

this.transform.root.GetComponent<GameManager>().FindTransform("InventoryUI").GetComponent<InventoryUI>();

 

...무슨 의미인지 알겠는가? InventoryUI라는 객체에 담긴 InventoryUI클래스를 얻어오는 거다.

 

뭔가 쓸데없이 길어진다. 정말 답이 없게 길어진다.

 

 

내 경우 FindTransform을 쓰는 이유는 단 하나다, 해당 오브젝트 이름과 동일한 이름을 가진 스크립트 컴포넌트를 가져오기 위함이다.

 

그럼 왜 반환할때 컴포넌트를 직접 반환하지 않느냐?...

 

이게 InventoryUI를 반환할지 EventObject를 반환할지 확실하지않아서 반환 자료형을 확실히 정의할수가 없다.

 

그렇다고 부모 클래스인 MonoBehvaior로 주자니 쓸데없이 박싱하는작업이 길어진다.

 

 

애초에, 이런 용도면 매개변수가 그냥 class 타입 자체로 (InventoryUI면 그냥 InventoryUI라는 클래스명자체가 매개변수로 박힌다던가)보낼수있는게 가장 이상적일것같은데, 그건 뭔가 현실적으로 안되는것같고...

 

말이 장황한데, 내가 하고싶다는건 이거다. 상황은 

 

"플레이어가 인벤토리UI 컴포넌트를 가져오고싶다"

 

 

플레이어 스크립트

 

InventoryUI ui = this.transform.root.GetComponent<GameManager>().FindComponent(InventoryUI);

 

이렇게 하면 뙇하고 클래스가 반환되는걸 원하는거.

 

사실 어쩌면 된다해도 이게 훨씬더 비효율적일수도 있다.

 

 

....제네릭 메소드가 답이 될것같기도 한데. 좀 더 알아봐야겠다.

 

 

 

 

반응형

 

728x90

 

 

 

 

---------------------------------------------------

 

 

21:54분 추가

 

 

역시 답은 제네릭 메소드에 존재했다.

 

 

Pad pad = this.transform.root.GetComponent<GameManager>().FindComponent<Pad>();

 

 

함수 내부는 이렇게 구성되어있다.

 

    public T FindComponent<T>()

    {

        return ingameobjects[typeof(T).ToString()].GetComponent<T>();

    }

 

 

내 경우 대부분의 클래스파일은 대게 해당 클래스의 이름과 동일한 이름을 가진 게임오브젝트에 삽입되므로 (EventObject같은 예외야 있겠지만 이건 매개변수를 하나 넣는식으로 해결가능) 쉽게 도달한것같다.

 

 

...그나저나, 이걸 기껏 발견하고났더니 이걸 또 어느세월에 다 수정하고있나...하하...

 

 

----------------------------------------------------------

 

22:10분 추가

 

 

줄일수 있는 방법은 더 존재한다. 다만...이건 좀 신경쓰이는 문제긴 하다.

 

    public static GameManager getter;

    private void Awake()

    {

        getter = this;

        Find(this.transform);

    }

 

GameManager 클래스 내부 내용이다. static으로 선언해놨기에 이런 사용법이 가능하다.

 

pad = GameManager.getter.FindComponent<Pad>();

 

이젠 getcomponent를 할 필요조차 없어진다는 의미.

 

다만 유니티에서 static을 쓰는건 꽤나 지양되는 분위기라 이게 베스트인지는 좀 조심스러워진다.

private void Start()

{

//루트 오브젝트를 찾아내고, 해당 오브젝트로부터 Pad 게임오브젝트를 받은뒤 Pad 컴포넌트를 가져온다.

//pad = this.transform.root.GetComponent<GameManager>().FindTransform("Pad").GetComponent<Pad>();

//pad = this.transform.root.GetComponent<GameManager>().FindComponent<Pad>(); //pad = GameManager.GetRoot().FindComponent<Pad>(); pad = GameManager.getter.FindComponent<Pad>();

}

 

오늘 하루동안 얻은걸 바탕으로 pad 컴포넌트를 얻어오는 4가지 방법 변천사. 2번째 아님 4번째가 모범답안 아닐까 싶다.

 

 

=================================

=================================

=================================

 

 

기타관련링크

https://cru6548.tistory.com/5 

 

 

=================================

=================================

=================================

 

 

반응형


관련글 더보기

댓글 영역