MonoBehaviour ← Behaviour ← Component ← Object
⇒ 즉, MonoBehaviour를 상속받는 모든 스크립트는 GameObject에 붙을 수 있다!!
UI, Sound, Network, Scene관리 …. 많은 것들이 들어감.
Manager는 관리용 스크립트일 뿐 GameObject에 붙어서 실행시키는 것이 아니다! 그래서 MonoBehaviour의 상속을 받을 필요가 없다.
⚠️ 그렇다고 MonoBehaviour 상속을 지우면, Start(), Update()함수 실행이 안된다;;;;
💡그냥 MonoBehaviour 상속을 유지하고, 하이어라키창에서 빈게임오브젝트(좌표reset) 생성해서 스크립트를 붙여주고 실행한다.
: 객체의 인스턴스를 한개만 생성되게 하는 패턴.
: 주로 프로그램 내에서 하나로 공유를 해야하는 객체가 존재할 때 해당 객체를 싱글톤으로 구현하여 모든 유저 또는 프로그램들이 해당 객체를 공유하며 사용하도록 할 때 사용된다.
- 프로그램 내에서 하나의 객체만 존재해야 할 때
- 프로그램 내에서 여러 부분에서 해당 객체를 공유하여 사용해야 할 때
💡 싱글톤 패턴을 사용하는 이유
메모리 측면의 이점
한 개의 인스턴스만을 고정 메모리에 생성하고 추가 생성하지 않기 때문에 추후 해당 메모리에 접근할 때 메모리 낭비를 방지할 수 있다.
속도 측면의 이점
생성된 인스턴스를 사용할 때는 이미 생성된 인스턴스를 활용하기 때문에 속도에서도 이점이 있다.
데이터 공유가 쉽다
전역으로 사용하는 인스턴스이기 때문에 다른 여러 클래스에서 데이터를 공유하며 사용할 수 있다. 하지만 동시성 문제가 발생할 수 있어 이 점은 유의하여 설계해야 함.
💡Managers를 Singleton으로 단일화시켜 사용한다.
ㄴ하지만 이렇게 Instance = this;로 자기 자신을 Instance에 넣어서 초기화해준다면, @Managers가 한 개 밖에 없을 때에는 문제가 없지만, 만약 누군가 하이어라키에서 Managers 스크립트가 있는 @Managers 오브젝트를 @Managers(1),(2).. 복사해버렸다면, 모두 각자 자신을 Instance로 초기화하는 문제가 발생한다. 이에, 사용할 @Managers로만 초기화되도록 아래와 같이 작성한다.
⚠️ 하지만, 만약 @Managers 객체가 없다면? 이 코드에는 문제가 발생한다!!
그래서, Init()함수로 초기화 상태를 설정해준다. null체크를 통해 s_instance가 아직 없다면 @Managers를 찾고, 만약 해당 객체가 없다면 직접 만들고 Managers 컴포넌트까지 추가한 후, 해당 컴포넌트를 s_instance에 넣어준다!
public class Managers : MonoBehaviour
{
static Managers s_instance; //유일성이 보장된다.
public static Managers Instance { get { Init(); return s_instance; } }
//외부에서 사용할 때 유일한 매니저를 갖고 온다.
//다른 오브젝트에서 먼저 Instance로 Managers 객체를 생성해도 null인 경우 체크해서 새로 만들어서 return해줌
void Start()
{
//만약 운좋게 Start()가 실행되면 Init()실행
Init();
}
static void Init() //초기화
{
if(s_instance == null)
{
GameObject go = GameObject.Find("@Managers");
if(go == null)
{
//하이어라키에 코드로 오브젝트만들고 스크립트 넣음
go = new GameObject { name = "@Managers" };
go.AddComponent<Managers>();
}
DontDestroyOnLoad(go);
s_instance = go.GetComponent<Managers>();
}
}
}
ㄴ원래는 외부에서 사용할 때 GetInstace()라는 함수로 불러오도록 했는데, 함수로 불러오는게 괄호때문에 괜히 번거로우니까 Instance 프로퍼티로 만들어줬다.
public class Player : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Managers mg = Managers.Instance;
}
}