Destroy#2

CJB_ny·2022년 1월 12일
0

Mini_MMO_RPG

목록 보기
13/16
post-thumbnail

우리가 나중에 나중에

1. 첫번째 고민

게임서버랑 연동을 하였을때


이런식으로 id와 GameObject를 묶어서 관리를 할 수 있을 것이다.


몬스터라면은 이렇게 들고 있으면 될 것이다.

이렇게 들고 있으면 되는데

2. 첫번째 고민

두번째 고민은 몬스터랑 player랑 하나의 오브젝트에 넣을지 따로 분리를 할지도 고민이다.

여러 방식으로 할 수도 있겠지만

강사가 본 프로젝트는 다 분리를 해두었었다.


이런식으로 다 따로따로 관리를 하자.

이런식으로 타입별로 다 구별을 해서 한다.

그런데 지금은 Player는 본인 한명 밖에 없고

나중에 서버가 붙기 전까지는 id가 없으니까


HashSet으로 바꿔주자
(Hashset은 Dictionary와 비슷한데 Key가 없다는 점이다.)

그래서 우리가

스폰이라는 함수를 만들어 줄 것인데.

우리가 어떤 게임오브젝트를 만들어 주고 싶을 때는

이제 우리 GameManagerEx를 통해가지고

우리 스폰함수를 통해서 만들어 주면은 좀더 범용적으로 사용할 수 있을 것이다.

일단 이렇게 하면 될거같은데

그다음에 고민이 되는 것은

GameObject를 생성을 해주는데 우리가 만드는 것이 Monster이냐 Player이냐 구분을 또 해주어야 할 것이다.

그래서 구분을 하기 위해서 스폰함수에서 구별할 인자를 받아 주도록 하자.

그리고 그것을 구분을 해주기위해 Define에 enum추가를 하자.


이런식으로 하나만 늘려 주도록 하자.

나중에가서 점점점점 추가가 될 것이다.


그래서 인자로 GameObject를 받고 path, parent를 받고 뱉어 주는것은

Manager에 접근해서 Instantiate를 해주면 될 것이다.

그리고 그 다음에 만들어 줄 것은


이렇게 GmaeObject를 만들어 준다음 go를 뱉어 줄 것인다.

근데 무작정 뱉어주기 전에

새로 추가한 애니까 나중에 누가 체크를 할 수 있도록


이렇게 구분을 해주자.

Moster의 경우 _monster Dictionary에 Add 해주고
_player의 경우 하나밖에 없으니까 go로 해주자.

그리고 spawn을 했으면 대칭적으로 Despawn도 만들어 주자.


Despawn을 만들어 주자 그런데
go의 타입을 구분을 어떻게 해줄지가 고민인데

type을 받아올 GetWorldObjectType함수를 만들어 주자.

WorldObjectType이 녀석은 GameObejct를 받은 다음에 타입을 구분을 해주면 되는데

애당초 GetWorldObjectType함수에 들어오는 go의 타입을 어떻게 알 수 있을까??

사실 이 부분은 우리가 정의를 해주기 나름이다.


이렇게 가지고 오면은

go.GetComponent를 한것이 어떤것이냐에 따라가지고

Playercontroller냐 Monstercontroller 이냐에 따라가지고

몬스터인지 Player인지 구분할 수 있으니까

새로운 정보를 추가를 하기 보다는 이것을 이용하도록 하자.

그런데 혹시 이것이 PlayerController인지 알고 싶으면은

"문법"이 있기는 하다.

bc is PlayerController; 이렇게 체크를 할 수는 있기는 하다.

그런데 이렇게 하면은 느리니까

이렇게 하지는 않고

우리의 Basecontroller로 가가지고 이곳에다가 넣어 주도록 하자.


프로퍼티 형식으로 WorldObjectType 만들어 주고 기본값으로 Unknwon을 넣어 주도록 하자.

그럼이제 MonsterController와 PlayerController같은 경우에는

init을 하자마자 자신의 type부터 정의를 해주고 시작을 하면 될 것이다.

먼저 Playercontroller에서

이렇게

MonsterController에서도
이런식으로 정의를 해주면 될 것이다.

그러면 이제 GameManagerEx로 와가지고

여기서 이제는

여기서 go가 무엇인지 쉽게 판단을 할 수 있을 것이다.
(Player나 Monster나 둘다 init부분에서 타입을 정의를 해주었으니까)

그래서

이렇게 뱉어 주면 될 것이다.

그리고 어떠한 이유에서든 null이라고 한다면

Unknown이라고 뱉어 주면 될 것이다.

이렇게하면은 WorldObjectType은 알 수 있을 것이다.

그리고 Despawn에서

WorldObjectType은 방금만든 GetWorldObjectType(go);로 만들어 주면 될 것이다.

그리고 타입을 가져왔으면은


이런식으로 switch로 둘중 하나가 될 것이니까

여기서 뭔가를 해주면 될 것이다.

혹시 모르니까

여기서 함더 체크를 해주는데

진짜 _play가 맞다면은 여기서 뭔가를 해주면 될 것이다.


그래서 Despawn함수답게 _player경우에는 null로 만들어 주고
_mosters의 경우에는 Contains하는 경우 go를 Remove를 해주자.

이렇게하면은 GameManagerEx안에서 관리를 하고있느 애들은 잘 처리를 해주는 셈이 된다.

이 다음에는 실제로 날려주는 작업을 해주어야 한다.


이렇게 해주면은 이제 go가 Destroy가 되어서 Despawn이 완벽하게 처리가 될 것이다.

그다음 이제 우리가 GameScene으로 가서


이렇게 스폰을 해주도록 하자.

그리고 씬에서 없애준다음에

이렇게 없애고 저장.

그러면

이제 이 Scene에서 동적으로 호출을해서 코드상에서 애내들을 만들어 줄 것이다.

그리고 유니티에서 실행을 해보면


만들어져서 이동은 원래대로 하는데

카메라가 따라가지를 않는다.


cameracontroller 보면은 우리가 직접 툴로 연결을 하도록 만들어서 그런거 같다.

그러면 이제 이것을 툴이 아니라 스크립트로 연결을 해주면 될거같다라는 생각이 든다.


그래서 이렇게 셋팅을 해주는 녀석을 만들면 될거같다.

그리고 다시 GameScene으로 가서

camera.main.gameObject로하면은 일단 우리가 main으로 사용할 카메라를 불러올 수 있다.

여기다가 이제 Cameracontroller스크립트로 접근을 해야한다.


그리고 이렇게 GetOrAddComponent로 접근을 해서 간단하게 셋팅을 해주고

다시 유니티에서 테스트를 해보도록 하자.

아까 카메라 컨트롤러가 Player를 못찾았는데

인자로

넣어주는 거랑 바뀌어서 그렇다. 이거 수정하면 잘된다.

그리고 이제 또하나 궁금한것이 삭제를 하면은 어떻게 될지가 굉장히 또 궁금하다.

우리가 MonsterController에서

Hp <= 0 일때 Destroy를 해주었었는데 이것이 아니라

우리가 GameManagerEx에 만든 버젼으로 삭제를 해주자.


이렇게 수정을 해주고 유니티에서 어떻게 될지 테스트를 해보자


그러면 없어졌는데 클릭은 된다 그리고 클릭을 하면 에러 메세지가 뜨는데


이런식으로 뜬다.


우리가 다시 GameManager로 가보면

뭐 이러이러한 작업을 거쳐서 Managers.Reosource.Destroy를 해주었었다.

그리고 이 Destroy함수를 타고 가보면은

우리가 예전에 Pooling을 해주었었다.


만약 Poolable타입이라고 한다면은 Manager에 Pool에 밀어 넣는 작업을 한적이 있었다.

그렇다는 것은 유니티짱이 Poolable인지 보면은


이렇게 @Pool_Root산하에 root보면은

유니티짱은 Poolable이 되는 객체인데


우리가 이렇게 제3의 우주공간(대기실)로 보내 버리고

꺼놓은 상태로 놔두어서 이렇다 중간에 플레이 상태에서 키면은 다시 생성이 된다!

그래서 정리를 하자면은

Player가 GameObject.Destroy를 해주면 더이상 유효하지가 않으니까

다른 애들이 null체크를 해가지고 더이상 유효하지 않다라는 것을 알 수 있었는데

이런식으로 풀링을 사용해서 DeActive상태가 될 경우에는

null체크 만으로는 판별할 수 없다라는 문제가 있다.

그래서 지금

유니티를 실행한 상태에서 플레이어가 죽은 상태에서

우리가 cameraController에서 null일 경우 return 한다고 했는데

이부분을 breakPoint를 잡고 유니티에 연결을 해보면


이렇게 잡고

하면 그냥 넘어가지는데 if문에 안걸리고

그러면 유추를 해볼 수 있는것이 지금 null인 상태가 아니라 그냥 꺼진 상태일 것이다.

그런데 꺼진 상태를 어떻게 판별하는지??

->
이녀석으로 activeSelf로 확인 할 수 있다.

그래서 if문에 조건을

activeSelf이거나 null일 경우 return 을 한다라고 수정을 해주어야 한다.


이렇게.

그리고 이렇게 매번 체크를 하기가 귀찮다! 라고하면은 Extension에다가 메소드로 만들어 주면 된다.

Extension에서

이렇게 함수를 만들어 주고

return 하는 값은 go가 null이 아니고
activeSelf가 true인 경우를 return해주면됨.


이렇게요.

이럴경우 Valid한 경우이다.

그러면 다시 cameraController로 돌아가가지고

이부분을


이렇게 false일 경우 return 을 하면된다.


그리고 여기 다시 잡고 유니티 실행 -> 딱 걸린다.

풀링을 할 경우 == null체크만으로는 부족하니까

Extension으로 체크를 해도되고

다양한방법으로 체크가 가능하다.

그래서 오늘 알아본 내용은 사실 굉장히 중요한 내용인데

결국에는

이렇게 GameManager라는 것을 만들고 여기서 뭔가를 관리를 하면 편안 하다는 사실인데 이것은 나중에 서버가 붙으면 더 중요한 부분이다.

이번시간에 했던 내용중에 가장 중요한것은

Detroy를 했을때

그 참조를 물고있던 애들이 어떻게 동작하느냐! 이것이 핵심적인 내용이였다.


3. 핵심

혹시라도

레퍼런스를 물고있는 애들중에서 하나를 GameObject.Destroy를 멋대로 때려 버리면

나머지 애들은 null체크를 이용을 해가지고

실제로 그녀석이 파괴된 객체인지 아닌지 판별 할 수 있다.


여기서 이런식으로 이렇게.

이것이 가장 핵심적인 내용이 될 것이고

그리고

혹시라도 파괴된 아이의 컴포넌트를 물고있던 아이들도

그 컴포넌트에 접근을 할려고 하는 순간

프로그램이 바로 크래쉬가 날테니까

그런 부분도 굉장히 조심해서 사용해야 한다! 이것이 결론이다.


4. 질문글들

profile
https://cjbworld.tistory.com/ <- 이사중

0개의 댓글