R&D Prototype 생성

COrollaROOT·2025년 6월 23일
  • 필수 기능을 가진 Prototype 생성
    • GameManager
    • AudioManager
  • ScriptableObject를 사용

GameManager

  • Unity에서 GameManager는 게임의 전반적인 흐름과 상태를 중앙에서 관리하는 역활
  • 일반적으로 Singleton 패턴을 사용하여 하나의 인스턴스만 유지하도록 설계
  • 게임의 주요 시스템을 통합적으로 제어하는 기능 수행
  • 게임 시작, 일시 정지,종료 등의 흐름을 제어 또는 특정 이벤트(플레이어 사망,게임 클리어)가 발생하면 적절한 동작을 수행
  • 점수,플레이어 진행 상황,설정 등 데이터를 저장하고 불러오는 기능
  • JSON 파일, PlayerPrefs, ScriptableObject 등을 이용하여 데이터를 관리
  • 전역적인 접근이 필요한 객체를 관리 다른 스크립트에서 쉽게 접근할 수 있도록 싱글톤 패턴을 활용
  • 이벤트 시스템을 관리하여 게임에서 중요한 이벤트가 발생할 때 적절한 핸들링을 수행

Prototype

GameManagerSO.cs

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

[CreateAssetMenu(fileName = "GameManager", menuName = "Managers/GameManager")]
public class GameManagerSO : ScriptableObject
{
    // 게임 일시 정지 상태
    [HideInInspector] public bool isGamePaused;

    // 플레이어 점수
    [HideInInspector] public int score;

    // 점수 추가
    public void AddScore(int value)
    {
        score += value;
    }

    // 게임 일시 정지
    public void PauseGame()
    {
        isGamePaused = true;
        Time.timeScale = 0f;
    }

    // 게임 재개
    public void ResumeGame()
    {
        isGamePaused = false;
        Time.timeScale = 1f;
    }
}

GameManagerRunner.cs

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

public class GameManagerRunner : MonoBehaviour
{
    public GameManagerSO gameManager;

    void Start()
    {
        // 시작 시 게임 재개 상태로 초기화
        gameManager.ResumeGame();
    }
}

AudioManager

  • 사운드를 여러 오브젝트에 붙이고, 특정 조건이 발생하면 실행할 수 있지만
    씬 규모가 커지면 관리하기 힘들수 있다
  • 하나의 AudioManager를 싱글톤 패턴을 이용하여 구현 하여 다른 스크립트에서 쉽게 접근이 가능하고 관리도 용이한 형태로 AudioManager 구현
  • ScriptableObject 사용

Prototype

AudioManagerSO.cs

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

[CreateAssetMenu(fileName = "AudioManager", menuName = "Managers/AudioManager")]
public class AudioManagerSO : ScriptableObject
{
    // 런타임에서 주입받는 AudioSource들
    [HideInInspector] public AudioSource bgmSource;
    [HideInInspector] public AudioSource sfxSource;

    public void Init(AudioSource bgm, AudioSource sfx) // AudioSource를 외부에서 주입
    {
        bgmSource = bgm;
        sfxSource = sfx;
    }

    // 배경음악 재생
    public void PlayBGM(AudioClip clip)
    {
        if (bgmSource == null || clip == null) return;
        bgmSource.clip = clip;
        bgmSource.Play();
    }

    // 효과음 재생
    public void PlaySFX(AudioClip clip)
    {
        if (sfxSource == null || clip == null) return;
        sfxSource.PlayOneShot(clip);
    }

    // 배경음악 정지
    public void StopBGM()
    {
        bgmSource?.Stop();
    }
}

AudioManagerRunner.cs

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

public class AudioManagerRunner : MonoBehaviour // // AudioSource를 ScriptableObject에 연결하는 러너
{
    public AudioManagerSO audioManager;
    public AudioSource bgmSource;
    public AudioSource sfxSource;

    void Awake()
    {
        audioManager.Init(bgmSource, sfxSource); // 런타임 AudioSource 주입
    }
}

SceneManager

  • 편집기의 플레이어와 재생 모드에서 장면을 관리 합니다
  • SceneManager를 사용하면 플레이어에서 장면을 관리하고 조작할 수 있습니다

Prototype

SceneTransitionManagerSO.CS

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


[CreateAssetMenu(fileName = "SceneManager", menuName = "Managers/SceneManager")]
public class SceneTransitionManagerSO : ScriptableObject
{
    // 이름으로 씬 로딩
    public void LoadScene(string name)
    {
        SceneManager.LoadScene(name);
    }

    // 현재 씬 리로드
    public void ReloadCurrentScene()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }
}

InputManager

  • Update() 함수 안에서 플레이어마다 키를 반복하는 방식은 매우 비효율적인 방식이다
  • 공통된 기능을 이벤트로 받아 처리하는 클래스로 구현

Prototype

InputManagerSO.cs

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

[CreateAssetMenu(fileName = "InputManager", menuName = "Managers/InputManager")]
public class InputManagerSO : ScriptableObject
{
    public KeyCode pauseKey = KeyCode.Escape;

    // 일시 정지 키 입력 확인
    public bool IsPausePressed()
    {
        return Input.GetKeyDown(pauseKey);
    }
}

InputManagerRunner.cs

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

public class InputManagerRunner : MonoBehaviour
{
    public InputManagerSO inputManager;
    public GameManagerSO gameManager;
    public UIManagerSO uiManager;

    void Update()
    {
        if (inputManager.IsPausePressed())
        {
            if (gameManager.isGamePaused)
            {
                gameManager.ResumeGame();
                uiManager.ShowPauseUI(false);
            }
            else
            {
                gameManager.PauseGame();
                uiManager.ShowPauseUI(true);
            }
        }
    }
}

UIManager

  • UI를 관리해주는 역활
  • 전체 닫기,뒤로 가기, 예약 기능, 일시정지, 게임 재개, 설정창 적용 등

Prototype

UIManagerSO.cs

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

[CreateAssetMenu(fileName = "UIManager", menuName = "Managers/UIManager")]
public class UIManagerSO : ScriptableObject
{
    [HideInInspector] public GameObject pauseUI;

    // UI 패널 객체 연결
    public void Init(GameObject pausePanel)
    {
        pauseUI = pausePanel;
    }

    // 일시 정지 UI On/Off
    public void ShowPauseUI(bool show)
    {
        if (pauseUI != null)
            pauseUI.SetActive(show);
    }
}

UIManagerRunner.cs

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

public class UIManagerRunner : MonoBehaviour
{
    public UIManagerSO uiManager;
    public GameObject pausePanel;

    void Awake()
    {
        uiManager.Init(pausePanel);
    }
}

ObjectPoolManager

  • 게임에서 객체를 생성하고 삭제하는 대신 재사용하여 성능을 최적화하는 시스템
  • 미리 생성된 객체들을 풀(Pool)에 저장해두고 필요할 때마다 가져와 사용
    사용후엔 다기 풀(Pool)에 반환하여 재사용(동적할당과 해제를 줄여 성능을 향상 시킬 수 있습니다)

Prototype

ObjectPoolManagerSO.cs

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

[CreateAssetMenu(fileName = "ObjectPoolManager", menuName = "Managers/ObjectPoolManager")]
public class ObjectPoolManagerSO : ScriptableObject
{
    // 풀 저장소 (key: 프리팹 이름)
    private Dictionary<string, Queue<GameObject>> pool = new();

    // 오브젝트 풀 생성
    public void CreatePool(string key, GameObject prefab, int count)
    {
        if (!pool.ContainsKey(key))
            pool[key] = new Queue<GameObject>();

        for (int i = 0; i < count; i++)
        {
            GameObject obj = Instantiate(prefab);
            obj.SetActive(false);
            pool[key].Enqueue(obj);
        }
    }

    // 풀에서 꺼내기
    public GameObject Spawn(string key, Vector3 pos, Quaternion rot)
    {
        if (!pool.ContainsKey(key) || pool[key].Count == 0) return null;

        GameObject obj = pool[key].Dequeue();
        obj.transform.SetPositionAndRotation(pos, rot);
        obj.SetActive(true);
        return obj;
    }

    // 풀에 반환
    public void Despawn(string key, GameObject obj)
    {
        obj.SetActive(false);
        pool[key].Enqueue(obj);
    }
}

ObjectPoolRunner.cs

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

public class ObjectPoolRunner : MonoBehaviour // 오브젝트 풀 매니저에 초기 풀 생성
{
    public ObjectPoolManagerSO poolManager;
    public GameObject prefab;
    public string key = "Bullet";

    void Awake()
    {
        poolManager.CreatePool(key, prefab, 20);
    }
}

이후 필요 기술 R&D

profile
"시들지 않는 꽃"

0개의 댓글