<aside> 📌

한 줄 요약 — 온라인 게임에서 "이 플레이어에게 지금 무엇을 보여줄까"를 정하는 게 AOI(Area of Interest, 관심영역)다. 대표적으로 섹터 그리드(공간을 격자로 나눠 관심영역을 공간에 둠)와 per-player viewlist(각 플레이어가 보이는 객체 집합을 직접 들고 다님)가 있다. 흔히 둘 중 하나를 고르는 문제로 오해하지만, 실무에선 섹터로 후보를 좁히고 viewlist로 정밀 판정하는 조합이 정석이다.

</aside>

AOI는 왜 필요한가

멀티플레이어 서버는 한 플레이어가 움직이면 "그걸 봐야 할 사람들"에게 위치를 뿌린다. 순진하게 접속자 전원에게 뿌리면 수신자 수가 동접에 비례하고, 이동 이벤트마다 O(N) 송신이 발생한다. 동접 수천이면 이것만으로 서버가 무너진다.

그래서 "지금 이 플레이어에게 의미 있는 대상"만 추려 보낸다. 이 관심영역을 어떻게 잡느냐가 AOI이고, 구현은 크게 두 갈래다.

방법 A · 섹터 그리드 — 관심영역을 공간에 둔다

맵을 균일한 격자로 나누고, 각 셀(섹터)이 그 안의 객체 목록을 가진다. 플레이어는 자기가 속한 섹터 좌표(정수 2개)만 들면 된다.

대가는 사각형 시야다. 시야가 셀 격자를 따르므로 정확한 원이 아니다. 대부분의 게임에선 무해하지만, 시야 모양이 규칙에 직접 영향을 주면 걸린다(아래에서 다룸).

방법 B · per-player viewlist — 관심영역을 플레이어에 둔다

각 플레이어가 **"지금 내게 보이는 객체 id 집합"**을 직접 상태로 든다.

<aside> ⚠️

흔한 오해 — 여기서 "엔티티(객체)"는 개별 대상이지 컨테이너가 아니다. 다른 플레이어·몬스터·NPC·투사체 하나하나가 집합의 원소다. "섹터마다 자료구조를 두는 것"과 헷갈리기 쉬운데, 그건 오히려 방법 A다. viewlist는 자료구조를 플레이어마다 둔다.

</aside>

class Player {
    // 지금 내 눈에 보이는 상대들의 id
    std::unordered_set<int64_t> viewSet;
    // 시야 인원이 수십 이하로 작으면 정렬된 vector가 캐시에 더 유리
};

갱신의 본질은 매 틱, 이전 시야와 새 시야의 차집합이다.

매 틱, 각 플레이어 P마다:
  후보    = 주변에서 후보 수집            // 이 단계에 공간 자료구조가 필요 (아래 참고)
  newView = 후보 중 dist(P, c) <= R 인 것
  enter   = newView - viewSet             // 새로 보임    -> CREATE 패킷
  leave   = viewSet - newView             // 안 보이게 됨 -> DELETE 패킷
  viewSet = newView