2025년, 코딩은 선택이 아닌 필수!

2025년 모든 학교에서 코딩이 시작 됩니다. 먼저 준비하는 사람만이 기술을 선도해 갑니다~

응용프로그래밍/유니티기초

[유니티기초] 2-02.싱글턴 패턴

파아란기쁨1 2022. 5. 31. 16:17
반응형
목표

싱글턴 패턴의 필요성을 알아보고 구현하는 방법을 살펴 보자.

 

싱글턴 패턴의 필요성

프로젝트를 수행할 때 관리자 역할을 하는 GameManager(파일매니저,몬스터매니저,점수매니저 등)는 프로그램에 단 하나만 존재해야 한다. 그리고 어디서든 즉시 접근이 가능해야 한다.

 

1. 단일 오브젝트 

만약 점수를 관리하는 점수매니저가 두개라고 하면 최고 점수도 두개가 될 수 있다. 이와 같은 이유로 관리매니저는 단 하나만 존재해야 한다.

 

2. 손쉬운 접근

매니저는 프로그램의 특정영역이 아나라 어느곳에서 사용할 수 있는 편의 기능을 제공한다. 따라서 매니저 오브젝트는 어느곳에서나 쉽게 접근하여 사용할 수 있도록 구현해야 된다.

 

3. 싱글턴을 사용하는 이유

  • 게임매니저 오브젝트는 단 하나만 존재
  • 어떤 곳에서도 손쉽게 게임 오브젝트에 접근 가능
싱글턴 패턴 구현

1. 싱글턴 패턴을 구현 시 Static 변수의 특징을 활용한다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Dog : MonoBehaviour
{
    public static int count = 0;
    // Start is called before the first frame update
    private void Awake() {
        count++;
        Debug.Log(count);
    }
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

count를 static 변수로 선언하면 외부에서 객체를 생성하지 않고 Dog.count = 10 과 같이 공유가 가능해 진다.

또한 static 변수는 다음과 같은 특징이 있다.

  • 메모리에 단 하나만 존재하고 모든 오브젝트가 공유한다.
  • 클래스 이름과 점(.)을 이용해 접근할 수 있다.

 

 

2. GameManager 

using UnityEngine;
using UnityEngine.SceneManagement;

// 점수와 게임 오버 여부를 관리하는 게임 매니저
public class GameManager : MonoBehaviour {
    // 외부에서 싱글톤 오브젝트를 가져올때 사용할 프로퍼티
    public static GameManager instance
    {
        get
        {
            // 만약 싱글톤 변수에 아직 오브젝트가 할당되지 않았다면
            if (m_instance == null)
            {
                // 씬에서 GameManager 오브젝트를 찾아 할당
                m_instance = FindObjectOfType<GameManager>();
            }

            // 싱글톤 오브젝트를 반환
            return m_instance;
        }
    }

    private static GameManager m_instance; // 싱글톤이 할당될 static 변수

    private int score = 0; // 현재 게임 점수
    public bool isGameover { get; private set; } // 게임 오버 상태


    private void Awake() {
        // 씬에 싱글톤 오브젝트가 된 다른 GameManager 오브젝트가 있다면
        if (instance != this)
        {
            // 자신을 파괴
            Destroy(gameObject);
        }
    }

    private void Start() {

    }

    // 점수를 추가하고 UI 갱신
    public void AddScore(int newScore) {
        // 게임 오버가 아닌 상태에서만 점수 증가 가능
        if (!isGameover)
        {
            // 점수 추가
            score += newScore;
            // 점수 UI 텍스트 갱신
            UIManager.instance.UpdateScoreText(score);
        }
    }

    // 게임 오버 처리
    public void EndGame() {
        // 게임 오버 상태를 참으로 변경
        isGameover = true;
        // 게임 오버 UI를 활성화
        UIManager.instance.SetActiveGameoverUI(true);
    }
    
    private void Update() {

    }

}

GameManager 가 생성 되어 있다면 생성 되어 있는 객체를 반환하고 만약 자신을 생성하려고 하는데 이미 생성된 객체가 있다면 자신을 파괴해 준다.

 

게임오버가 되면 UIManager의 게임오버 화면을 띄울 수 있도록 UIManager 클래스를 만들자.

 

using UnityEngine;
using UnityEngine.SceneManagement; // 씬 관리자 관련 코드
using UnityEngine.UI; // UI 관련 코드

// 필요한 UI에 즉시 접근하고 변경할 수 있도록 허용하는 UI 매니저
public class UIManager : MonoBehaviour {
    // 싱글톤 접근용 프로퍼티
    public static UIManager instance
    {
        get
        {
            if (m_instance == null)
            {
                m_instance = FindObjectOfType<UIManager>();
            }

            return m_instance;
        }
    }

    private static UIManager m_instance; // 싱글톤이 할당될 변수


    public Text scoreText; // 점수 표시용 텍스트
    public GameObject gameoverUI; // 게임 오버시 활성화할 UI 


    // 점수 텍스트 갱신
    public void UpdateScoreText(int newScore) {
        scoreText.text = "Score : " + newScore;
    }

    // 게임 오버 UI 활성화
    public void SetActiveGameoverUI(bool active) {
        gameoverUI.SetActive(active);
    }

    // 게임 재시작
    public void GameRestart() {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }
}

 

3. 화면 구성 및 스크립트 추가

플레이어가 바닥에 닿으면 게임오버 화면을 띄우는 프로그램을 만들어 보자

 

-  플레이어와 바닥을 만들어 놓은 후 collider를 만들어 놓는다.(플레이어에 Rigidbody 추가 하여 중력 발생)

- UI를 만들어서 Score 와 GameOver 텍스트를 추가하자.

- Canvas 에 UIManager를 추가하고 각각의 객체 매칭, GameObject를 생성하여 GameManager를 추가하자.

- 프로그램이 시작하면 Game Over를 보이지 않도록 처리해야 한다.

플레이어 이동 부분을 다음 파트에서 처리 하지만 먼저 PlayerMovement 스크립트를 다음과 같이 만들어서 플레이어에 추가 하자.

 

   private void Awake() {
      UIManager.instance.SetActiveGameoverUI(false);  
    }

실행해 보면 Game Over 는 사라지고 플레이어가 바닥에 닿는 것을 확인 할 수 있다.

여기서 떨어지는 시간 마다 업데이트에서 점수를 업데이트 해 보겠습니다.

PlayerMovement 스크립트에 다음을 추가

    void Update()
    {
        GameManager.instance.AddScore(++score); 
    }

실행을 해 보면 점수가 올라가는 것을 확인 할 수 있다.

 

바닥에 닿았을때 게임오버가 나오도록 처리해 보자.

바닥의 tag 를 bottom 로 만들어 주자. 플레이어가 바닥에 닿았는지 tag 속성을 확인해서 판단 한다.

PlayerMovement 스크립트에서 다음과 같이 바닥에 닿았는지 체크해 보자.

    private void OnCollisionEnter2D(Collision2D other) {
        if(other.gameObject.tag=="bottom"){
            UIManager.instance.SetActiveGameoverUI(true);  
        }
    }

부딪힌 게임오브젝트의 tag가 bottom 이라면 게임오버 화면을 활성화 시킨다.

 

 

연습문제

위의 화면에서 게임오버가 되어도 점수는 계속 올라간다.

점수 올라가는 것을 멈추게 하시오.

 

더보기

GameManager를 다음과 같이 변경하자.

    private void Start() {
        FindObjectOfType<PlayerMovement>().onDeath += EndGame;
    }

PlayerMovemnet 에서 onDeath 이벤트가 발생하면 EndGame을 실행하자.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class PlayerMovement : MonoBehaviour
{
    private int score = 0;
    public bool dead { get; protected set; } // 사망 상태
    public event Action onDeath; // 사망시 발동할 이벤트
    // Start is called before the first frame update
    private void Awake() {
      UIManager.instance.SetActiveGameoverUI(false);  
      Debug.Log("PlayerMovement");
    }
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if(dead) return;
        GameManager.instance.AddScore(++score);
        //UIManager.instance.UpdateScoreText(++score);    
    }

    private void OnCollisionEnter2D(Collision2D other) {
        if(other.gameObject.tag=="bottom"){
            Die(); 
        }
    }

    // 사망 처리
    public virtual void Die() {
        // onDeath 이벤트에 등록된 메서드가 있다면 실행
        if (onDeath != null)
        {
            onDeath();
        }

        // 사망 상태를 참으로 변경
        dead = true;
    }
}

onDeath 이벤트를 만들어서 발동시키면 GameManager 의 EndGame 메서드가 실행된다.

 

반응형