패링 게임 - 9 (싱글톤, 이벤트)

Labin·2025년 4월 24일

패링 게임

목록 보기
11/14

싱글톤

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject); 
        }
        else
        {
            Destroy(gameObject);
        }
    }

싱글톤 클래스의 Instance 정적 속성을 통해 어디서든 접근할 수 있습니다. 이것이 가능한 이유는:

  1. public static MonsterManager Instance 속성이 클래스 자체에 속해 있기 때문에 인스턴스 생성 없이 접근 가능
  2. 정적(static) 멤버는 프로그램 실행 중 항상 메모리에 존재하므로 어디서든 접근 가능
  3. Unity의 경우 싱글톤 인스턴스는 보통 Awake() 메서드에서 초기화되므로 게임 시작 후 바로 사용 가능

단, 싱글톤 패턴 사용 시 주의할 점은:

  1. 인스턴스가 초기화되기 전에 접근하면 null 참조 오류가 발생할 수 있으므로 null 체크는 항상 하는 것이 좋습니다
  2. 과도한 싱글톤 사용은 코드 의존성을 높여 테스트와 유지보수를 어렵게 만들 수 있습니다

Event

monstermanager.cs

public event System.Action OnAllMonstersDead;

이벤트를 선언하고

        if (!wasAllDead && allDead)
        {
            Debug.Log("모든 몬스터가 죽었습니다!");
            OnAllMonstersDead?.Invoke();
        }

Invoke로 이벤트에 등록된 모든 delegate 호출.

delegate는

gamemanager.cs

    private void Start()
    {
        // MonsterManager의 이벤트 구독
        if (MonsterManager.Instance != null)
        {
            MonsterManager.Instance.OnAllMonstersDead += OnAllMonstersDead;
        }
    }
    
    private void OnDestroy()
    {
        // 이벤트 구독 해제
        if (MonsterManager.Instance != null)
        {
            MonsterManager.Instance.OnAllMonstersDead -= OnAllMonstersDead;
        }
    }
     private void OnAllMonstersDead()
    {
        Debug.Log("모든 몬스터가 처치되었습니다! 다음 스테이지로 진행합니다.");
        NextStage();
    }
    
    public void NextStage()
    {
        int currentStageIndex = stageIndex;
        if (currentStageIndex < stages.Length - 1)
        {
            stages[currentStageIndex].SetActive(false);
            stages[currentStageIndex + 1].SetActive(true);
            stageIndex++; // 스테이지 인덱스 증가 추가
        }
        else
        {
            Debug.Log("모든 스테이지를 클리어했습니다!");
            // 게임 클리어 로직
        }
    }

게임 매니저에서 이벤트를 등록해둠.
그러면 모든 몬스터가 죽는 순간, 이벤트 실행. 구독된 OnAllMonstersDead()가 실행되고
그에 따라 다음 스테이지로 진행됨.

Invoke()

이벤트(Event)의 Invoke() 메서드:
이벤트에서 사용되는 Invoke()는 이벤트에 등록된 모든 구독자(delegate)를 즉시 호출합니다. 이것은 대기하지 않고 즉시 실행

OnAllMonstersDead?.Invoke(); // 즉시 모든 구독자 호출

MonoBehaviour의 Invoke() 메서드:
Unity의 MonoBehaviour 클래스에 있는 Invoke() 메서드는 지정된 시간 후에 함수를 호출하는 메서드입니다.

Invoke("FunctionName", 2.0f); // 2초 후에 FunctionName 함수 호출

해결한 문제

        if (m_stats.IsDead())
        {
            m_animator.SetBool("Death", true);
            m_sensorCollider.enabled = false; // 죽으면 센서 비활성화

            MonsterManager.Instance.UnregisterMonster(m_monster); // 몬스터 매니저에서 등록 해제
            Destroy(transform.parent.gameObject, m_stats.DeathTime);
        }   

여기서 몬스터가 죽었을 경우 Destroy를 transform.root.gameObject로 했었다.
근데 자꾸 모든 스테이지가 사라지는 오류가 생겨서 뭔지 도무지 몰랐는데 알고보니 monster를 stage의 자식 오브젝트로 넣으면서 destroy를 스테이지 자체를 해버린거다...
이를 parent로 바꾸면서 해결했는데 찾는데 한참 걸렸다.
애초에 스테이지를 생각하면 root로 한다는 것 자체가 멍청했던 판단.

profile
공부를 기록하는 공간

0개의 댓글