비트를 쪼개는 개발자

allen321@naver.com

Unity

Unity [디자인 패턴] - 싱글톤 패턴

MozarTnT 2024. 8. 7. 16:39
728x90
반응형

 

 

 

싱글톤 패턴이란?

 

 

  • 싱글톤 패턴은 특정 클래스의 인스턴스가 프로그램 전체에서 오직 하나만 존재하도록 만드는 디자인 패턴이다.

 

  • 해당 인스턴스를 호출하면 매번 새로운 인스턴스를 생성하는 것이 아니라 기존에 생성한 인스턴스를 반환한다.

 

  • 기존의 인스턴스를 재사용하기 때문에 메모리를 절약할 수 있지만 너무 많은 인스턴스를 싱글톤으로 만들면 스태틱 메모리에 너무 많은 인스턴스가 할당되어 있게 된다.

 

  • Singleton 객체에는 어디서나 static 변수로 참조값을 할당해서 모든 객체에서 쉽게 접근이 가능하도록 구현한다.

 

  • 씬과 씬 사이에 데이터를 공유하는 용도로도 사용함(DontDestroyOnLoad 함수 사용)

 

 

 

 

싱글톤이 필요한 경우

 

 

 

1. 많은 클래스에서 해당 클래스를 수시로 공유하는 경우

 

 

 

유니티에서는 보통 게임 시작 후 종료시 까지 존재해야 하는 중요한 기능들을 담당하는 스크립트나 오브젝트들은 Manager라는 이름을 붙여 따로 관리하는 경우가 많다.

 

 

예를 들어 사운드에 관한 기능은 많은 클래스에서 수시로 호출해야 하며 시작부터 끝까지 존재해야 한다.

 

 

이러한 경우에는 많은 개발자들이 SoundManager라는 스크립트를 만들어 관리하고, 다른 클래스에서 엑세스 하기 쉽도록 해당 기능은 싱글톤 패턴으로 만들어 버리면 편리하다.

 

 

 

2. Scene을 전환해도 통일된 값이나 데이터를 유지하고 싶은 경우

 

 

유니티는 Scene을 전환하면 이전 씬에서 사용 했던 데이터 값들이 초기화 되서 다음 Scene으로 넘어간다.

 

만약 여러가지 스테이지를 각각의 Scene으로 분리하고 스테이지가 넘어가도 HP나 MP와 같이 이전 씬에서 유지 되었던 데이터를 유지하고 싶을 경우에는 각각의 Scene에 있는 스크립트에서 이를 관리하기가 어렵다.

 

이러한 경우에 싱글톤 패턴을 이용해서 하나의 GameManager라는 오브젝트를 만들어 주고 이 오브젝트를 싱글톤 패턴으로 관리한다면 위와 같은 데이터 관리 및 함수 호출을 보다 쉽게 구현할 수 있다.

 

당연히 이 GameManager는 하나만 존재할 수 있도록 관리해야 하고 어떠한 상황에서도 호출이 용이하게 관리해야 한다.

 

 

 

싱글톤 패턴 사용 예시

 

 

 

싱글톤 패턴을 사용하는 방법은 상당히 다양하다.

 

싱글톤을 전담하는 스크립트나 class를 하나 만들어서 이 싱글톤 class를 상속 받아 사용하는 경우도 있고

 

해당 구현 기능이 필요한 스크립트에 그냥 싱글톤을 선언하는 경우도 있다.

 

 

싱글톤을 상속받아 사용하는 코드 예시

 

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;

    public static T Instance
    {
        get
        {
            if(instance == null)
            {
                instance = FindObjectOfType<T>();
            }
            return instance;
        }
    }
    private void Awake()
    {
        if(!instance)
        {
            instance = this as T;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

 

 

이렇게 싱글톤을 전담할 class를 하나 선언해 주고 필요할 때마다 위 class를 상속받아 사용하면 싱글톤을 쉽게 구현할 수 있다.

 

싱글톤을 상속받은  코드 예시

 

public class GameManager : E01Singleton<E01GameManager>
{
    private int currentLevel = 0;

    public void UpdatePlayerPosition(Vector3 playerPosition)
    {
        Debug.Log($"Player Position : {playerPosition}");
    }
    public void LoadNextLevel()
    {
        if(currentLevel > 0)
        {
            currentLevel = 0;
        }
        else
        {
            currentLevel = 1;
        }
        SceneManager.LoadScene(currentLevel);
    }
}

 

 

위 GameManager 코드는 싱글톤으로 오직 하나만 존재하게 만들 코드이며 임시로 Scene을 전환하는 기능을 전담시킬 예정이다.

 

원래 Scene이 전환된다면 currentLevel이라는 변수는 Scene 전환마다 매번 초기화 되어 다음 Scene으로 넘어갈때 이전 Scene의 level을 받아올 수 없지만

 

GameManager는 싱글톤 객체에 있는 DontDestroy 함수를 통해 다음 Scene으로 같이 넘어오기 때문에 이전의 Level을 할당시킬 수 있다.

 

 

즉 Scene을 전환 하면서 이전 Scene에 있는 특정 데이터를 계속 사양하고 싶을때 싱글턴 패턴을 이용하면 된다.

 

 

 

 

플레이어 객체가 이동하면서 초록색 큐브에 충돌한다면 다음 씬으로 이동하는 기능을 구현해보자.

 

초록색 큐브에 씬 이동이 가능한 코드는 다음과 같이 처리하자.

 

 

public class PortalController : MonoBehaviour
{
    private void OnTriggerEnter(Collider other)
    {
        if(other.CompareTag("Player"))
        {
            // 스테이지 이동
            GameManager.Instance.LoadNextLevel();
        }
    }
}

 

 

GameManager는 싱글톤 패턴을 이용해서 구현 했기 때문에 어디서든 호출할 수 있다. 

 

원래 Scene을 전환할때는 기존 스크립트에 할당한 변수들이 Scene이 전환되며 초기화 되지만 GameManager 오브젝트는 DontDestroyOnLoad 함수를 이용해 오브젝트를 관리하기 때문에 Scene이 전환되어도 변경된 Scene에 함께 넘어온다.

 

 

 

 

 

이상 없이 잘 동작하며 GameManager는 Scene 전환시 DontDestroyOnLoad를 통해 잘 유지된다.

 

 

 

 

사진 출처 : https://refactoring.guru/design-patterns/singleton

728x90
반응형