내일배움캠프 35일차 TIL, 디자인 패턴

황오영·2024년 6월 5일
0

TIL

목록 보기
35/56
post-thumbnail
  • 오늘은 디자인 패턴 특강이벤트에 대해 정리해보는 TIL을 작성!
    <출처 : 챌린지반 강의노트>

Pub-Sub(옵저버/이벤트 버스) 패턴

옵저버/이벤트 버스 패턴?

  • 옵저버 패턴의 일정이며 다수의 Consumer가 자신이 관심 있는 이벤트를 비동기적으로 수신할 수 있도록 한다.
  • 시스탬 내의 다양한 구성 요소들이 느슨하게 결합되어 상호작용할 수 있도록 도와준다.
  • 다만 궁금하지도 않은 정보를 대상으로 뿌리는 스팸형 설계 라던가 프레임마다 설계를 확인하는 방식은 지양해야 하므로 나오게 된 패턴이 이벤트 기반의 설계이다.
  • 옵저버 패턴은 이벤트를 오브젝트가 발생시킬 경우 이를 구독하는 구독자들의 함수를 실행시키는 패턴이라고 보면된다. 발행자가 1명일때 구독자가 N명인 방식
using System;
using System.Collections.Generic;

public static class EventBus
{
    private static Dictionary<string, Action> eventDictionary = new Dictionary<string, Action>();

    public static void Subscribe(string eventName, Action listener)
    {
        if (eventDictionary.TryGetValue(eventName, out Action thisEvent))
        {
            thisEvent += listener;
            eventDictionary[eventName] = thisEvent;
        }
        else
        {
            thisEvent = listener;
            eventDictionary.Add(eventName, thisEvent);
        }
    }

    public static void Unsubscribe(string eventName, Action listener)
    {
        if (eventDictionary.TryGetValue(eventName, out Action thisEvent))
        {
            thisEvent -= listener;
            if (thisEvent == null)
            {
                eventDictionary.Remove(eventName);
            }
            else
            {
                eventDictionary[eventName] = thisEvent;
            }
        }
    }

    public static void Publish(string eventName)
    {
        if (eventDictionary.TryGetValue(eventName, out Action thisEvent))
        {
            thisEvent?.Invoke();
        }
    }
}

using UnityEngine;

public class Listener : MonoBehaviour
{
    private void OnEnable()
    {
        EventBus.Subscribe("TestEvent", OnTestEvent);
    }

    private void OnDisable()
    {
        EventBus.Unsubscribe("TestEvent", OnTestEvent);
    }

    private void OnTestEvent()
    {
        Debug.Log("TestEvent received!");
    }
}

using UnityEngine;

public class Publisher : MonoBehaviour
{
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            EventBus.Publish("TestEvent");
        }
    }
}

주의점

  • 구독했지만 사실 궁금하지 않게 되어버리는 상황이 있을 수 있기 때문에 메시지의 낭비가 있을수 있으니 설계를 잘 해야한다.

비트플래그 패턴

<출처 챌린지반 강의노트>

비트플래그패턴이란

  • 여러 가지 상태나 옵션을 하나이ㅡ 변수로 관리할 수 있도록 해주는 프로그래밍기법
  • 주로 비트 연산자를 사용하여 각각의 상태를 비트로 표현하고 조합하여 정수형 변수로 사용한다.
  • 유니티에선 보통 layer관련이 비트연산자로 작동한다.

비트연산자

    1. And 연산자(&)
      두 비트가 모두 1일때만 1일반환, 특정 비트를 선택할 때 사용
    1. Or 연산자(|)
      두 비트 중 하나라도 1이면 1을 반환 비트를 설정하거나 조합할 때 사용
    1. Not 연산자(~)
      비트를 반전 시킬 때 사용
    1. 비트 시프트 연산자(>> , <<)
      비트를 왼쪽 혹은 오른쪽으로 이동 << 은 왼쪽으로 이동 >> 오른쪽으로 이동 비트 마스크 패턴에서는 왼쪽 시프트만 활용

비트플래그 패턴의 장점

  • 메모리 효율 : 하나의 변수에 여러 상태를 저장할 수 있어 메모리 사용이 줄어든다.
  • 비교 및 조작의 간편함 : 비트 연산을 통해 빠르게 상태를 확인하거나 변경할 수 있다.
  • 가독성 : 적절하게 사용하면 코드가 더 명확하고 이해하기 쉬워진다.

유니티에서의 활용

  1. layerMask
using UnityEngine;

public class LayerMaskExample : MonoBehaviour
{
    public LayerMask layerMask; // 검사할 레이어 마스크

    void Start()
    {
        // 이름으로 레이어를 가져와서 레이어 마스크에 추가
        int layerNumber = LayerMask.NameToLayer("MyLayer");
        layerMask = 1 << layerNumber;

        // 기존 레이어 마스크에 새로운 레이어를 추가
        layerMask |= (1 << LayerMask.NameToLayer("AnotherLayer"));
    }

    void Update()
    {
        // 카메라가 바라보는 방향으로 레이캐스트를 수행
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;

        // 지정한 레이어 마스크를 사용하여 레이캐스트를 수행
        if (Physics.Raycast(ray, out hit, Mathf.Infinity, layerMask))
        {
            // 레이캐스트가 특정 레이어의 객체에 충돌한 경우
            Debug.Log("레이캐스트가 " + hit.collider.name + " 에 충돌했습니다.");
        }

        // 특정 레이어 번호를 검사
        if (hit.collider != null)
        {
            if (hit.collider.gameObject.layer == LayerMask.NameToLayer("MyLayer"))
            {
                Debug.Log("충돌한 객체는 MyLayer에 속합니다.");
            }
            else if (hit.collider.gameObject.layer == LayerMask.NameToLayer("AnotherLayer"))
            {
                Debug.Log("충돌한 객체는 AnotherLayer에 속합니다.");
            }
        }
    }
}
  1. Enum flag
public enum ItemType{
	Armor = 1,
	Potion = 2,
	Accessory = 3,
	Belt = 4,
	...
}

[Flags]
public enum CharacterState
{
    None = 0,
    Idle = 1 << 0,
    Running = 1 << 1,
    Jumping = 1 << 2,
    Attacking = 1 << 3,
    Defending = 1 << 4
 
}
[Flags]
public enum EquipStatus{
		Nothing = 0,
		LeftHand = 1 << 0,
		RightHand = 1 << 1,
		Both = LeftHand | RightHand
}

public class Character : MonoBehaviour
{
    public CharacterState currentState;

    void Start()
    {
        // 상태 설정
        currentState = CharacterState.Idle | CharacterState.Defending;

        // 상태가 Idle인지 확인
        if ((currentState & CharacterState.Idle) == CharacterState.Idle)
        {
            Debug.Log("캐릭터가 Idle 상태입니다.");
        }

        // 상태가 Defending인지 확인
        if ((currentState & CharacterState.Defending) == CharacterState.Defending)
        {
            Debug.Log("캐릭터가 Defending 상태입니다.");
        }
    }

    void Update()
    {
        // 상태 변경 예시
        if (Input.GetKeyDown(KeyCode.Space))
        {
            currentState |= CharacterState.Jumping;
            Debug.Log("캐릭터가 Jumping 상태로 변경되었습니다.");
        }

        if (Input.GetKeyDown(KeyCode.A))
        {
            currentState &= ~CharacterState.Defending;
            Debug.Log("캐릭터가 Defending 상태를 해제했습니다.");
        }
    }
}

오늘의 회고

  • 팀프로젝트가 나름? 잘 진행되고 있는것 같긴하다. 다만 내가 담당한 건축부분을 좀 많이 고칠 예정이라 찾아보고 열심히 해야할듯 ㅠ 생각보다 어려운 시스템인것 같다.
  • 비트연산자는 뭔가 익숙치않다. 유니티 하면서 많이 쓰게되는 Layer라서 잘 공부해 놔야겠다.
  • 내일은 쉬는날이니까 열심히 놀아야지 놀고 금요일~ 주말을 더 열심히 달려봐야겠다.
profile
게임개발을 꿈꾸는 개발자

0개의 댓글