34. Unity 게임개발 숙련 1주차(2)

이규성·2023년 12월 11일
0

TIL

목록 보기
39/106

12/11 강의를 계속해서 듣자아

📌스탠다드 반 세션

LayerMask, 비트 연산, 싱글톤에 대해 강의를 해주셨다. 영상 강의 내용 중에 나왔던 것들인데 명확한 이해를 하지 못하고 이렇게 코드를 작성하면 이렇게 동작하는 구나~ 하고 넘어갔었어서 아주 반가웠다.

LayerMask

유니티에서는 총 32개(0~31)의 레이어를 활용할 수 있으며, 이를 한번에 처리하기 위해 정수형 변수의 각 비트(32비트)를 할당하여 처리합니다. 1개의 변수를 여러 개의 bool값처럼 처리하는 방법!

이렇게 하는 경우 32개의 레이어를 비교연산 하기 때문에 2진법으로 표현하여 효율적으로 처리하는 것이 보통이다. 이진수로 변환하여 비트 연산을 활용하여 사용한다.

LayerMask 메서드들

LayerMask.GetMask(params string[] layerNames);
LayerName들을 넣어서 비트마스크를 만듭니다.

LayerMask mask = LayerMask.GetMask("Monster") | LayerMask.GetMask("Wall");
// int mask = (1 << 8) | (1 << 9); 와 동일
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100.0f, mask))
{
   Debug.Log(hit1.collider.gameObject.name);
}

LayerMask.value
비트마스크값을 도출합니다(실제 이진수를 십진수로 바꿔서 계산) 예) 1025 = 1024 + 1
LayerMask.NameToLayer(string layerName)
레이어의 이름을 통해 레이어의 인덱스(비트마스크값 아님)을 도출합니다. 예) 9
LayerMask.Contains(int layerIndex)
LayerMask가 특정한 레이어 인덱스를 포함하고 있는지 확인합니다

비트 연산

비트 옮기기 (Shift)
비트를 왼쪽으로 옮긴다는 의미에서 비트 시프트(shift)연산은 << 처럼 나타내고, 오른쪽으로 옮기는 시프트연산은 >>처럼 나타냅니다. // 1 << 2

// 8번 레이어 활성화
// 8번 : 보스 6번 : 일반
int layerMask = 1 << 8;
layerMask |= 1 << 6; 

// 사용 예시: 8번 레이어의 오브젝트만 감지하는 Raycast
if (Physics.Raycast(ray, out hit, 100, layerMask)) 
{
    // 8번 레이어의 오브젝트와 충돌했을 때의 처리
}

비트를 1로 만들기 (OR) |

// 8번과 10번 레이어 결합
int layerMask = (1 << 8) | (1 << 10);
101000000000
// 사용 예시: 8번 또는 10번 레이어의 오브젝트만 감지하는 Raycast
if (Physics.Raycast(ray, out hit, 100, layerMask)) 
{
    // 8번 또는 10번 레이어의 오브젝트와 충돌했을 때의 처리
}

비트가 1인지 확인하기 (AND) &

bool isLayer8Included = (layerMask & (1 << 8)) != 0;

// 사용 예시: layerMask에 8번 레이어가 포함되어 있는지 확인
if (isLayer8Included) {
    // 8번 레이어가 포함된 경우의 처리
}

// 예시
// 1000000000 & 1001010101 
// => 1000000000 != 0 => true
// 100000000 & 010101010 => 000000000 != 0 => false

비트 뒤집기 (NOT) ~

// 8번 레이어 제외
int layerMask = ~(1 << 8);

// 사용 예시: 8번 레이어를 제외한 모든 레이어의 오브젝트를 감지하는 Raycast
if (Physics.Raycast(ray, out hit, 100, layerMask)) 
{
    // 8번 레이어를 제외한 오브젝트와 충돌했을 때의 처리
}

비트 마스트 상태이상 시스템

[System.Flags] // 중첩 비트 마스크를 부여한다.
public enum StatusEffects
{
    None = 0,
    Poisoned = 1 << 0,  // 0001
    Burned = 1 << 1,    // 0010
    Frozen = 1 << 2,    // 0100
    Paralyzed = 1 << 3  // 1000
}

public class StatusEffectManager
{
    private StatusEffects currentEffects = StatusEffects.None;

    public void AddEffect(StatusEffects effect)
    {
        currentEffects |= effect;
    }

    public void RemoveEffect(StatusEffects effect)
    {
        currentEffects &= ~effect;
    }

    public void ClearEffects()
    {
        currentEffects = StatusEffects.None;
    }

    public bool HasEffect(StatusEffects effect)
    {
				// 0100 & 0100 => 0100 != 0000 -> true
        return (currentEffects & effect) != StatusEffects.None;
    }

    public void PrintEffects()
    {
        Console.WriteLine("Current Status Effects: " + currentEffects);
    }
}

class Program
{
    static void Main()
    {
        StatusEffectManager manager = new StatusEffectManager();

        // 상태 이상 추가
        manager.AddEffect(StatusEffects.Poisoned);
        manager.AddEffect(StatusEffects.Frozen);

        // 현재 상태 이상 출력
        manager.PrintEffects(); // Poisoned, Frozen

        // 상태 이상 제거
        manager.RemoveEffect(StatusEffects.Poisoned);

        // 상태 이상 확인
        if (manager.HasEffect(StatusEffects.Frozen))
        {
            Console.WriteLine("The character is frozen.");
        }

        // 모든 상태 이상 제거
        manager.ClearEffects();
    }
}

📌싱글톤

싱글톤 패턴은 한 개의 인스턴스만 생성하고, 어디서든 그 인스턴스에 접근할 수 있는 디자인 패턴입니다.

대부분 사람들이 싱글톤을 쓰는 이유 : 객체 간 접근이 편하니까 / 중앙집중식 관리가 머리 안아픔

  1. 전역적인 상태나 리소스에 접근: 싱글톤은 어디서든 접근할 수 있는 전역적인 상태나 리소스에 대한 중앙 집중적인 접근을 제공합니다. 예를 들어, 게임의 설정, 오디오 관리자, 이벤트 매니저 등을 싱글톤으로 구현할 수 있습니다. 한 가지의 상태로, 하나가 주가 되어서 관리했으면 좋겠다!
  2. 중복 인스턴스 방지: 싱글톤 패턴을 사용하면 오직 한 개의 인스턴스만 생성되므로, 중복 인스턴스를 방지할 수 있습니다. 이는 리소스 낭비나 예기치 않은 동작을 방지하는 데 도움이 됩니다.
  3. 객체 간 편한 통신: 싱글톤 인스턴스는 어디서든 접근할 수 있으므로, 객체 간의 통신이 편리해집니다. 다른 객체에서 싱글톤 인스턴스를 사용해 데이터를 공유하거나 메서드를 호출할 수 있습니다. // 슈퍼싱글톤 → 단일책임원칙 망가짐 → 유지보수성 떨어지고, 결합도 높아짐
  4. 유지보수 및 확장성: 싱글톤 패턴은 코드의 유지보수성과 확장성을 향상시킵니다. 인스턴스에 대한 접근이 중앙 집중화되므로, 코드의 변경이나 기능의 추가/변경이 용이해집니다. 또한, 싱글톤 인스턴스를 사용하는 객체들 사이의 결합도를 낮출 수 있어 유지보수성을 향상시킵니다.

싱글톤 예제

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

    void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
        else
        {
            Destroy(gameObject); // 중복 인스턴스가 생성될 경우 제거
        }
    }
}
public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }

    void Awake() // 게임오브젝트가 처음으로 켜진 그 순간
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject); // 씬 전환 시 파괴되지 않도록 설정
        }
        else
        {
            Destroy(gameObject); // 중복 인스턴스가 생성될 경우 제거
        }
    }

		public void Init(){
				// 초기 세팅
		}
}
using UnityEngine;

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T _instance;

    public static T Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = FindObjectOfType<T>();
                if (_instance == null)
                {
                    GameObject obj = new GameObject();
                    // obj.name = typeof(T).Name;
                    _instance = obj.AddComponent<T>();
                }
            }
            return _instance;
        }
    }
}

public class AudioManager : Singleton<AudioManager>
{
    public void PlaySound(string soundName)
    {
        // 사운드 재생 로직
    }
}

🤸🏻‍♀️Feedback

우선 영상 강의를 보며 간지러웠던 부분들을 긁어주셔서 좋았다. 갑자기 새로운 개념들로 구현하기 시작해서 혼란스러운 와중에 반가웠다. 모두 이해한 것은 아니지만 그래도 코드를 계속 작성해오다 보니 어느 정도의 감은 잡힌다. 역시 이해도가 부족할 땐 계속해서 반복적으로 사용해 보는 것이 최선인 듯 하다.

0개의 댓글