2024. 5. 9. 16:18ㆍUnity/Unity 학습정리
LayerMask란 레이어 기반 작업을 단순화 하는 것이다. 32비트 정수로 표시되는 Bit Mask를 이용해 특정 레이어 대상 작업을 할 수 있다. 각 레이어는 0에서 31까지의 인덱스가 할당된다. 주로 비트플래그로, 비트로 각각의 아이템을 상징하거나, 레이어를 구분하는데 사용된다.
LayerMask
0000 0000 0000 0000 0000 0000 0000 0000 (32bit)로 표현된다.
- Monster Layer : 0000 0000 0000 0000 0000 0000 1000 0000 8번 레이어
- Level Layer : 0000 0000 0000 0000 0000 0000 0100 0000 7번 레이어
와 같이 표현이 가능하다. 실제로 유니티 에디터에서 Layer를 세팅할 수 있다. 32bit이기 때문에 Layer도 0~31 총 32개 까지 사용할 수 있는 모습이다.
선언
[SerializeField] private LayerMask levelCollisionLayer;
LayerMask 클래스로 선언을해주면 유니티 에디터에서 Layer를 선택 할 수 있게 된다. 여러개를 골라서 원하는 동작을 할 수 있다. 현재는 화살이 벽(Level Layer)에 부딫히거나 적(Enemy Layer)에 부딫히는것을 체크하여 화살을 파괴시키거나 적에게 대미지를 입히는 등의 동작을 한다.
사용법
//ProjectileController.cs
private void OnTriggerEnter2D(Collider2D collision)
{
// levelCollisionLayer에 포함되는 레이어인지 확인합니다.
if (IsLayerMatched(levelCollisionLayer.value, collision.gameObject.layer))
{
Debug.Log("levelCollisionLayer.value :" + levelCollisionLayer.value);
// 벽에서는 충돌한 지점으로부터 약간 앞 쪽에서 발사체를 파괴합니다.
Vector2 destroyPosition = collision.ClosestPoint(transform.position) - direction * .2f;
DestroyProjectile(destroyPosition, fxOnDestory);
}
// _attackData.target에 포함되는 레이어인지 확인합니다.
else if (IsLayerMatched(attackData.target.value, collision.gameObject.layer))
{
HealthSystem healthSystem = collision.GetComponent<HealthSystem>();
if(healthSystem != null)
{
bool isAttackApplied = healthSystem.ChangeHealth(-attackData.power);
if(isAttackApplied && attackData.isOnKnockBack)
{
ApplyKnockback(collision);
}
}
DestroyProjectile(collision.ClosestPoint(transform.position), fxOnDestory);
}
}
이 코드는 화살이 어딘가에 충돌했을때 해당 충돌 오브젝트의 레이어에 따라서 작동하는 방식을 두 개로 나누었다.
- 하나는 벽(Level Layer)에 부딫혀서 그냥 화살을 부딫힌 지점에서 조금 떨어져 파괴시키는것
- 나머지는 몬스터의 Layer에 부딫혔다면 몬스터의 체력을 깎고 넉백을 시킨다음 화살을 파괴하는 로직이다.
private bool IsLayerMatched(int layerMask, int objectLayer)
{
return layerMask == (layerMask | (1 << objectLayer));
}
IsLayerMatched 메서드로 화살이 부딫힌곳이 내가 원하는곳인지 확인하여 bool을 리턴하는 메서드이다. LayerMask로 선언된 layerMask필드가 int형으로 매개변수로 넘어온것을 확인할 수 있는데 LayerMask는 내부적으로 연산자 오버로딩과 int로의 변환이 구현되어 있기 때문에 LayerMask로 선언하고 int로 넘겨도 상관없다.
layerMask는 확인하고 싶은 Layer이기 떄문에 값이 고정되어있고, objectLayer가 충돌된 곳인데 1을 objectLayer만큼 왼쪽으로 쉬프트해주어 확인하고싶은 layerMask와 or연산을 수행한다. or연산은 두 비트의 값이 일치한다면 변화가 없기때문에 원래의 값과 같다면 원하는 곳에 충돌했다는 뜻이기 때문에 True를 반환한다.
- layerMask : 0000 0000 0000 0000 0000 0000 0100 0000 7번 레이어
- object Layer : 0000 0000 0000 0000 0000 0000 0100 0000 7번 레이어
- layerMask | object Layer == 0000 0000 0000 0000 0000 0000 0100 0000 변함이 없다.
마무리
해당코드는 Level만 선택해서 화살이 벽에 부딫히면 제거되는 방식으로만 구현되었다. 하지만 LayerMask는 여러 Layer를 선택할 수 있다. 따라서 장애물, Player 등 여러 레이어를 설정하여 화살이 닿였을때 데미지가 입지 않는 동작을 설정해 줄 수 있고, 원하는 동작을 개발자가 할 수 있다. 이는 프로그램의 확장을 편하게 만들어준다.
이번 유니티 강의를 듣고 프로그램을 만들때 확장성에 대해서 고민을 많이 하게되었다. 기능이 추가되거나 삭제될 때 다른 로직을 건드려야하는 부분이 적겠구나 라는 것을 느꼈고, 유지보수하는것도 매우 도움이 될 것 같다는 생각을 했다. 내가 구현 해야 하는것을 어떤방식으로 설계해야 확장성 있는 코드가 될지 고민하면서 코딩을 해야겠다고 느꼈다.
'Unity > Unity 학습정리' 카테고리의 다른 글
Unity - Vector2.Dot으로 시야각 구하기 (0) | 2024.05.17 |
---|---|
Unity - 각도 구하기 (0) | 2024.05.16 |
Unity - Coroutine2 (0) | 2024.04.22 |
Unity - Coroutine (1) | 2024.04.19 |
Unity Animation (1) | 2024.04.18 |