본문 바로가기

유니티 교재 정리_ 싱글턴 (248pg~255pg) 멋쟁이사자처럼 43회차 1

@salmu2025. 7. 24. 16:49
반응형

1. 싱글턴

:프로그램에서 단 하나만 존재하는 객체를 만들고, 어디서든 쉽게 접근할 수 있게 하는 디자인 패턴

1개만 존재 무조건 하나만 만들어짐
전역 접근 클래스명.Instance로 언제 어디서든 사용 가능
상태 공유 여러 스크립트에서 같은 값을 볼 수 있음

 

  • 유일성 보장
  • 다른 클래스에서 쉽게 접근 가능 ⭕ → 코드 간결성 ⬆
  • 하나만 존재할 수 있는 클래스 → 다른 클래스와 혼동할 가능성이 적음
  • 원하는 시점에 생성할 수 있음 → 유연한 초기화
  • MonoBehaviour 상속 가능 → 다양한 Unity C# 기능 활용
  • 객체로써 존재 → 객체 지향의 디자인 패턴
  • Manager등에 활용 /씬 이동에도 유지 가능 (DontDestroyOnLoad)

 

정적 클래스 (Static Class)

  • 메모리 상에 언제나 존재하는 클래스 → 메모리 공간 차지
  • Static 클래스가 포함한 변수나 함수도 모두 Static으로 존재 → 메모리 공간 더 차지
  • 객체로써 존재 X → 객체 지향의 방식이 아님

 

[싱글턴 예시]

public class SingletonEx : MonoBehaviour
{
    private static SingletonEx instance;
    // SingletonEx2라는 클래스 자체를 타입으로 갖는 Instance라는 이름의 속성(Property)을 선언하는 것

    // 외부에서 접근 가능하게 하고, 내부에서만 할당 가능
    public static SingletonEx Instance
    {
        get { return instance; }
    }

    void Awake()
    {
        if (instance == null)
        {
            instance = this;

            // 씬이 전환되어도 오브젝트 유지됨
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            // 중복 방지
            Destroy(gameObject);
        }
    }
}

 

 

 

[유일성 보장 싱글턴]

public class SingletonEx : MonoBehaviour
{
    private static SingletonEx instance;

    public static SingletonEx Instance
    {
        get
        {
            // 인스턴스가 없다면
            if (instance == null)
            {
                // 씬 안에서 해당 컴포넌트 탐색
                var obj = FindObjectOfType<SingletonEx>();

                if (obj != null)
                    instance = obj;
                else
                {
                    // 없으면 새 GameObject 만들어서 컴포넌트 붙임
                    var newObj = new GameObject("SingletonEx");
                    instance = newObj.AddComponent<SingletonEx>();
                }
            }

            return instance;
        }
    }

    void Awake()
    {
        if (instance == null)
        {
            instance = this;

            // 씬 이동 시 파괴되지 않도록 유지
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            // 이미 존재하면 자기 자신 제거
            Destroy(gameObject);
        }
    }
}

 

 

  일반 싱글턴 유일성 보장 싱글턴
초기화 방식 오브젝트가 씬에 직접 존재해야 함 씬에 없어도 자동으로 생성됨
필수 구성 Awake()에서 직접 instance 지정 Instance 프로퍼티에서 탐색/생성
씬 내 존재 여부 미리 배치된 GameObject 필수 없어도 괜찮음 (자동 생성)
사용 편의성 수동 배치 필요 자동 생성되므로 스크립트만 있으면 OK
GameObject 이름 지정 자유 자동 생성 시 이름 지정 필요
사용 시 주의점 여러 씬에 중복 배치 주의 Awake() 두 번 호출될 수 있어 관리 필요

 

 

 

 

[Generic Singleton] 

public class Singleton<T> : MonoBehaviour where T : Component

: TMonoBehaviour 또는 Component를 상속받는 타입만 허용됨

: 다양한 클래스에서 상속해서 싱글턴 구조를 재사용 가능

  • 예: GameManager : Singleton<GameManager>, AudioManager : Singleton<AudioManager>

1. 

using UnityEngine;

// T는 Component를 상속받은 타입이어야 함
public class Singleton<T> : MonoBehaviour where T : Component
{
    // 실제 싱글턴 인스턴스를 저장할 static 변수
    private static T instance;

    // 외부에서 접근할 수 있는 정적 프로퍼티
    public static T Instance
    {
        get
        {
            // 아직 인스턴스가 없으면 생성 또는 찾기
            if (instance == null)
            {
                // 씬에 있는 T 타입 오브젝트를 찾음
                var t = FindFirstObjectByType<T>();

                if (t != null)
                {
                    // 이미 존재하면 그것을 인스턴스로 사용
                    instance = t;
                }
                else
                {
                    // 존재하지 않으면 새로운 GameObject 생성 후 T를 붙임
                    var newObj = new GameObject(typeof(T).ToString());
                    newObj.AddComponent<T>();

                    // 붙인 컴포넌트를 instance에 저장
                    instance = newObj.GetComponent<T>();
                }
            }

            return instance;
        }
    }

    // 유니티의 생명주기 함수: 오브젝트가 생성될 때 호출됨
    protected virtual void Awake()
    {
        // 인스턴스가 없으면 지금 이 오브젝트로 지정
        if (instance == null)
        {
            instance = this as T;

            // 씬 전환 시에도 파괴되지 않게 설정
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            // 이미 인스턴스가 있으면 중복 생성 방지를 위해 파괴
            Destroy(gameObject);
        }
    }
}

1

1

1

 

 

-> 사용 예시

public class GameManager : Singleton<GameManager>
{
    public int score = 0;

    void Start()
    {
        Debug.Log("Score: " + score);
    }
}

 GameManager.Instance.score로 어디서든 접근 가능함.

 

 

 

2. [Unity최적화 코드]

using UnityEngine;

// 제네릭 싱글턴 클래스 선언
// T는 반드시 MonoBehaviour를 상속해야 함 (유니티 컴포넌트로만 사용 가능)
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    // 실제 싱글턴 인스턴스를 담을 정적 변수
    static T instance = null;

    // 외부에서 접근할 수 있는 프로퍼티
    public static T Instance
    {
        get
        {
            // 아직 인스턴스가 생성되지 않았다면
            if (instance == null)
            {
                // 씬 안에서 해당 타입의 오브젝트를 검색
                instance = FindFirstObjectByType<T>();

                // 그래도 못 찾으면
                if (instance == null)
                {
                    // 새 GameObject를 만들고, 그 안에 T 컴포넌트를 붙여서 인스턴스를 생성
                    var newObj = new GameObject(typeof(T).ToString());
                    instance = newObj.AddComponent<T>();
                }
            }

            // 인스턴스 반환
            return instance;
        }
    }

    // 유니티 생명주기 함수: 오브젝트가 생성될 때 호출됨
    protected virtual void Awake()
    {
        // 아직 instance가 없으면 자신을 할당
        if (instance == null)
        {
            instance = this as T;

            // 씬이 바뀌어도 이 오브젝트를 파괴하지 않음
            DontDestroyOnLoad(this.gameObject);
        }
        else
        {
            // 이미 instance가 존재한다면 중복 방지를 위해 파괴
            Destroy(this.gameObject);
        }
    }
}

 

 

반응형
salmu
@salmu :: SMU 각종 기록

목차