유니티/멋쟁이사자처럼

[멋쟁이 사자처럼 부트 캠프 TIL 회고] Unity 게임 개발 3기 - 디자인 패턴 이란?

몰캉이이 2025. 1. 1. 17:48

디자인 패턴

목차

    1. 기본 개념

    게임 개발 과정에서 자주 발생하는 문제들을 해결하기 위한 재사용 가능한 솔루션

    • 코드의 재사용성 향상
    • 유지보수 용이성
    • 확장성 개선
    • 협업 효율화

    2. 핵심 디자인 패턴

    1. Singleton

    더보기
    public class GameManager : MonoBehaviour
    {
        private static GameManager instance;
        public static GameManager Instance
        {
            get {
                if (instance == null)
                {
                    instance = FindObjectOfType<GameManager>();
                    if (instance == null)
                    {
                        GameObject go = new GameObject("GameManager");
                        instance = go.AddComponent<GameManager>();
                    }
                }
                return instance;
            }
        }
    
        void Awake()
        {
            if (instance == null)
            {
                instance = this;
                DontDestroyOnLoad(gameObject);
            }
            else if (instance != this)
            {
                Destroy(gameObject);
            }
        }
    }

    2. Observer 

    더보기
    public class EventManager
    {
        private Dictionary<string, Action<object>> eventDictionary = new Dictionary<string, Action<object>>();
    
        public void Subscribe(string eventName, Action<object> listener)
        {
            if (!eventDictionary.ContainsKey(eventName))
            {
                eventDictionary[eventName] = null;
            }
            eventDictionary[eventName] += listener;
        }
    
        public void Unsubscribe(string eventName, Action<object> listener)
        {
            if (eventDictionary.ContainsKey(eventName))
            {
                eventDictionary[eventName] -= listener;
            }
        }
    
        public void TriggerEvent(string eventName, object data)
        {
            if (eventDictionary.ContainsKey(eventName))
            {
                eventDictionary[eventName]?.Invoke(data);
            }
        }
    }

    3. State

    더보기
    public interface IPlayerState
    {
        void Enter();
        void Update();
        void Exit();
    }
    
    public class IdleState : IPlayerState
    {
        private Player player;
    
        public IdleState(Player player)
        {
            this.player = player;
        }
    
        public void Enter()
        {
            player.Animator.Play("Idle");
        }
    
        public void Update()
        {
            // Check for state transitions
            if (Input.GetKeyDown(KeyCode.Space))
            {
                player.ChangeState(new JumpState(player));
            }
        }
    
        public void Exit()
        {
            // Cleanup code
        }
    }
    
    public class Player : MonoBehaviour
    {
        private IPlayerState currentState;
        public Animator Animator { get; private set; }
    
        public void ChangeState(IPlayerState newState)
        {
            currentState?.Exit();
            currentState = newState;
            currentState.Enter();
        }
    
        void Update()
        {
            currentState?.Update();
        }
    }

    4. Command

    더보기
    public interface ICommand
    {
        void Execute();
        void Undo();
    }
    
    public class MoveCommand : ICommand
    {
        private Transform transform;
        private Vector3 direction;
        private float speed;
        private Vector3 previousPosition;
    
        public MoveCommand(Transform transform, Vector3 direction, float speed)
        {
            this.transform = transform;
            this.direction = direction;
            this.speed = speed;
        }
    
        public void Execute()
        {
            previousPosition = transform.position;
            transform.Translate(direction * speed * Time.deltaTime);
        }
    
        public void Undo()
        {
            transform.position = previousPosition;
        }
    }

    3. Unity 특화 패턴

    1. Component

    더보기
    public class Health : MonoBehaviour
    {
        [SerializeField] private float maxHealth = 100f;
        private float currentHealth;
    
        void Start()
        {
            currentHealth = maxHealth;
        }
    
        public void TakeDamage(float damage)
        {
            currentHealth -= damage;
            if (currentHealth <= 0)
            {
                Die();
            }
        }
    
        private void Die()
        {
            // Death logic
        }
    }

    2. Object Pool

    더보기
    public class ObjectPool : MonoBehaviour
    {
        [System.Serializable]
        public class Pool
        {
            public string tag;
            public GameObject prefab;
            public int size;
        }
    
        public List<Pool> pools;
        public Dictionary<string, Queue<GameObject>> poolDictionary;
    
        void Start()
        {
            poolDictionary = new Dictionary<string, Queue<GameObject>>();
    
            foreach (Pool pool in pools)
            {
                Queue<GameObject> objectPool = new Queue<GameObject>();
    
                for (int i = 0; i < pool.size; i++)
                {
                    GameObject obj = Instantiate(pool.prefab);
                    obj.SetActive(false);
                    objectPool.Enqueue(obj);
                }
    
                poolDictionary.Add(pool.tag, objectPool);
            }
        }
    
        public GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation)
        {
            if (!poolDictionary.ContainsKey(tag))
                return null;
    
            GameObject objectToSpawn = poolDictionary[tag].Dequeue();
            objectToSpawn.SetActive(true);
            objectToSpawn.transform.position = position;
            objectToSpawn.transform.rotation = rotation;
    
            poolDictionary[tag].Enqueue(objectToSpawn);
            return objectToSpawn;
        }
    }

    4. 패턴 선택 가이드

    1. Singleton

    • 글로벌 상태 관리가 필요할 때
    • 리소스 관리자가 필료할 때

    2. Observer

    • 시스템 간 결합도를 낮추고 싶을 때
    • 이벤트 기반 시스템 구현 시
    • UI 업데이트 처리 시

    3. State

    • 복잡한 상태 전이가 필요할 때
    • 캐릭터 행동 관리 시
    • 게임 플로우 제어 시

    4. Object Pool

    • 빈번한 생성/파괴가 있는 객체 처리 시
    • 파티클 시스템 구현 시
    • 총알이나 적 캐릭터 스폰 시

     

    5. 주의 사항

    1. 과도한 패턴 사용 피하기

    • 필요한 곳에만 적절한 패턴 적용
    • 코드 복잡도 증가 고려

    2. 성능 고려

    • 패턴 적용으로 인한 오버헤드 확인
    • 최적화 필요설 검토

    3. 유지보수성

    • 문서화 중요
    • 팀원들과의 커뮤니케이션