목표 |
싱글턴 패턴의 필요성을 알아보고 구현하는 방법을 살펴 보자.
싱글턴 패턴의 필요성 |
프로젝트를 수행할 때 관리자 역할을 하는 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 메서드가 실행된다.
'응용프로그래밍 > 유니티기초' 카테고리의 다른 글
[유니티기초] 2-03. 두 객체가 부딪혔을 때 밀림 방지 (0) | 2022.05.31 |
---|---|
[유니티기초] 2-02. 다형성과 인터페이스 (0) | 2022.05.31 |
[유니티기초]2-01.에셋스토어에서 2D 이미지 다운받아 적용하기 (0) | 2022.05.31 |
[유니티기초]1-10. 카메라 이동 (0) | 2022.05.30 |
[유니티기초]1-09. 객체 방향 전환 (0) | 2022.05.30 |