흔한 덕후의 잡동사니

싱글 스레드 MMO 게임에서의 섹터 간 이동 방식 본문

서버

싱글 스레드 MMO 게임에서의 섹터 간 이동 방식

chinodaiski 2025. 4. 15. 23:48

MMO 게임은 수많은 오브젝트가 존재하며 플레이어는 맵을 돌아다니며 다른 플레이어들과 상호작용할 수 있다. 모든 플레이어가 서로의 움직임을 관찰하려 하면, 서버는 처리할 패킷 수가 N²로 급증한다. 이를 방지하기 위해 서버는 맵을 그리드로 나누어 관리하고, 각 구역을 섹터라 부른다.

플레이어가 섹터 간 이동을 하면 이전 섹터 주변의 플레이어들에게는 플레이어가 사라졌음을 알리고, 새로운 섹터 주변의 플레이어들에겐 새로운 플레이어가 왔음을 알린다.

이 방식으로 플레이어 간 상호작용 범위를 제한하여 서버 부하와 패킷 전송량을 크게 줄일 수 있다.

그렇담면 이를 어떻게 구현할까?

 1. 고정 그리드 섹터 방식
맵을 일정 크기의 정사각형 섹터로 분할하고, 오브젝트는 위치에 따라 특정 섹터에 속함.
예: 섹터 크기가 100x100이면 (250, 340) 위치의 플레이어는 (2, 3) 섹터에 포함.

 2. 섹터 이동 처리 방법
플레이어가 이동할 때마다 섹터 위치를 계산하고, 섹터가 바뀌면 주변 섹터에 이벤트 전송.
주변 섹터는 현재 섹터를 중심으로 하는 3x3 영역.
- 기존 3x3 섹터에서 벗어난 오브젝트들에게는 "떠남" 메시지 전송.
- 새로 포함된 3x3 섹터의 오브젝트들에게는 "등장함" 메시지 전송.

 

3. 예제

void UpdatePlayerPosition(Player& player, float newX, float newY) {
    int oldSectorX = player.posX / SECTOR_SIZE;
    int oldSectorY = player.posY / SECTOR_SIZE;

    int newSectorX = newX / SECTOR_SIZE;
    int newSectorY = newY / SECTOR_SIZE;

    player.posX = newX;
    player.posY = newY;

    if (oldSectorX != newSectorX || oldSectorY != newSectorY) {
        NotifySectorChange(player, oldSectorX, oldSectorY, newSectorX, newSectorY);
    }
}

 

+ 추가로 섹터를 구성할때 100x100짜리 크기를 가진 섹터 10x10을 만들어야한다면, 12x12를 만들어서 가장 겉에 있는 섹터에는 이동하지 못하게 만들면 코드를 구성하기 좋다. 이렇게 하지 않으면 가장자리에 있는 섹터로 이동할때 예외가 많아기지 때문에 오히려 연산이 더 많이 들어간다.

 

4. 마무리
이렇게 싱글 스레드 MMO 서버에서 섹터 기반 이동 처리를 사용하면 네트워크 부하와 연산 비용을 크게 줄일 수 있다. 하지만 멀티스레드 환경에선 data race를 피하기 위해 또 다른 방식을 사용해야한다.