🔥 10/8 화요일 목표 🔥
🔎 16강 까지 듣기📝
🔎 이전 학습 복습하기
09:00 어제 학습 복습 ❗️ (6강, 8강 이해하기)
14:00 9강부터 강의시작 💛
📝 Study 📝
⭐️ 열거형(Enum) : 쓰는 이유? int 기반이지만 상수형 값에 의미를 부여하기 위해 사용함.
⭐️ 스크립터블 오브젝트(Sciptable Object) : 유연한 데이터 컨테이너
게임에 재사용가능한 데이터 또는 설정을 저장하는 사용
코드와 데이터를 분리해 코드를 더 깔끔하게 관리하기 쉽게만듬
하나의 스크립터블 오브젝트를 여러 게임 오브젝트에서 참조하거나 재사용 할 수 있음
Unity에디터와 통합되어 인스펙터 창에서 직접 수정하고 관리 할 수 있음.
⭐️ protected virtual void Awake() 상속을 받을때는 protected 이상을 써야만 메서드를 상속 받을수 있다.
protected override void Awake()
👀 실제구현코드
public partial class TopDownController : MonoBehaviour
{
protected CharacterStatsHandler stats { get; private set; }
protected virtual void Awake()
{
stats = GetComponent<CharacterStatsHandler>();
}
}
public class PlayerInputController : TopDownController
{
protected override void Awake()
{
base.Awake(); //TopDowmController를 상속받았기에 base = 부모가 됨
}
}
⭐️ 비트 연산자, 레이어 마스크
레이어를 사용하는 이유화살이 캐릭터가 쏜건 몬스터만, 몬스터가 쏜건 캐릭터만 맞을 수 있게 하기 위해
레이어가 32개인 이유 : int는 32bit (4Byte)
비트연산자 사용 예시1<<6 // 1을 왼쪽으로 6번 보내라 = 1000000 라는 결과값이 나옴.
레이어는 비트마스크를 생성하는데 사용됨
비트마스크란?
이진수(비트)를 사용하여 여러 상태를 하나의 변수에 저장하고 조작하는 방법이다
주로 효율적으로 여러 상태를 관리하거나 특정 상태를 빠르게 확인, 설정, 변경하는 데 사용된다
비트마스크의 기본 개념
비트 단위로 상태 표현: 각 비트가 하나의 상태(혹은 플래그)를 나타냅니다.
예를 들어 8비트 변수에서 각 비트는 0 또는 1이 될 수 있으므로, 8개의 상태를 동시에 표현할 수 있습니다.
논리 연산 사용: 비트마스크는 AND, OR, XOR, NOT과 같은 비트 연산을 통해 상태를 설정하거나 확인합니다.
👀 레이어와 비트의 상관관계
Unity와 같은 게임 엔진에서 레이어(Layer)와 비트(Bit)는 비트마스크를 통해 밀접하게 연결됩니다.
레이어와 비트의 관계를 이해하면 특정 레이어에 대한 처리, 충돌 감지, 렌더링 등을 효율적으로 관리할 수 있습니다.
레이어는 비트마스크의 비트 위치로 표현:
Unity에서 각 레이어는 고유한 비트 위치를 가집니다.
예를 들어, Layer 0은 비트마스크의 첫 번째 비트에 대응하고, Layer 1은 두 번째 비트에 대응하는 식입니다.
이렇게 각 레이어가 특정 비트에 대응하기 때문에, 여러 레이어에 대한 처리를 한 번에 수행할 수 있습니다.
비트마스크로 다수의 레이어 선택:
여러 레이어에 대해 충돌이나 렌더링 같은 작업을 설정하려면 비트마스크를 사용해 특정 레이어들을 포함하는 마스크를 설정할 수 있습니다.
예를 들어, Layer 0과 Layer 2만 선택하고 싶다면 0b00000101처럼 특정 비트만 1로 설정하여 마스크를 만듭니다.
이 비트마스크는 다양한 작업에 적용되며, 비트 연산을 통해 설정된 레이어만 처리하게 합니다.
충돌 감지에서 비트마스크 사용:
Unity에서는 LayerMask라는 기능으로 충돌할 레이어를 지정하는데, 내부적으로는 비트마스크로 표현됩니다.
예를 들어 Physics.Raycast에서 특정 레이어에만 반응하게 하려면, LayerMask를 사용하여 필요한 레이어만 비트로 활성화할 수 있습니다.
👀 특정 레이어에 대한 충돌 감지 예시
int layerMask = (1 << 3) | (1 << 5); // Layer 3과 Layer 5만 활성화
if (Physics.Raycast(ray, out hit, maxDistance, layerMask)) {
// Layer 3이나 Layer 5에 속한 오브젝트와 충돌 시 처리
}
⭐️쿼터니언과 벡터의 곱셈
쿼터니언은 회전과 관련됨
쿼터니언을 활용해 벡터도 회전이 가능함
ex/ 캐릭터의 오른쪽에 있다고 할때, 캐릭터가 회전하면 그에 맞게 벡터도 회전해야함
Quaternion과 Vector3의 곱셈을 지원 하기때문에 Q*V 순서만 맞춰서 곱하면 된다
⭐️ as키워드에 대한 이해
C#에서 as는 다운캐스팅(downcasting)을 수행하는 방법 중 하나
👀 실제구현코드
RangedAttackSo rangedAttackSo = attackSo as RangedAttackSo;
attackSo는 RangedAttackSo 클래스의 부모 클래스 타입(예를 들어, AttackSo 클래스)으로 선언된 객체로 추정
as 키워드를 사용하여 attackSo 객체를 RangedAttackSo 타입으로 캐스팅하고, 결과를 rangedAttackSo 변수에 저장한다
as 키워드는 안전한 형 변환을 위해 사용된다
형 변환이 실패할 경우 InvalidCastException 예외를 발생시키는 대신, null을 반환하는 것이 특징
attackSo가 실제로 RangedAttackSo 타입이라면, rangedAttackSo 변수는 이 객체를 가리키게 된다
attackSo가 RangedAttackSo 타입이 아닐 경우, 형 변환에 실패하여 rangedAttackSo는 null이 된다
⭐️ 오브젝트 풀링
게임 성능 개선을 위해 사용
- 객체를 미리 생성해두고 필요할 때 가져다 사용, 사용 완료 시 풀에 반납하는 방식
- 생성(Instrantiate)과 소멸(Destroy)이라는 비용이 큰 작업을 최소화함
- 빈번하게 생성되고, 파괴하는 객체에 주로 사용하고, 풀에 저장하고 재사용함으로써
메모리 할당과 가비지 컬렉션에 따른 성능 저하를 방지
- 적절히 사용하면 큰 성능 개선을 가져올수 있지만,
불필요한 메모리 사용을 증가 시킬 수 있으므로 사용시에는 신중해야함.
👀실제 강의 사용코드
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;
private void Awake()
{
// 인스펙터창의 Pools를 바탕으로 오브젝트풀을 만들 것.
// 오브젝트풀은 오브젝트마다 따로이며, pool개수를 넘어가면 강제로 끄고 새로운 오브젝트에게 할당.
PoolDictionary = new Dictionary<string, Queue<GameObject>>(); //초기화
foreach (var pool in Pools)
{
// 큐는 FIFO(First-in First-out) 구조, 가장 오래 줄 선(enqueue) 가장 먼저 빠져 나올(dequeue)
Queue<GameObject> objectPool = new Queue<GameObject>();
for (int i = 0; i < pool.size; i++)
{
// Awake하는 순간 오브젝트풀에 들어갈 Instantitate 일어나기 때문에 터무니없는 사이즈 조심
GameObject obj = Instantiate(pool.prefab);
obj.SetActive(false);
objectPool.Enqueue(obj); // 줄의 가장 마지막에 세움
}
PoolDictionary.Add(pool.tag, objectPool); // 접근이 편한 Dictionary에 등록
}
}
public GameObject SpawnFromPool(string tag)
{
if (!PoolDictionary.ContainsKey(tag)) // 애초에 Pool이 존재하지 않는 경우
return null;
// 제일 오래된 객체를 재활용
GameObject obj = PoolDictionary[tag].Dequeue();
PoolDictionary[tag].Enqueue(obj);
obj.SetActive(true);
return obj;
}
}
⭐️ StringToHash : 문자열을 고유한 정수 값인 해시 값으로 변환하여 연산 비용을 크게 줄일 수 있음.
애니메이션 파라미터를 지정할때 문자열 대신 해시 값을 사용하면 CPU시간을 절약하고 애니메이션 성능을 향상시킬수 있음
💡 주의점 동일한 문자열은 항상 동일한 해시 값을 반환하지만,
반대로 동일한 해시 값이 항상 동일한 문자열을 반환하지 않음
이 점으로 인해 해시 충돌이 발생할 수 있음.
👀 사용예제 (그냥 int의 변수명만 사용가능)
private static readonly int IsWalking = Animator.StringToHash("IsWalking");
private static readonly int IsHit = Animator.StringToHash("IsHit");
private static readonly int Attack = Animator.StringToHash("Attack");
private void Hit()
{
animator.SetBool(IsHit, true);
}
⭐️ 싱글턴
하나만 존재하게 보장하는 디자인 패턴.
전역접근을 제공하는 패턴.
🔥 10/9일 수요일 목표 🔥
🔎 이전 학습 복습하기📝
🔎 개인 과제 시작하기
⭐️ 2D 심화 과정 진행 해보기 (9강)
화살의 발사방향을 Arm의 회전에 맞게 조정하기
화살이 앞으로 나갈 수 있게 만들어 보기
화살이 벽에 닿은 경우 사라지게 만들어보기
'Unity 내배캠 TIL' 카테고리의 다른 글
Unity 게임 개발 입문(4주차4일) (0) | 2024.10.15 |
---|---|
Unity 게임 개발 입문 (4주차3일) (2) | 2024.10.10 |
Unity게임 개발 입문 (4주차 1일) (0) | 2024.10.07 |
C# 기초 문법 - 팀 프로젝트(3주차 5일) (0) | 2024.10.06 |
C# 기초 문법 - 팀 프로젝트(3주차 4일) (0) | 2024.10.06 |