본문 바로가기
유니티 이야기

[Unity] 유니티 싱글톤 오브젝트의 활용 - singleton

by novices 2022. 9. 18.

프로그래밍을 설계 또는 디자인할 때 사용되는 디자인 패턴 중 하나인 싱글톤은 게임 개발 시 많이 사용되는 설계 방법입니다. 싱글톤은 프로젝트 안에서 유일하게 1개의 인스턴스로 존재하여 다른 클래스와 데이터 공유가 쉽다는 장점이 있습니다. 이런 이유로 게임 개발에서는 데이터 저장, 오디오 관리, 게임 점수 관리를 위해 사용되는 게임 매니저를 싱글톤으로 설계하고 구현하여 프로젝트 내 다른 클래스들과 연계하여 전체 기능을 구현합니다.

 

1. 게임 매니저 싱글톤으로 구현하기

아래는 게임 매니저를 만들고 해당 인스턴스를 할당할 정적 변수를 선언하고 Awake 함수에서 자신의 인스턴스를 할당하는 예제입니다. 게임 매니저는 score라는 게임 안에서 점수를 저장하는 정수 타입의 변수를 가지고 있으며 해당 점수는 AddScore 함수를 통해 점수 추가할 수 있습니다.

using UnityEngine;

public class GameManager : MonoBehaviour
{
    public static GameManager inst;
    private int score;
    
    void Awake()
    {
        inst = this;
    }
    public void AddScore(int newScore)
    {
        score += newScore;
    }
}

위에서 선언한 싱글톤 클래스인 GameManager의 inst 변수는 static 변수로 할당되어 다른 클래스에서 접근이 가능하고 다른 클래스 간의 데이터를 공유할 수 있는 상태가 됩니다. 예를 들어 몬스터가 사망했을 때나 퀘스트를 완료했을 때 추가 점수를 준다고 했을 때 각각의 클래스가 GameManager.inst.Addscore 함수에 입력으로 각각의 점수를 전달하면 간단하게 처리할 수 있습니다. 아래는 몬스터와 퀘스트 클래스의 예시입니다.

using UnityEngine;
//몬스터 클래스
public class Monster : MonoBehaviour
{
    private int MonsterScore = 30;
    void Die()
    {
    	// 게임매니저의 score에 몬스터 킬 점수를 추가합니다.
        GameManager.inst.AddScore(MonsterScore);
    }
}

//퀘스트 클래스
public class Quest : MonoBehaviour
{
    private int questScore = 100;
    public void QuestComplete()
    {
    	// 게임매니저의 score에 퀘스트 점수를 추가합니다.
        GameManager.inst.AddScore(questScore);
    }
}

 

싱글톤 구현 요점

  • 싱글톤 클래스는 인스턴스화 될 때 정적 변수에 인스턴스화 된 자기 자신을 할당합니다.
  • 다른 클래스에서 정적 변수를 통해 데이터를 쉽게 공유할 수 있습니다.

 

 

2. 싱글톤의 활용

싱글톤은 장점으로 여러 클래스들이 데이터 공유를 쉽게 할 수 있다는 점입니다. 추가로 게임에서는 각각의 오브젝트(클래스)가 개별로 동작하기 때문에 단순히 데이터 공유를 넘어 현재 게임 내에서 일어나고 있는 상태 값을 클래스 간 바로 알 수 있다는 점을 활용합니다. 예를 들어 효과음 설정의 On/Off 상태 저장 값을 싱글톤 클래스에 배치하여 몬스터의 사망 시나 퀘스트 완료 시 발생하는 효과음 처리를 다르게 사용할 수 있습니다.

using UnityEngine;

public class GameManager : MonoBehaviour
{
    public static GameManager inst;
    private int score;

    private bool sfxFlag = true;
    
    void Awake()
    {
        inst = this;
    }
    public void AddScore(int newScore)
    {
        score += newScore;
    }
    // 효과음 ON/OFF 상태를 리턴
    public bool GetSfxFlag(){return sfxFlag;}
}

public class Monster : MonoBehaviour
{
    private int MonsterScore = 30;
    void Die()
    {
        GameManager.inst.AddScore(MonsterScore);

        if(GameManager.inst.GetSfxFlag())
            // 몬스터 사망 사운드 재생
    }
}

public class Quest : MonoBehaviour
{
    private int questScore = 100;
    public void QuestComplete()
    {
        GameManager.inst.AddScore(questScore);

        if(GameManager.inst.GetSfxFlag())
            // 퀘스트 완료 사운드 재생
    }
}

 

싱글톤 활용 요점

  • 싱글톤 클래스를 통해 다른 클래스 간의 데이터 공유가 용이합니다.
  • 싱글톤 클래스를 통해 게임 내 상태를 서로 공유할 수 있습니다.

 

 

3. 싱글톤의 사용 시 주의할 점

첫 번째는 게임 매니저의 Awake 함수에서 인스턴스를 할당합니다. 그러므로 인스턴스 할당 시점 이전에 다른 클래스에서 접근하면 null오류가 발생할 수가 있습니다. 두 번째 scene이 변경될 경우 게임 매니저의 클래스가 파괴되므로 이전 scene의 데이터를 손실합니다. 첫 번째의 경우에는 다른 클래스가 Awake뒤의 시점에서 싱글톤에 접근하도록 주의하면 되고 두 번째의 경우 DontDestroyOnLoad함수를 사용해 scene이 변경되어도 해당 클래스의 게임 오브젝트가 파괴되지 않도록 처리하면 됩니다. 아래는 DontDestroyOnLoad 함수가 추가된 게임 매니저의 코드입니다.

using UnityEngine;

public class GameManager : MonoBehaviour
{
    public static GameManager inst;
    private int score;

    private bool sfxFlag = true;
    
    void Awake()
    {
        // inst 정적변수가 null 일경우만 할당하고
        // 게임 오브젝트에 DontDestroyOnLoad 처리를 한다.
        if (GameManager.inst == null)
        {
            GameManager.inst = this;
            DontDestroyOnLoad (gameObject);
        }
        else
        {
            // 이미 할당되어있는경우
            Destroy (gameObject);
        }
    }
    public void AddScore(int newScore)
    {
        score += newScore;
    }
    public bool GetSfxFlag(){return sfxFlag;}
}

 

싱글톤 주의할 점

  • 싱글톤 클래스가 static변수에 인스턴스를 할당하기 전에 다른 클래스에서 접근하지 않아야 합니다.
  • 다른 클래스에서 시점에 상관없이 싱글톤 정적 변수에 접근하려면 별도의 처리가 필요합니다.
  • scene 변경 시 싱글톤 클래스의 게임 오브젝트가 파괴되어 데이터를 잃을 수 있습니다.
  • scene 변경 시 DontDestroyOnLoad함수를 통해 게임 오브젝트를 보존할 수 있습니다.

 

 

댓글