전체 상태 업데이트보다 멀티 플레이어 게임 상태를보다 효율적으로 동기화하려면 어떻게합니까?


10

나는 전에 약간의 게임 네트워크 코딩을 해왔지만 주로 실시간 요구가없는 게임을 위해 TCP를 사용했습니다. 네트워크 멀티 플레이어로 2D Java 게임을하고 있습니다. 학습을 위해 기존 네트워크 API없이 직접 수행하고 싶습니다.

서버에서 클라이언트에게 보낸 게임 상태를 효율적으로 나타내는 방법은 무엇입니까? 각 플레이어의 위치, 애니메이션 상태 등으로 일종의 게임 상태 컨텍스트 객체를 생성 하고 업데이트 할 때마다 각 플레이어에게 전송하는 가장 분명하지만 가장 효율적인 방법이 있습니다 . 그것은 구현하기가 몹시 어렵지는 않지만 실시간 상호 작용에 가까운 것을 달성하기에는 너무 클 것입니다 (물론 이것에 대한 내 경험은 제한되어 있으므로 틀릴 수 있습니다).

상태 변화 만 전송하기 위해 이전에 사용해 왔던 확실한 방법이 있습니까? 그리고 추가 작업에 가치가있는 성능의 차이도 충분히 있습니까?


2
모든 프레임의 모든 상태를 시도하고 너무 느린 경우 (약간 간단한 2D 게임의 경우 충분히 효율적 임) 최적화를 시도하십시오. 제대로 작동하면 제대로 작동하므로 나중에 병목 현상이 발생하지 않는 한 변경하지 않아도됩니다.
Robert Rouhani

답변:


10

전체 게임 상태를 정기적으로 전송하는 것은 일반적으로 불가능하지만 게임의 복잡성에 크게 의존합니다. 작은 세계 모델의 간단한 게임의 경우 효과가있을 수 있습니다.

나는 개인적으로 다음 모델에서 훨씬 더 많은 성공을 거두었습니다.

  • 공간 데이터 구조 (예 : octree)로 잘 정의 된 객체 모델에 저장된 게임 상태
  • 클라이언트 또는 서버에서 게임 상태에 대한 모든 변경 사항은 이벤트로 설명됩니다. 이벤트는 게임 오브젝트의 속성 변경, 맵 타일 변경, 게임 오브젝트 이동 등일 수 있습니다.
  • 서버의 게임 엔진은 게임이 진행됨에 따라 일련의 이벤트를 생성합니다. 이것들은 서버의 게임 상태에 직접 적용됩니다.
  • 이벤트는 해당 플레이어와 관련이있는 경우에만 플레이어에게 전송됩니다 (예 : 현재 위치에서 이벤트가 표시됩니까?).
  • 플레이어 가시성 변경으로 인해 플레이어가 움직일 때 맵의 새로운 부분을 "공개"하는 이벤트가 발생할 수도 있습니다. 또한 플레이어가 게임에 처음 참여할 때 관련 게임 상태를 정확하게 처음 볼 수 있도록하는 데 사용될 수도 있습니다.
  • 플레이어의 게임 상태는 이벤트가 수신되면 업데이트됩니다. 따라서 게임 상태의 부분 모델 만 가지고 있지만 모든 이벤트가 올바르게 처리되었다고 가정하면 서버와 동기화 상태를 유지해야합니다.

이것은 상당히 큰 게임 세계에서 나에게 좋은 성능을 제공했습니다.

또 다른 팁은 클라이언트가 서버를 참조하지 않고 애니메이션, 파티클 효과 등을 처리하도록합니다. 이것들을 전달할 필요는 없습니다. 적절한 게임 이벤트로 "트리거"하면됩니다.


6

동기화는 일반적으로 증분과 절대의 두 부분으로 나뉩니다.

때로는 모든 것을 전송해야하지만 크기가 크지 만 올바른 방법으로 포장하면 몇 초마다 한 번씩 할 수 있습니다. 증분 새로 고침의 결함을 수정하여 Everithing을 제자리에 두는 것이 좋습니다.

실시간 경험을 얻으려면 일부 변경 사항을 빠르게 전송해야하지만 변경할 수있는 속성 만 전송해야합니다. 예를 들어 로켓이 직선으로 비행하는 경우 위치를 업데이트 할 필요가 없으며 각 클라이언트는 시작점에서 계산할 수 있습니다. 그러나 충돌이 발생하면 이에 대한 메시지를 생성 할 수 있으므로 각 클라이언트가 올바른 위치에서 로켓을 폭발시킬 수 있습니다. 작은 결함은 무시할 수 있습니다.

물론 클라이언트에 영향을 줄 수있는 것만 업데이트합니다! 화면에서 멀리 떨어진 것은 가치가 없습니다. 일부 값은 덜 자주 업데이트 될 수 있습니다. 예를 들어 위치는 다소 정확해야하며, 이벤트 (데스, 샷 발사, 폭발 등)는 즉시 보내야하지만 직접적으로 중요하지 않은 값은 스코어 보드, 채팅과 같이 새로 고침주기가 더 낮을 수 있습니다.

데이터 패킹도 중요합니다. 하나의 UDP 패키지에서 약 1400 바이트 (구성에 따라 다릅니다. 기본값)를 전송할 수 있습니다. 일반적으로 몇 바이트의 헤더가 있습니다. 따라서 하나의 패키지에서 50-100 단위 위치를 쉽게 업데이트 할 수 있습니다.


조언 Matzi 주셔서 감사합니다. 여전히 서버와 클라이언트를 구현하고 있지만 며칠 후에 다시 확인하고 귀하의 답변을 수락 할 것입니다.
Haz

당신에게 행운을 빕니다! ;)
Matzi

1

게임에 따라 키보드 / 조이스틱 입력 및 타이머 이벤트와 같은 비 결정적 입력을 공유함으로써 각 클라이언트가 동일한 게임을하는 "동기화 된 실행"모델을 고려할 수 있습니다. (각 클라이언트가 로컬 시뮬레이션을 실행하고 원격 시뮬레이션의 결과를 통합 할 것으로 예상하는 모델과 비교). 게임 엔진은 일반적으로 이것이 작동하기 위해 완전히 결정적이어야하며, 이는 게임에 따라 큰 부담이 될 수 있습니다. 그러나 게임이 이미 결정 론적이라면 더 쉬운 방법 일 수 있습니다.

#AltDevBlogADay 게시물 은 최신 RTS (특히 고객이 "다른"게임을 시작하는시기를 감지하는 방법)에서이 접근 방식의 일부 측면을 다룹니다.

그러나 그렇지 않으면 입증 될 때까지 단순하게 유지하십시오. :)


1
이것들은이 접근법을 사용하는 Factorio 개발자가 읽은 좋은 글 이며이 접근법의 복잡성을 암시하면서도 실행 가능하다는 것을 보여줍니다 : factorio.com/blog/post/fff-76 factorio.com/blog/post/fff -147 factorio.com/blog/post/fff-188
AaronLS
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.