Prosto

유니티, 원하는 게임오브젝트 얻기 -2(transform.FindChild..) 본문

Programing/Unity 3D

유니티, 원하는 게임오브젝트 얻기 -2(transform.FindChild..)

Prosto 2016. 10. 12. 14:32

 

GameObjcet.Find / GameObject.FindWithTag (GameObject.FindGameObjectWithTag)

를 이용한 일반적인 방법 (아래의 1번 글)

유니티, 원하는 게임오브젝트 얻기? -1(GameObject.Find..)

 

1번 글인 GameObject.Find에 이어서 진행하겠습니다.

 

이번에 우리가 다룰 내용은 바로

transform.FindChild / transform.GetChild 입니다.

 

이 함수는

 1. 자신의 자식에 있는 오브젝트를 얻고싶을 때

 2. 비활성화(Active값-false) 상태의 오브젝트를 얻고싶을 때

사용됩니다.

 (게임오브젝트(GameObject)나 트랜스폼(Transform)을 얻을 때 말이죠. [하위 Component도 포함되겠죠?])

 

 

기본적으로는 원래 자식의 Transform을 얻고 싶을 때 사용하는 거죠.

하지만 이를 통하여 GameObject나 Component 모두 얻을 수 있습니다.

(그리고 또 많이 사용되는 게 비활성화 상태인 오브젝트를 얻을 때죠.)

 

 

 - 자식을 이름으로 찾고싶다면

transform.FindChild("이름");

 

이렇게 사용할 수 있고요.

 

 - 자식을 번호로 찾고싶다면

transform.GetChild(번호);

 

 

이렇게 사용할 수 있습니다.

 

(하지만 여기서 외부의 게임오브젝트를 통한다면 바뀌겠죠?

 예를 들면 tempGameObject.transform.FindChild("이름"); 처럼요.)

 

자식을 transform.FindChild("이름")으로 찾는 방식은

기존의 1번 글 GameObject.Find("이름")과 같기 때문에 굳이 기능적인 설명은 하지 않겠습니다.

 

(그냥 해당 스크립트가 있는 오브젝트의 자식을 얻고 싶으시다면

 transform.FindChild("이름") 혹은 transform.GetChild(자식 순서 번호[0부터~])

 를 사용하시면 됩니다. )

 

 

이번 시간에 확인해야할 부분은 GameObject.Find로 비활성화된 오브젝트를 찾지 못 했지만,

transform.FindChild로는 찾을 수 있다는 점이 포인트입니다.

 

 

이와 관련된 내용의 예제 프로젝트를 통하여 확인해보겠습니다.

(프로젝트 자체는 1번 글에서 만들어졌습니다.)

 

우선 저번 글의 마지막 부분에 올린 사진으로 프로젝트 실행하고

GameObject.Find()함수로 실패한 이미지를 확인해볼까요?

1번 몬스터를 가지고 오려다가 실패한 모습입니다.

(Hierarchy 탭에서 Monster1이 비활성화된 상태로 있는 게 보이시죠?)

 

 

이번에는 5번 몬스터를 가지고 오려다가 실패한 모습입니다.

(Hierarchy 탭에서 Monster5의 부모인 Monsters 게임오브젝트가 비활성화된 상태로 있는 게 보이시죠?)

 

 

자 동작이 잘 되도록 스크립트를 바꿔볼까요?

 

 

이렇게 됐습니다.

1번 글의 소스에서 바뀐 부분이라고는

저 tempObj를 가지고 오는 부분밖에 없죠?

 

 tempObj = GameObject.Find("Monsters").transform.FindChild("Monster"+monsterNumber.ToString()).gameObject;

을 풀어서 설명하자면 아래와 같은 순서로 얻어옵니다.

 

1. GameObject.Find("Monsters")를 통하여 (G)GameObject를 얻습니다.

2. (G).transform으로 (GT)Transform을 얻습니다.

3. (GT).findChild("몬스터"+번호)를 통하여 (GTT)Transform을 얻습니다.

4. 마지막으로 (GTT).gameObject를 통하여 해당 몬스터 번호의 GameObject를 얻었습니다.

 

그렇게 제대로 tempObj를 얻어왔으면 처음에 null로 초기화해둔

tempObj에 해당 게임 오브젝트가 들어가겠죠?

해당 게임 오브젝트 얻기 성공 = 성공 출력

해당 게임 오브젝트 얻기 실패 = 실패 출력

이라는 결과가 콘솔탭에 나오게 됩니다.

 

 아래에 해당 소스 붙입니다. 필요하면 복사해서 알맞게 바꿔 사용해보세요.

 

Hierarchy 탭에서 Monster1이 비활성화 상태인데도

MonsterNumber에 따라

Monster1 게임 오브젝트를 성공적으로 받아왔죠?

 

(이렇게 비활성화된 오브젝트를 받아올 수 있다는 걸 확인했네요.)

 

 

하나 더 Monster2도 받아봅시다.

MonsterNumber를 2로 바꾸고

게임 화면을 클릭했더니

성공했다는 문구가 콘솔 탭에 출력됐습니다.

 

잘 되네요.

 

하지만 이렇게

Monster들의 부모인 Monsters 자체가 비활성화된 상태라면

받아올 수 없습니다.

 

NullReferenceException: Object reference not set to an instance of an object

이 오류는 비어있는 오브젝트(null)를 참조하려고 할 때 발생하는 예외 오류입니다. 

 

실제로 Monsters가 비활성화 상태라면

GameObject.Find("Monsters")를 통하여 부모였던 Monsters를 얻지 못 하겠죠?

그렇게 얻지 못 했지만 우리는 그 게임 오브젝트에 Transform을 참조하려고 하니 오류가 발생한 겁니다.

 

그러면 비활성화 된 부모에게도 받아오려면 어떻게 해야할까요?

(실제로 부모가 비활성화 되어있다면 자식도 비활성화라

자식만 활성화할 수는 없지만, 비활성화 부모에게 자식을 얻어 사용할 때는 분명있겠죠?)

이렇게 처음에 Awake() [스크립트 최초 실행]에서

MonstersParent라는 GameObject에 담아두면 됩니다.

그러면 중간에 MonstersParent가 비활성화되도

새롭게 GameObject.Find()를 통하여 얻는 게 아니기 때문에

못 찾을 일이 없겠죠? (이미 얻은 상태니까요)

 

 아래에 해당 소스 붙입니다. 필요하면 복사해서 알맞게 바꿔 사용해보세요.

 

 

한번 테스트 해봅시다.

이렇게 게임이 실행되면

콘솔 탭에 Monsters 게임 오브젝트를 얻었다는 문구가 출력된 게 보입니다.

 

 

Monsters를 비활성화 시킵니다.

(하위 몬스터들 모두 비활성화 상태가 됐죠?)

 

 

그리고 Monster Number를 2로 바꿔주고

화면을 클릭했지만,

성공적으로 Monster2 오브젝트를 받아왔다고 출력됐습니다.

 

처음 한번 받아둔 몬스터들의 부모 Monsters 오브젝트를 사용했기 때문에 가능한 거죠.

 

보통 게임 처음에 이렇게 얻어두고 쓰는 경우가 많이 생기겠죠?

그런데 우리가 중간에 개입해서 오브젝트를 꺼주기는 애매하잖아요.

 

그렇기 때문에 보통 처음에 시작(혹은 생성)할 때 활성화 상태로 두고,

그 대상을 참조하게 되면

SetActive(false)를 이용해 비활성화 시켜준답니다.

 

이렇게 말이죠.

 

실행해볼까요?

게임이 시작되자마자 Monsters 게임 오브젝트를 받았고,

그 후 바로 Monsters 게임 오브젝트를 비활성화시킨 것을 확인할 수 있습니다.

 

 

마찬가지로 Monster Number에 적절한 값을 넣고

화면을 클릭해보면 성공적으로 받는 모습을 볼 수 있습니다.

 

 

그럼 다음으로 transform.GetChild도 사용해볼까요?

이렇게 바꿨습니다.

 

tempObj = GameObject.Find("Monsters").transform.GetChild(monsterNumber-1).gameObject;

을 풀어서 설명하자면 아래와 같은 순서로 얻어옵니다.

 

1. GameObject.Find("Monsters")를 통하여 (G)GameObject를 얻습니다.

2. (G).transform으로 (GT)Transform을 얻습니다.

3. (GT).getChild(몬스터 번호 - 1)를 통하여 (GTT)Transform을 얻습니다.

4. 마지막으로 (GTT).gameObject를 통하여 해당 몬스터 번호의 GameObject를 얻었습니다.

 

여기서 getChild(몬스터 번호 -1)을 하는 이유는

getChild의 자식 첫 번째(Hierarchy 탭 기준)가 0번째 자식이기 때문입니다.

 

(부모와 자식이 바뀌는 경우가 있다면

GetChild보단 FindChild를 추천합니다.

자식이 추가/제거 되며 바뀌면 순서가 뒤죽박죽 섞일 수 있습니다.)

 

 아래에 해당 소스 붙입니다. 필요하면 복사해서 알맞게 바꿔 사용해보세요.

 

 

자, 실행해서 Monster1을 비활성화 상태로 바꾼 후

Click Event 스크립트의 Monster Number를 1로 바꾸고

화면을 클릭해보면

성공적으로 Monster1 오브젝트를 받았다는 콘솔 탭의 출력을 확인할 수 있습니다.

(GetChild로도 제대로 받을 수 있죠?)

 

마지막으로 하나만 더 확인해봅시다.

정상적으로 처리된 것을 확인할 수 있습니다.

 

만약 GetChild를 사용하는데 Monsters 오브젝트가 비활성화 된 상태에서도 하고싶다.

라고하면 아까 FindChild에서 해줬던 작업을 그대로 해주면 되겠죠?

 

 

그 후 컴포넌트를 얻을 필요학 있다면 다 똑같이

.GetComponent<Type>();을 사용하면 되겠죠?

 

그렇게 스프라이트 랜더러(Sprite Renderer)나 텍스트(Text),
 이미지(Image), 스크립트(Script) 등 모두 받아와서 사용할 수 있습니다.

 

지금까지 유니티에서 원하는 게임오브젝트를 찾기 위한 방법은 무엇이 있는지,

비활성화된 오브젝트도 얻으려면 어떻게 해야하는지,

또 실제 사용까지 봤습니다.

 

 

도움이 됐다면 좋겠습니다.

 

궁금한 점 있으시면 댓글이나 따로 메일로 질문하시면 시간되는 대로 답변드리겠습니다. ( 연락 )

 

Comments