실시간 전략 게임을위한 네트워킹


16

컴퓨터 과학 과정을위한 실시간 전략 게임을 개발 중입니다. 가장 어려운 측면 중 하나는 클라이언트-서버 네트워킹 및 동기화 인 것 같습니다. 이 주제에 대해 읽었 지만 ( 1500 궁수 포함 ) 다른 모델 (LAN 등)과 달리 클라이언트-서버 방식을 사용하기로 결정했습니다.

이 실시간 전략 게임에는 몇 가지 문제가 있습니다. 고맙게도 플레이어가 취하는 모든 행동은 결정적입니다. 그러나 예약 된 간격으로 발생하는 이벤트가 있습니다. 예를 들어 게임은 타일로 구성되어 있으며 플레이어가 타일을 사용할 때 해당 타일의 값인 '에너지 수준'은 촬영 후 1 초마다 증가해야합니다. 이것은 내 유스 케이스를 정당화 해야하는 매우 빠른 설명입니다.

지금은 서버에 패킷을 보내고 응답을 기다리는 씬 클라이언트를 수행하고 있습니다. 그러나 몇 가지 문제가 있습니다.

플레이어 간의 게임이 최종 게임으로 발전 할 때, (예약 된 이벤트, 앞서 설명한, 말뚝 박기 때문에) 초당 50 개가 넘는 이벤트가 종종 발생하며 동기화 오류가 표시되기 시작합니다. 저의 가장 큰 문제는 고객들 사이의 작은 상태 편차조차도 고객이 결정하는 다른 결정을 의미 할 수 있다는 것입니다. 또 다른 문제 (현재 중요하지 않은)는 대기 시간이 있으며 결과를보기 위해 몇 초, 심지어 몇 초를 기다려야한다는 것입니다.

최종 사용자에게 더 쉽고 빠르며 즐거운 방법으로 사용할 수있는 전략과 알고리즘이 무엇인지 궁금합니다. 이것은 게임당 몇 명의 플레이어와 함께 초당 많은 양의 이벤트를 고려할 때 특히 흥미 롭습니다.

TL; DR이 초당 50 개 이상의 이벤트로 RTS를 작성하는 경우 클라이언트를 어떻게 동기화합니까?


Eve-online의 기능과 "느린"시간을 구현하여 모든 것이 올바르게 처리되도록 할 수 있습니다.
Ryan Erb

3
다음은 Planetary Annihilation의 클라이언트 / 서버 모델에 대한 필수 링크입니다. forrestthewoods.ghost.io/… 이것은 매우 효과적인 Lockstep 모델 의 대안입니다.
DallonF

각 타일에 대한 업데이트 대신 모든 타일에 대해 단일 업데이트를 보내거나 Ilmari의 답변에 따라 플레이어가 아닌 작업을 분산시켜 이벤트 수를 줄이십시오.
Lilienthal

답변:


12

초당 50 개의 이벤트를 실시간 사운드로 동기화하는 것이 현실적이지 않은 것처럼 내게 목표입니다. 이것이 1500 년 궁수 기사 에서 언급 된 잠금 단계 접근 방식이 잘 설명 된 이유입니다 !

한 문장으로 : 너무 느린 네트워크를 통해 너무 짧은 시간에 너무 많은 항목을 동기화하는 유일한 방법은 너무 느린 네트워크를 통해 너무 짧은 시간에 너무 많은 항목을 동기화하지 않고 대신 모든 클라이언트에서 상태를 결정적으로 진행하고 동기화하는 것입니다. 필수품 (사용자 입력).


6

플레이어가 취하는 모든 행동은 결정 론적이지만 예정된 간격으로 발생하는 이벤트가 있습니다.

문제가 있다고 생각합니다. 게임에는 타임 라인이 하나만 있어야합니다 (게임 플레이에 영향을주는 것들). 당신은 어떤 것들이 초당 X의 속도로 성장한다고 말합니다 ; 1 초에 몇 개의 게임 단계가 있는지 확인하고이를 Y 게임 단계 당 X의 비율로 변환 하십시오 . 그런 다음 게임 속도가 느려질지라도 모든 것이 결정적입니다.

게임을 실시간으로 독립적으로 실행하면 다른 장점이 있습니다.

  • 최대한 빨리 실행하여 벤치마킹 할 수 있습니다
  • 언급 한 바와 같이 게임 진행 속도를 늦춤으로써 디버그 이벤트를 볼 수 있습니다.
  • 게임은 결정 론적이며 멀티 플레이어에게는 매우 중요합니다.

또한 50 개가 넘는 이벤트가 있거나 최대 몇 초 지연 될 때 문제가 발생한다고 언급했습니다. 이것은 1500 궁수에 설명 된 시나리오보다 규모가 훨씬 작 으므로 게임을 프로파일 링하고 둔화 위치를 찾을 수 있는지 확인하십시오.


1
+1 : 프레임 기반이 시간 기반이 아닌 올바른 선택입니다. 물론 초당 N 개의 프레임을 유지하려고 시도 할 수 있습니다. 약간의 장애는 완전 동기화 해제보다 낫습니다.
PatrickB

@PatrickB : 많은 게임 들이 비디오 프레임에 묶이지 않은 "시뮬레이션 된"시간을 사용한다는 것을 알았습니다 . 월드 오브 워크래프트는 매 100ms마다 마나 같은 것을 업데이트하며, 드워프 요새는 기본적으로 비디오 프레임 당 10 틱으로 설정됩니다.
Mooing Duck

@Mooing Duck : 제 의견은 RTS에만 해당됩니다. 작은 오류를 나중에 허용하고 수정할 수있는 경우 (예 : MMORPG, FPS) 연속 값을 사용하는 것이 좋을뿐만 아니라 중요합니다. 그러나 여러 기계에서 동기화되어야하는 결정 론적 시뮬레이션? 프레임을 고수하십시오.
PatrickB

4

먼저 예정된 이벤트 관련 문제를 해결하기 위해 이벤트가 발생할 때 이벤트를 브로드 캐스트하지 말고 처음 예약 할 때 브로드 캐스트하십시오 . 즉, "매초마다 타일의 에너지 증가 ( x , y )"메시지 를 보내는 대신 "타일 의 에너지가 증가 할 때까지 ( x , y ) 증가"메시지가 표시 될 때까지 또는 중단되었습니다. " 그런 다음 각 클라이언트는 업데이트를 로컬로 예약해야합니다.

실제로, 당신은이 원칙을 더 나아가서 플레이어 액션 만 전송할 수 있습니다. 다른 모든 것은 각 클라이언트 (및 필요에 따라 서버)에 의해 로컬로 계산 될 수 있습니다.

(물론 우발적 인 비 동기화를 감지하기 위해 때때로 게임 상태의 체크섬을 전송해야하며, 그러한 경우 클라이언트의 재 동기화를위한 메커니즘이 있어야합니다. 그러나 이것은 테스트 나 희소 한 오작동에서만 발생할 수있는 드문 이벤트입니다.)


둘째, 클라이언트를 동기화 상태로 유지하려면 게임이 결정적이어야합니다. 다른 답변은 이미 이에 대한 좋은 조언을 제공했지만 수행 할 작업에 대한 간략한 요약을 포함시켜 드리겠습니다.

  • 각 턴 또는 "틱"이 1/50 초와 같이 게임을 내부적으로 턴제로 설정하십시오. (사실, 1/10 초 이상으로 도망 갈 수 있습니다.) 한 턴 동안 발생하는 모든 플레이어 행동은 동시에 처리해야합니다. 적어도 서버에서 클라이언트로 전송되는 모든 메시지에는 차례 번호가 지정되어 각 클라이언트가 각 이벤트가 어떤 차례에 발생하는지 알 수 있습니다.

    게임에서 클라이언트-서버 아키텍처를 사용하고 있기 때문에 서버가 각 턴 동안 발생하는 일의 최종 중재자 역할을하도록하여 일부 작업을 단순화 할 수 있습니다. 그러나 고객이 고객을 다시 확인해야 함을 의미합니다. 서버에서 작업을 다시 "장치 X를 ​​한 타일 왼쪽으로 이동합니다"라는 메시지를 보내고 서버의 응답이 장치 X 이동에 대해 아무 것도 말하지 않으면 클라이언트 발생하지 않았다고 가정하고 이미 재생을 시작했을 수있는 예측 움직임 애니메이션을 취소 할 수 있습니다.

  • 동일한 차례에 발생하는 "동시"이벤트에 대해 일관된 순서를 정의하여 각 클라이언트가 동일한 순서로 이벤트를 실행하도록하십시오. 이 순서는 결정적이고 모든 클라이언트 (및 서버)에 대해 동일하다면 무엇이든 될 수 있습니다.

    예를 들어 한 타일의 자원 증가가 다른 타일의 자원 증가를 방해 할 수없는 경우 한 번에 모두 수행 할 수있는 모든 자원을 먼저 증가시킨 다음 각 플레이어의 유닛을 미리 결정된 순서로 이동 한 다음 NPC 유닛을 이동할 수 있습니다. 선수들에게 공평하게하기 위해, 턴마다 유닛 이동 순서를 변경하여 각 플레이어가 똑같이 자주 가도록 할 수 있습니다. 결정적으로 수행되는 한 (예 : 회전 수에 따라) 괜찮습니다.

  • 부동 소수점 수학을 사용하는 경우 엄격한 IEEE 모드에서 사용 중인지 확인하십시오. 이로 인해 상황이 약간 느려질 수 있지만 고객 간의 일관성을 유지하기에는 적은 비용입니다. 또한 통신 중에 우발적 인 반올림이 발생하지 않도록하십시오 (예 : 클라이언트가 반올림 된 값을 서버로 전송하지만 여전히 반올림 된 값을 내부적으로 사용함). 위에서 언급했듯이, 비 동기화를 감지하고 복구하는 프로토콜을 갖는 것도 좋은 경우입니다.


1
또한 RNG를 동기화하여 시작하고 서버가 지시 할 때만 동기화 된 RNG에서 당겨 빼십시오. Starcraft1은 오랫동안 재생 중에 RNG 시드가 저장되지 않은 버그가 있었으므로 재생은 실제 게임에서 천천히 벗어날 수 있습니다.
Mooing Duck

1
@MooingDuck : 좋은 지적입니다. 사실, 매 차례마다 현재 RNG 시드를 전송하여 RNG 비동기 화가 즉시 감지되도록 제안합니다. 또한 UI 코드에 임의성이 필요한 경우 게임 로직에 사용 된 것과 동일한 RNG 인스턴스에서 가져 오지 마십시오 .
Ilmari Karonen

3

게임 로직을 실시간과 완전히 독립적으로 만들고 본질적으로이를 턴제로 만들어야합니다. 그렇게하면 "타일 에너지 변화가 어떻게 발생하는지"정확히 알 수 있습니다. 귀하의 경우, 각 차례는 1/50 초입니다.

그렇게하면 플레이어 입력에 대해서만 걱정할 필요가 있습니다. 그 밖의 모든 것은 게임 논리에 의해 관리되며 모든 클라이언트에서 완전히 동일합니다. 순 지연 또는 추가 복잡 계산으로 인해 게임이 잠시 중단 되더라도 이벤트는 여전히 모든 사람에게 동기화됩니다.


1

우선 계산에 IEEE-754를 엄격하게 사용하도록 지정하지 않는 한 PC float / double math는 결정적이지 않다는 것을 이해해야합니다.

그런 다음 클라이언트가 서버에 연결하고 시간을 핑 (Ping 대기 시간을 처리하십시오!) (장시간 게임 플레이의 경우 타임 스탬프 / 턴을 다시 동기화해야 할 수도 있음)

이제 클라이언트가 작업을 수행 할 때마다 타임 스탬프 / 턴이 포함되며 잘못된 타임 스탬프 / 턴을 거부하기 위해 서버가 결정합니다. 그런 다음 서버는 클라이언트에게 작업을 되돌려주고, 차례가 "폐쇄"될 때마다 (일명 서버는 너무 오래된 회전 / 타임 스탬프를 허용하지 않음) 서버 전송 및 종료 작업을 클라이언트에 보냅니다.

클라이언트는 2 개의 "월드"를 갖습니다. 하나는 종료와 동기화되고, 다른 하나는 종료부터 시작하여 현재 클라이언트 전환 / 타임 스탬프까지 대기열에 도착한 작업을 추가합니다.

서버가 약간 오래된 동작을 받아들이 기 때문에 클라이언트는 대기열에 직접 동작을 직접 추가 할 수 있으므로 네트워크를 통한 왕복 시간은 최소한 자신의 동작에 대해 숨겨집니다.

마지막으로 더 많은 작업을 대기시켜 MTU 패킷을 채울 수있어 프로토콜 오버 헤드가 줄어 듭니다. 좋은 생각은 서버에서 그렇게하는 것이므로 모든 종료 이벤트에는 대기열에 대한 작업이 포함됩니다.

이 알고리즘을 실시간 슈팅 게임에서 사용하고 클라이언트가 자체 작업을 수행하지 않고 작동하지만 서버 핑은 20 / 50ms로 잘 작동하며 모든 X 엔드 턴 서버는 특별한 "모든 드리프트 된 값을 정정하기 위해 클라이언트 맵 "패킷.


부동 소수점 수학 문제는 일반적으로 피할 수 있습니다. RTS에서는 일반적으로 정수 / 고정 포인트로 시뮬레이션 및 이동을 쉽게 수행 할 수 있으며 게임 동작에 영향을 미치지 않는 디스플레이 레이어에 대해서만 부동 소수점을 사용할 수 있습니다.
Peteris

정수를 사용하면 팔각형 보드가 아닌 한 수평 타일을 만들기가 어렵습니다. 고정 점에 대한 hw 가속이 없으므로 float ieee754보다 느릴 수 있습니다.
Lesto
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.