카테고리 없음

20240414 TIL 비트연산을 통한 bitmask 오토 타일링

note4973 2025. 4. 14. 21:34
public class AutoWallTileSet : ScriptableObject
{
    public int id;
    public string name_kr;
    /// <summary>
    /// bitmask 순서는 상 우 하 좌
    /// 상 +1 우 +2 하 +4 좌 +8
    /// </summary>
    [Header("Front Wall Sprites")]
    public List<Sprite> frontBaseSprites = new(16);
    public List<Sprite> frontUpperSprites = new(16);

    [Header("Back Wall Sprites")]
    public List<Sprite> backBaseSprites = new(16);
    public List<Sprite> backUpperSprites = new(16);

    public Sprite GetBaseSprite(int bitmask, bool isFront)
    {
        var list = isFront ? frontBaseSprites : backBaseSprites;
        return (bitmask >= 0 && bitmask < list.Count) ? list[bitmask] : null;
    }

    public Sprite GetUpperSprite(int bitmask, bool isFront)
    {
        var list = isFront ? frontUpperSprites : backUpperSprites;
        return (bitmask >= 0 && bitmask < list.Count) ? list[bitmask] : null;
    }
}
    public static int CalculateWallBitmask(Tile tile, Level level)
    {
        int bitmask = 0;

        // 순서: 상 우 하 좌 


        for (int i = 0; i < 4; i++)
        {
            Tile neighbor = level.GetAdjacentTile(tile, (FourDir)i);
            if (IsWallLike(neighbor))
                bitmask |= 1 << i;
        }

        return bitmask;
    }

 

bitmask를 활용하여 주변 타일을 검사하여 auto tiling 시스템을 구현했다.

 

↑ (위):    1 << 0 = 1
→ (오른):  1 << 1 = 2
↓ (아래):  1 << 2 = 4
← (왼쪽):  1 << 3 = 8

예시:
위와 아래에 벽이 있다면 → bitmask = 1 (↑) + 4 (↓) = 5
오른쪽에만 있다면 → bitmask = 2

방향별 비트 위치:
 ↑: 1 << 0 → 0001
 →: 1 << 1 → 0010
 ↓: 1 << 2 → 0100
 ←: 1 << 3 → 1000

 

for (int i = 0; i < 4; i++)
    {
        Tile neighbor = level.GetAdjacentTile(tile, (FourDir)i);
        if (IsWallLike(neighbor))
            bitmask |= (1 << i);

    }

 

비트 연산자를 활용하면 다양한 기능을 쉽게 구현이 가능하다

 

비트 연산자 종류 정리표

연산자이름설명

 

& AND 둘 다 1일 때만 1
` ` OR
^ XOR 서로 다르면 1
~ NOT 비트 반전 (1 → 0, 0 → 1)
<< 왼쪽 시프트 비트를 왼쪽으로 밀기 (×2)
>> 오른쪽 시프트 비트를 오른쪽으로 밀기 (÷2)

 

1. & (AND) 공통된 비트 검사

int a = 0b_1100; // 12
int b = 0b_1010; // 10
int result = a & b; // 0b_1000 = 8

2. | (OR) — 비트 켜기 (추가)

int flags = 0b_0001;
flags |= 0b_0100; // flags = 0b_0101

3. ^ (XOR) — 비트 토글

int x = 0b_0101;
x ^= 0b_0010; // x = 0b_0111
x ^= 0b_0010; // 다시 x = 0b_0101

 

4. ~ (NOT) — 비트 반전

int x = 0b_0000_1111;
int y = ~x; // y = 0b_1111_0000 (32bit 기준으로 -16)

 

5. << (왼쪽 시프트)

int a = 1 << 2; // 2^2 = 4 → 0b_0100

 

6. >> (오른쪽 시프트)

int b = 8 >> 2; // 8 / 4 = 2 → 0b_0010

 

실전: 게임에서 비트 연산 활용 예

분야예시비트 연산
오토타일링 주변 타일 연결 상태 `bitmask
상태관리 중독/기절/무적 등 ON/OFF `flags
입력 처리 방향키 동시에 누르기 inputFlags & 방향
렌더링 마스크 레이어 설정 layerMask & cameraMask

자주쓰는 패턴

// 비트 켜기
flags |= (1 << 2);

// 비트 끄기
flags &= ~(1 << 2);

// 비트 토글
flags ^= (1 << 2);

// 비트 검사
bool isSet = (flags & (1 << 2)) != 0;

 

정리

a & b 공통된 비트만 유지
`a b`
a ^ b 서로 다른 비트만 유지
~a 모든 비트 반전
a << n a를 왼쪽으로 n칸 이동 (×2ⁿ)
a >> n a를 오른쪽으로 n칸 이동 (÷2ⁿ)