MMO 게임에서 많은 수의 픽업을 처리하는 방법


26

Minecraft와 같은 게임 또는 실제로 픽업이있는 MMO 게임은 어떻게 처리합니까?

지형을 파낼 때마다 지형에 "흙"이 3 방울 떨어집니다. 모든 항목에 매 프레임마다 계산 된 회전 애니메이션이 있다고 가정하십시오. 세계의 픽업 수가 매우 많으면 주어진 서버의 클라이언트에 대한 프레임 계산에서 쓸모없는 엄청난 오버 헤드가 될 것입니다. 왜냐하면 많은 픽업 항목이 몇 년이 걸리기 때문입니다.

그래서 내가 생각한 것은 로컬 플레이어에 근접한 픽업만으로 "물건"을해야한다는 것입니다. 그러나 여전히 이것은 다른 픽업 아이템이 애니메이션을 시작하기에 충분히 가까울 때 확인해야하는 모든 프레임을 암시합니다.

내 실제 질문은 다른 MMO 가이 문제를 어떻게 해결 했습니까?


9
또한 Minecraft의 맥락에서 특정 개수의 항목이 서로 충분히 가까이있는 경우 (동일한 블록 공간에서 동일한 항목의 3+) 서버는 3 개의 인스턴스를 블록 유형이 포함 된 그룹화 된 인스턴스 ( minecraft:dirt) 및 개수 (30)를 사용하여 플레이어가 픽업 할 수있을만큼 가까이있을 때 플레이어의 인벤토리에 최대한 많은 수를 추가합니다. 만약 플레이어가 6 개의 아이템을위한 공간을 가지고 있고 30의 스택이지면에 있다면, 플레이어는 6을 가져오고지면의 스택은 24로 줄어 듭니다.
Zymus

6
@Zymus 적당한 수의 드롭 된 아이템이 항상 근처에있는 아이템을 찾기 때문에 실제로 틱 성능을 떨어 뜨렸다는 점에 주목할 가치가 있습니다.
user253751

답변:


48

단순히 세계의 해당 부분 만 플레이어와 가까운 메모리에로드하면됩니다. 다른 모든 것은 하드 드라이브에 일시 중지됩니다. 약 2km 떨어진 곳에 작은 물체가 있으면 플레이어는 물체를 볼 수없고 상호 작용할 수 없습니다. 따라서 렌더링을 위해 업데이트하거나 GPU로 보낼 이유가 없습니다. 객체와 그 상호 작용 범위가 작을수록 플레이어 주변에서로드해야하는 범위가 낮아집니다.

플레이어와 가장 가까운 것을 찾는 것과 관련하여 : 공간 조회에 최적화 된 데이터 구조로 세계를 저장하는 것으로 주로 요약됩니다. 이것들에 대한 좋은 후보는 공간 해싱다차원 트리 입니다.


빠른 답변 주셔서 감사합니다. 트리거 콜 리더를 확인하기 위해 일종의 공간 파티셔닝을 사용한다고 생각하면서 Unity를 사용하려고 생각했기 때문에 내 캐릭터 주위에 하나의 큰 원 충돌체를 만들고 그 안의 모든 항목은 "애니메이션"됩니다. 이것이 귀하의 답변을 구현하는 방법입니까? 내가 틀렸다면 나를 바로 잡아, 건배!
Alakanu

2
@Alakanu 장거리에서 객체를 볼 수 있지만 플레이어와 가까이있을 때 특정 계산 강렬한 동작 만 수행하려는 경우에 사용할 수 있습니다 (y 축 주위에서 무언가를 회전시키는 것은 비용이 많이 들지 않아야 함). 그러나 Unity에서 오픈 월드 게임을 구현할 때 실제로 해결해야 할 과제는 플레이어가 월드를 이동하는 동안 지능적으로 게임 오브젝트를 인스턴스화하고 파괴하는 것입니다 (또는 인스턴스 풀링과 파괴 대신 오브젝트 풀링 사용).
Philipp

예,이 상황에서는 객체 풀링이 필수입니다.) 감사합니다.
Alakanu

3
@Alakanu이 답변이 해당 게임에 어떻게 적용되는지에 대한 자세한 내용은 Minecraft의 "Loaded Chunks"개념을 확인할 수 있습니다.
T. Sar-복원 모니카

1
이것은 픽업에만 해당되는 것은 아닙니다. 플레이어와 너무 멀리 떨어진 물체는 그렇게 취급 할 수 있습니다. 때로는 플레이어와 가까운 물체도 있습니다. 전체 인테리어가있는 집을 상상하지만 실제로 집에 들어갈 때까지 렌더링 할 필요는 없습니다.
Zibelas

22

관리해야 할 두 가지 사항이 있습니다.

  1. 서버 전 세계를 정식으로 관리 해야합니다 . 이를 위해서는 N 개의 클라이언트 (N이 "대규모")와의 통신이 필요합니다.

  2. 클라이언트 원칙적으로 전 세계에 대해 알 있지만 반드시 그럴 필요는 없습니다 . 클라이언트의 경우 플레이어 근처에 무엇이 있는지 아는 것으로 충분합니다. 예를 들어 다소 거친 그리드와 같은 파티셔닝을 가정하면 플레이어의 셀과 플레이어 주변의 26 셀 (또는 2D 그리드가있는 경우 8 셀) 만 알아야합니다. 다소 미세한 격자가 더 좋지만 아이디어를 얻습니다.

지금, 많은 픽업, "많은"은 무엇입니까? 초당 5 개를 파야 할 수도 있습니다. 서버에서 업데이트해야하는 24 개의 숫자 일 수도 있고, 서버 관심 영역이 셀과 겹치는 다른 플레이어에게 전송해야 할 수도 있습니다. 컴퓨터의 경우 이것은 상당히 말도 안되는 양의 데이터이며 무시할 수없는 양의 계산입니다. 같은 셀에 수백 / 수천 명의 플레이어가있을 경우 문제가 될 수 있습니다 (귀하의 패리티가 너무 거칠다).

서버는 픽업의 회전 또는 그와 같은 세부 사항을 알거나 신경 쓸 필요가 없습니다. 왜 그런가요?

클라이언트는 실제로 신경 쓰지 않습니다. 클라이언트가 즉시 구성 할 수있는 눈 사탕 일뿐입니다.

서버의 관점에서 필요한 것은 당신이있는 노드에서 (30, 40, 50)을 파고 있다는 것을 알고 있으며, 예를 들어 5 유형의 3 개의 객체 또는 7 유형의 1 개의 객체를 생성하기로 결정합니다 그게 다 중요합니다. 그것이 당신에게하는 전부입니다. 또한 그리드 셀을 통해 관심 영역을 이동시키는 누군가에게 보낸 데이터의 정보도 나중에 포함됩니다 (그때까지 계속 있다고 가정).

클라이언트는 거기에 세 개의 오브젝트가 생성되었다고 들었습니다. 이제 클라이언트가 'D'가있는 ASCII 아트 맵을 표시하는지, 회전하는 먼지 더미를 표시하는지 여부는 모두 동일합니다. 파일의 회전이 다른지 또는 플레이어와 가까운 파일의 회전 만 같은지 여부 모니터에 표시되는 내용 일 뿐이며 다른 사람에게는 영향을 미치지 않습니다.

따라서 콘크리트의 경우 근처에있는 먼지 더미 만 회전 시키려면 알고있는 모든 개체에 대해 범위 검사를 수행하면됩니다. 데이터 세트가 크지 않기 때문에 모든 것에 대한 무차별적인 힘조차도 효과 가 있습니다.

파티션 크기에 따라 너무 멀리있는 그리드 셀을 사소하게 제거 할 수 있습니다.

물론 셀의 하위 파티션에 대해 더 똑똑한 것을 사용할 수 있습니다. 당신이 원한다면 kd-Tree를 사용하십시오. 그러나 큰 이익을 기대하지는 마십시오. Manhattan distace로 물건을 정리하거나 물건을 작은 격자로 정렬 할 수는 있지만 왜 그럴까요?

거리 확인 (실제로 제곱 거리이지만 사용자와 동일)은 단지 두 번의 곱셈과 덧셈 (MUL, MADD, 실제로 두 개의 연산에 최적화 됨)에 이어 분기 또는 조건부 이동입니다. 한 번에 전체 그리드 셀을 제거하지 않는 다른 작업만큼 빠릅니다. 사실 이것은 GPU에서 할 있는 일입니다 ...

동일한 위치에 대해 수백 또는 최대 수천 개의 거리 검사를 수행하는 방법 (제곱 거리가 잘 작동 함)을 보았을 때 실제로 계산하는 데 많은 어려움을 겪지 않습니다. 연속 메모리에 대한 친절한 반복 및 조건부 이동으로 먼지가 저렴합니다. (의사 코드)와 같은 것 rot = r[i] + 1; r[i] = ((dx*dx+dy*dy) < DIST_SQ) ? rot : r[i];. 이는 프레임 당 수백 개의 값 배열에 대한 반복입니다. 컴퓨터는 그 작업에 대해 신경 쓰지 않았으며, 인접한로드 및 저장, 간단한 ALU, 분기 없음 및 수천 번의 반복입니다.

이 (다 대일) 서버에서와 같은 종류의 문제 (다 대다)가 아닙니다. 실제로, 클라이언트는 문제가되지 않습니다.


죄송합니다. 프레임 속도에 대해 이야기하기 시작할 때 고객에 대해 이야기하고있는 것이 분명하다고 생각했습니다.
Alakanu

1
그러나 클라이언트는 결코 문제가되지 않습니다. 클라이언트는 매우 비 대중 적이고 로컬이기 때문에 서버보다 훨씬 덜 알아야 합니다. 이상적으로, 클라이언트는 플레이어가있는 공간 분할 노드 (그것이 무엇이든 그리드)와 바로 주변 노드를 알고 있습니다. 따라서 수천 명의 플레이어가 서로 옆에 있지 않으면 업데이트가 매우 완만합니다. 일반적으로 노드 너비의 절반 이상을 한 방향으로 이동 한 후 하나 또는 두 개의 오브젝트에 대한 델타와 새 그리드 노드의 컨텐츠 만 필요합니다. 그 밖의 모든 것 : 문제가 아닙니다.
데이먼

1
요점은 너무 똑똑하면 어리석은 생각이 될 수 있다는 것입니다. 귀하의 세계는 각 노드에 관리 가능한 수의 객체로 이미 공간적으로 나뉘어져 있습니다. 최신 CPU (및 GPU)는 대량의 SoA 데이터를 순차적으로 처리하는 데 탁월합니다. 그들은 조리 분기 좋아하지 않아, 그들은 더 적은 조리 메모리 액세스와 같은 - 그러나입니다 정확히 "단지 인근 처리"무엇 않습니다. 관리 가능한 숫자 (수백, 수천 개)의 경우 한 셀 내의 "모두 처리"가 완벽하게 적합하며 가능한 최선의 방법 일 것입니다.
데이먼

1
@Alakanu 이것은 귀하의 질문에 대한 상세하고 완전한 답변입니다. 답변이 아니라고 생각되면, 오해 한 것이거나 질문이 너무 불분명하여 Damon, 나와이 답변을지지 한 모든 사람들이 오해 한 것입니다.
David Richerby

2
@Alakanu 당신은 정말로 당신을 도와 주려는 사람들에게 불평하는데 많은 시간을 보냅니다. 행운을 빌어 요.
David Richerby

2

@ T.Sar는 자세한 정보를 위해 Minecrafts "로드 된 청크"개념을 살펴보아야한다는 의견을 작성합니다. 그렇다면 Minecraft에서는 게임에서 기계를 만드는 사람들로 인해 이것이 다소 복잡하다는 점에 유의하십시오.

매우 단순화 된 버전은 다음과 같습니다.

세계는 사각형 영역 (청크)으로 나뉩니다. Minecraft에는 높이 분할도 있지만 대부분의 MMOS에는 필요하지 않습니다.

게임 클라이언트는 플레이어와 가까운 지역에만 관심이 있습니다. 이것은 플레이어 주위에 원을 그리는 것보다 훨씬 간단하지만 완벽하게 충분합니다.

Minecraft에서 영역은 16x16 블록이며 클라이언트는 약 9x9 영역을 알고 있으며 각 방향으로 4 영역이 있습니다. (동쪽 4 개 지역 + 지역 플레이어는 서쪽 4 개 지역 = 총 9 개 지역에 있습니다. 동일한 남 / 북)

이 숫자에 마법은 없습니다. 게임에서 의미가있는 것을 사용하십시오.

클라이언트는이 영역 내의 내용 만 애니메이션으로 만듭니다. 서버는 일부 플레이어 와 가까운 지역에서 방황하는 몬스터와 같은 것을 계산합니다 .

플레이어가 지역 내부를 돌아 다닐 때 특별한 일이 발생하지 않습니다. 지역 경계를 넘어 서면 "애니메이션 가장자리"가 한 지역 위로 밀려납니다. 그런 다음 클라이언트는 서버에 현재 보이는 지역에 대해 문의해야합니다.

여러 개의 중첩 애니메이션 제한이 있어도 아무 문제가 없습니다. 예를 들어 3x3 영역에서 아이템을 떨어 뜨리고 5x5 영역에서 괴물을 방황하고 9x9 영역에서 풍경을 보여줍니다.

서버는 플레이어가 볼 수없는 지역의 "동결 된 버전"을 유지합니다. 이 작업에 많은 메모리가 필요한 경우 시간이 지나면 언로드 할 수 있습니다. 다음에 플레이어가 도착하면 아이템이 떨어지지 않고 지역이 다시로드됩니다. 다음에 더 빨라야합니다, 선수 1


드로우 거리는 조정 가능하지만이 경우 8 청크는 9x9이며 클라이언트 측 결정이므로 서버에 속도를 내도록 지시 할 수 있습니다 (따라서 서버는 클라이언트가 렌더링하지 않는 데이터를 보내지 않습니다). 또한 ... Doom과 Quake는 말이되는 것만 렌더링하는 문제를 해결하지 않았습니까?
SparK

떨어 뜨린 아이템의 데스 폰 제거에 관하여 ... 마인 크래프트에서 플레이어가 근처에있을 때만 아이템이 "나이"가됩니다. 따라서 드롭 된 항목을 언로드 된 청크에 "저장"하고 나중에 가져올 수 있습니다.
SparK
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.