클라이언트와 서버 모두에서 물리 시뮬레이션을 실행 하시겠습니까?


13

게임에서 클라이언트 / 서버 네트워크 아키텍처에 대해 배우기 위해 멀티 플레이어 소행성 클론을 구현하고 있습니다. 클라이언트 / 서버 기술에 관한 GafferOnGames 및 Valve의 출판물을 읽는 데 시간을 보냈습니다. 두 가지 개념에 문제가 있습니다.

  1. 현재 box2d로 물리를 시뮬레이션하고 초당 약 20 회 세계 상태를 클라이언트에게 보내는 신뢰할 수있는 게임 서버가 있습니다. 각 클라이언트는 수신 한 마지막 몇 개의 스냅 샷을 추적하고 스프라이트의 움직임을 매끄럽게하기 위해 두 상태 사이에서 잠복합니다. 그러나 그렇게 매끄럽지는 않습니다. 그것은 잠시 동안 매끄럽게 될 수 있습니다. 그런 다음 약간 거꾸로 한 다음 다시 매끄럽게 할 수 있습니다. TCP와 UDP를 모두 시도했지만 모두 동일합니다. 내 문제가 무엇인지 알 수 있습니까? (참고 : 나는 이것을 싱글 플레이어 용으로 먼저 구현했으며, 물리 세계를 초당 20 회만 업데이트 할 때 스프라이트 움직임이 60fps에서 완벽하게 매끄 럽습니다).

  2. 첫 번째 문제를 해결하기 위해 클라이언트가 box2d 시뮬레이션을 실행하고 서버 스냅 샷이 일치하지 않을 때 스프라이트 위치를 업데이트해야한다고 생각했습니다. 싱글 플레이어 구현이 매끄 럽기 때문에 이것이 더 부드러울 수 있다고 생각했습니다. 이것이 좋은 생각입니까?

    위의 문제를 해결하지 않더라도 클라이언트 측 예측에 필요합니까? 예를 들어, 플레이어가 우주선을 움직이려고하면 물리 시뮬레이션없이 소행성, 벽 또는 적의 함선에 충돌했는지 어떻게 알 수 있습니까? 우주선이 서버에서 개체를 쳤다는 스냅 샷을 받기 전에 충돌해야하는 개체를 통과하는 것처럼 보입니다.

감사!

답변:


10

클라이언트와 서버 모두에서 시뮬레이션을 확실히 실행하십시오. 다른 것들은 대기 시간이 너무 길다. 고정 된 시간 간격을 사용하고 포인터 비교를 피하면서 동일한 순서로 객체를 삽입하여 시뮬레이션이 일치하는지 확인해야합니다. Box2D로 이것을 시도하지는 않았지만 물리 시뮬레이션에서 모든 머신에서 동일한 동작을 달성하는 것이 일반적으로 가능합니다. 모든 수학은 일반적으로 IEEE 754 binary32 float를 기반으로하며 그 동작은 예를 들어 +-*/몇 가지 등의 작업에 대해 엄격하게 정의됩니다 . 에 대해 조심해야합니다 sin.cos런타임마다 다를 수 있기 때문에 좋아합니다 (여러 플랫폼을 위해 개발할 때 특히 중요합니다). 또한 컴파일러에서 부동 최적화를 위해 엄격한 설정을 사용해야합니다. 서버에서 객체 상태를 주기적으로 보내 객체를 동기화 할 수 있습니다. 불필요한 말더듬을 피하기 위해 차이가 임계 값보다 크지 않으면 업데이트하지 마십시오.

염두에 두어야 할 한 가지 문제는 새로운 객체를 생성하고 이것이 클라이언트 간의 시뮬레이션을 어떻게 변화시킬 것인가입니다. 이를 해결하는 한 가지 방법은 서버가 모든 오브젝트를 작성하게하는 것입니다. 현재 시간 단계가 t이면 서버는에 추가 될 개체를 예약합니다 t+d. 따라서 추가 할 개체와 추가시기를 포함하는 새 개체 목록을 모든 클라이언트에서 유지 관리하고 서버에서 미리 업데이트 할 수 있습니다. d충분히 큰 경우 다른 결과의 위험을 최소화합니다. 실제로 차이를 처리 할 수없는 경우 해당 시간 단계를 시뮬레이션하기 전에 클라이언트가 특정 시간 단계 동안 새 객체에 대한 정보를 기다리도록 할 수 있습니다.


답변 주셔서 감사합니다. box2d가 다른 CPU에서 동일한 결과를 생성한다고 보장하지는 않습니다. 데스크탑 게임을 작성하고 있기 때문에 우리에게는 시나리오가 될 것입니다. 권위있는 서버의 주기적 업데이트로 차이가 미세하고 쉽게 수정되기를 바랍니다. 그러나 결코 시도하지 않았습니다.
Venesectrix

Erin Catto는 여러 Box2D 세계의 전체 상태를 동기화 상태로 유지하는 것이 패배한다고 생각합니다 ( box2d.org/forum/viewtopic.php?f=3&t=8462 )
Pavel

성명 "binary32 수레 [...] 동작은 엄격히 같은 동작에 대해 정의 된 IEEE 754는 +-*/" 완전히 거짓이다. IEEE-754의 모든 작업은 구현에 따라 달라질 수 있습니다. 자세한 내용은 여기여기 를 참조 하십시오 .
BlueRaja-대니 Pflughoeft

1
아닙니다. 완전히 사실입니다. 링크가 설명하는 문제는 x87 fpu의 다른 모드 및 초월 구현과 관련이 있습니다. IEEE 754 binary32 기본 작업을 위해 엄격하게 정의되어 있습니다. 올바른 모드를 설정하고 올바른 지침을 사용하여 표준을 준수하는 것은 사용자의 책임입니다. x87 fpu가 아닌 SSE 명령어를 사용하면 많은 도움이됩니다.
rasmus

4

그것들 사이의 보간은 항상 보간 할 다음 데이터 세트에 의존하기 때문에 그렇게 좋아 보이지 않을 것입니다. 즉, 지연 시간이 짧으면 모든 것이 따라 오기를 기다려야합니다.

있다 GameDev에 오래된 기사 당신이 마지막으로 데이터를 한 지점 과거 개체의 위치를 예측하는 차 스플라인을 사용하는 방법에 대한이. 그런 다음 해당 위치를 사용하고 새 위치를 설명 할 새 데이터를 가져올 때 스플라인을 조정합니다. 또한 두 번째 물리 시뮬레이션을 실행하는 것보다 훨씬 저렴할 것이므로 클라이언트를 명시 적으로 구현하여 클라이언트를 구현했기 때문에 신뢰하는 사람을 결정할 필요가 없음을 의미합니다. :)


이 경우가 될 수 있습니다. 내가하려는 것은 서버에서 3 개의 스냅 샷을받을 때까지 지연됩니다. 1 번에서 2 번으로 나옵니다. 2 번에서 3 번으로 나옵니다. 어떤 지점에서든 패킷이 빠지면 1에서 2가 아닌 1에서 3이 아니라 1에서 3까지 뛸 수 있습니다. 그래도 아직 올바르게 구현하지 않았을 수 있습니다. 기사 링크를 주셔서 감사합니다!
Venesectrix

1

비슷한 작업을 직접 수행했으며 클라이언트에서만 Box2D를 실행했습니다. 내가 한 방법은 클라이언트가 자체 시뮬레이션을 거의 자체적으로 실행하여 모든 동기화 패킷의 현재 속도 (및 회전)를 서버로 보내는 것입니다. 그런 다음 서버는이 정보를 다른 플레이어에게 전송합니다. 다른 플레이어는 새로받은 속도를 복제 된 엔티티로 설정합니다. 클라이언트간에 눈에 띄는 차이없이 매우 매끄 럽습니다.

물론 여기서 문제는 엔티티에 대한 중앙 집중식 제어가 없다는 것입니다. 그러나 서버 측에서 물리학을 시뮬레이션하여 서버 측에서도 수행 할 수 있다고 생각합니다.


입력 해 주셔서 감사합니다. 부정 행위를 방지하려면 중앙 집중식 제어가 필요하므로 클라이언트가 말한 것이 가능한지 여부를 알기 위해서는 최소한 서버에서 시뮬레이션을 실행해야합니다.
Venesectrix

1

개인적으로 서버에서만 시뮬레이션을 실행하고 관련된 객체의 선형 / 각속도 / 가속에 대한 변경 사항을 브로드 캐스트하도록합니다. 어떤 이유에서든 특정 개체가 물리적 속성 (위에서 언급 한 속도 및 가속과 같은)을 변경하면이 특정 변경 사항이 서버에서 클라이언트로 전송되고 클라이언트가 그에 따라 객체의 데이터.

현재 구현에 비해 이점은 클라이언트 측 보간의 필요성을 무효화하고 객체에 대해 매우 충실한 동작을 생성한다는 것입니다. 문제는이 방법이 지연 시간에 매우 취약하다는 점입니다. 이는 플레이어가 지리적으로 너무 멀리 떨어져있을 때 매우 큰 문제가됩니다.

질문 1에 관해서는, 스냅 샷의 각 수신 사이에 정확히 20 초 간격이있을 것이라는 절대적인 보장이 없기 때문에 문제는 지연 시간에 변동이있을 것이라고 말합니다. 밀리 초 단위로 측정 된 시간을 "t"로 설명하겠습니다.

1) 게임이 시작된 이후 t = 20에서 클라이언트는 스냅 샷을 수신하고 성공적으로 보간을 보냈습니다.

2) t = 40에서 서버와 클라이언트 사이에 대기 시간이 있었고 스냅 샷은 실제로 t = 41에 도달했습니다.

3) t = 60에서 서버는 다른 스냅 샷을 보냈지 만 대기 시간으로 인해 시뮬레이션의 1 초가 클라이언트 측에서 낭비되었습니다. 스냅 샷이 t = 60에 도달하면 클라이언트는 40 및 60 인스턴트의 보간을 수행하지 않지만 실제로는 41-60 인스턴트에서 보간하여 다른 동작을 생성합니다. 이러한 부정확성으로 인해 최종적으로 "자 키감"이 발생할 수 있습니다.

질문 2의 경우, 객체의 위치를 ​​알려주는 각 프레임에 패키지를 보내지 않고도 각 객체가 실제로 클라이언트-서버 동기화되었는지 여부를 효율적으로 추적하는 무언가를 구현하면 아이디어가 효과가 있습니다. 불연속 간격으로 수행하더라도 질문 1의 동일한 문제에서 실행될뿐만 아니라 너무 많은 양의 데이터를 전송할 수 없습니다 (나쁜 일).


첫 단락에서 말하는 내용을 잘 모르겠습니다. 시뮬레이션이 서버에서만 실행되고 속도 / 가속의 변경 사항 만 브로드 캐스트하는 경우 클라이언트는 스프라이트를 그려야하는 위치를 어떻게 알 수 있습니까? 클라이언트는 객체를 올바르게 그리려면 수신 된 속도 / 가속도를 기반으로 객체를 시뮬레이션해야합니다. 정확히 예상 한 것 이외의 간격으로 스냅 샷을받는 것이 옳은 것 같습니다. 그 문제를 어떻게 해결할 수 있습니까?
Venesectrix

클라이언트는 객체의 초기 및 현재 위치, 속도 및 가속도를 알고 그에 따라 객체가 서버와 독립적으로 생각 하는 위치를 업데이트합니다 . 서버는 물리 및 충돌 감지를 수행하는 서버이기 때문에 결국 메시지를 통해 클라이언트에서 이러한 속성을 변경합니다 (주어진 객체의 속도 / 가속도 및 방향을 조만간 변경해야 함)
UBSophung
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.