본문 바로가기

Unity/Unity 기타

Unity - 싱글톤패턴

- 일반적으로 Java나 코틀린등 타언어들과 같이 C#에서 클래스객체를 생성할때는 프로그램이 실행되는

 메인함수안에 new NewClass();을 코드로 작성하고 이를 실행하는 것으로 NewClass라는  클래스객체를 생성한다

 하지만 유니티엔진에서 클래스객체를 생성할때는 위와 같은 방식으로 객체를 생성할 수 있는것은 당연하고 추가로 

 하이라키창에 임의의 오브젝트를 생성하고 해당 오브젝트의 컴포넌트에 NewClass라는 스크립트를 붙여주는 방식

 으로도 객체생성이 가능하게 된다

 즉, NewClass라는 C#스크립트를 컴포넌트로 가진 임의의 오브젝트는 우리가 유니티 엔진상에서 눈으로 볼 수 있는   

 메모리구조의 힙영역에 생성된 가시화된 객체인 것이다.

 C#에서는 new 클래스명();과 같은 코드상의 객체 생성외에는 달리 객체를 생성할 방법이 없다 하지만 유니티엔진에서 는 하이라키창에 오브젝트를 직접생성하여 스크립트를 붙여준다던지, 메인함수에서 스크립트가 부착된 프리팹을 instantiate로 생성한다든지와 같은 새로운 객체가 생성될 여지가 많다

 

이것은 우리가 게임을 관리하는 로직이 담긴, 예를테면 NewClass 라는 C#스크립트를 컴포넌트로 가진 오브젝트( = 눈으로 가시화된 new NewClass()라는 객체)가 단 하나만 존재해야함을 보장되도록 하고 싶을때 만드는 싱글톤패턴에 대해 더 잘 이해할 수 있게 된다

 

- 우리는 게임을 관리할 로직인 GameManigerSc2 스크립트를 가진 오브젝트가 유니티엔진상에 존재하지 않는다면 생성할 것이고, 

( = new GameManigerSc2() 라는객체가 존재하지 않는다면 생성할 것이며)

이미 존재한다면 그 이후에 혹여나 같은 오브젝트가 생성될 시 그 오브젝트를 파괴할 것이다

( = new GameManigerSc2()객체는 오직 1개만 존재하도록 할 것이다)

 

여기서 주목해야할 점은 특정 객체가 힙영역에 이미 존재하는지, 존재하지 않는지를 어떤방식으로 체크해야 하느냐는 것이다, 일반적으로 특정 클래스의 객체를 여러개 생성하면 생성된 객체들끼리는 연관성이 없이 독립적으로 존재하게 된다 따라서 모든 생성된 객체들이 공통적으로 공유하는 메모리구조상 데이터영역에 존재하는 static 키워드를 활용하는 것이다

static 키워드로 현재 객체의 존재 유무에 대한 정보를 알수 있게 설계한다면

새롭게 생성된 객체가 내부적으로 static키워드를 살피면서 객체의 존재유무를 알 수 있게 되고, 없다면 본인이 단 한개의 객체가 되고, 이미 있다면 자기 자신은 사라지도록 만들 수 있는 것이다.

 

결론적으로 이러한 싱글톤을 구현하기 위해 초점을 둬야하는 것은 static으로 선언한 자기자신을 가르키는 변수를

어느시점에 초기화 해줄 것인지(int, string등 다른 자료형과는 다르게 class자체를 나타내는 자료형은 선언과 동시에 할당이 불가능하다)

또 객체가 새롭게 생성될때 초기화된 static 변수로써 자기자신의 객체가 존재하지 않는지 이미 생성되어있는지를 확인함과 동시에 새롭게 생성된 객체가 자신이 그 유일한 객체과 될지 스스로 파괴되어야할지를 어느시점에서 어떠한 방식으로 확인하고 실행할지가 관건이다

 

 

■싱글톤 구현 방식 1

static 변수 초기화 시점 

 - 외부에서 GameManigerSc2 클래스의 자기자신자료형을 나타내는 static변수를 호출(ex)Player스크립트에서 GameManigerSc2.Instance를 호출)하는 시점 에 해당 변수 초기화 

 

유일객체 확인 및 자가파괴 시점 

 - 객체가 생성될 시에 Awake()에서 GameManigerSc2스크립트를 가진 오브젝트(new GameManigerSc2() 객체)

가 몇개 인지 파악하여 1개가 아니라면 방금 생성된 스스로를 파괴(1개라면 본인이 유일한 객체이므로 형상유지) 

 

코드설명 

 - 외부에서 GameManigerSc2.Instance를 호출하는 순간 GameManigerSc2 class에서 static으로 선언한 instance

변수에 객체가 없다면 객체를 생성해서 생성한 객체를 할당하거나,

   이미 객체가 있다면 해당 객체를 할당한다(참조형인 객체를 값으로 할당하면 힙영역의 객체를 가르키는 주소값이 할당된다)

   즉, 데이터 영역에 존재하는 GameManigerSc2 자료형을 가진 instance라는 static 변수에 값을 할당하는 시점은

   외부에서 Instance를 호출하는 시점이다

 

 

 

- 이 후 같은 객체가 또 다시 중복되어 생성될때 Awake()에서 이미 생성된 객체가 있는지를 검사하고 있다면 자기 자신  을 파괴하도록 만든다

- 아래방식은 중복된 객체가 생성된 경우에는 GameManigerSc2라는 스크립트를 가진 오브젝트가 이미 존재했던 오브젝트 + 새로 중복되어 생성된 오브젝트 = 2개가 되기 때문에 if문에 걸리게 되어 자기 자신이 삭제 되는 것이다

 

 

 

싱글톤 구현 방식2 

static 변수 초기화 시점 

 - static변수를 초기화하는 시점은 방식1과 동일하나 코드상 표현방식을 좀더 간추린 것이고

 

유일객체 확인 및 자가파괴 시점 

 - 객체 생성시에 이미 객체가 존재하는지 파악하는 방식은 힙영역을 검사하는 방식1과 달리 내부적으로 데이터 영역을    검사하여  static 변수가 초기화 된 상태인지를 체크하는 방식으로 파악한다

 

 

 

싱글톤 구현 방식3

 static 변수를 초기화하는 시점

      1)하이라키 창에서 직접 오브젝트를 만들어 해당 스크립트를 붙여 넣은 상태에서,

      2)혹은 메인코드 상에서 해당 클래스가 미리 붙어있는 프리팹을 Instaniate해주었을때

 -  유니티 엔진의 Play버튼을 눌렀을때 이미 하이라키창에 존재한 스크립트 컴포넌트가 붙어있는 오브젝트(객체)가 존재한 상태로 해당 오브젝트의 스크립트안에 있는 Awake()함수가 실행되던지 혹은

 - 하이라키창에 오브젝트가 없던 상태에서 동일한 조건의 오브젝트인 프리팹(객체)이 instaniate되어 하이라키창에 생성되면서, 각 객체안에 존재하는 스크립트안에서 유니티 생명주기에 따라 Awake()함수가 실행될때 static instance변수에 자기 자신을 할당해주는 것이다

 

유일객체 확인 및 자가파괴 시점

   - 객체의 중복을 확인하여 스스로를 파괴할지를 결정하는 과정은 방식2와 같다

 

 

 

 

결론

 

- 결론적으로 세가지방식 모두 다 싱글톤 패턴을 구현하고 있으며 어떤 방식을 써야할지를 고찰해보자면...

 

 크게 보아 static 변수를 초기화하는 시점을 기준으로 방식1,2와 방식3은 구별된다

 메모리영역의 힙영역에 게임관리에 관한 객체가 1개도 존재하지 않는 경우라면 방식1과2는 메인함수에서               GameManigerSc2.Instance를 호출하는 것만으로 최초 객체를 생성해주고 초기화까지 해준다

 하지만 방식3은 GameMAnigerSc.instance를 호출하면 Null이 나올 것이다

 

 코드상의 편의성은 방식3이 간단하다 다만, 이 방식을 사용하려면 최초의 객체는 우리가 직접 하이라키창에 게임오브  젝트를 생성하고 스크립트를 붙여주던지, 혹은 메인함수에서 스크립트가 부착된 오브젝트인 프리팹을 생성해주던지 해야한다 

 

코드1,2는 위와같은 처리를 하지않아도 외부에서 GameManigerSc2.Instance를 호출하는것 만으로 스크립트가 부착된 오브젝트를 알아서 만들어주기때문에 코드는 복잡해보일지라도 싱글톤패턴+알파의 기능까지 한다고 볼 수 있다.

 

 

 

   

 

'Unity > Unity 기타' 카테고리의 다른 글

UnityC# - 추상클래스, 인터페이스  (0) 2021.05.04
UnityC# - 컬렉션, 구조체  (0) 2021.05.03
Unity - C# List정리  (0) 2021.04.23
Unity3D- FieldOfView 시야구현(최종)  (0) 2021.04.06
Unity3D- fieldOfView 시야구현(3)  (0) 2021.04.06