저격수의 움직임 예측


35

나는 약 20-30 명의 플레이어가 영구 서버에 한 번에 연결된 중간 규모의 멀티 플레이어로 아이소 메트릭 2D 게임을하고 있습니다. 올바른 움직임 예측 구현을 얻는 데 어려움이있었습니다.

물리 / 이동

게임에는 실제 물리 구현이 없지만 기본 원리를 사용하여 움직임을 구현합니다. 지속적으로 입력을 폴링하는 대신 상태 변경 (즉, 마우스 다운 / 업 / 이동 이벤트)은 플레이어가 제어하는 ​​캐릭터 엔티티의 상태를 변경하는 데 사용됩니다. 플레이어의 방향 (즉, 북동쪽)은 일정한 속도와 결합되어 실체의 속도 인 실제 3D 벡터로 바뀝니다.

메인 게임 루프에서 "Draw"전에 "Update"가 호출됩니다. 업데이트 논리는 0이 아닌 속도로 모든 엔티티를 추적하는 "물리적 업데이트 작업"을 트리거합니다. 기본 통합을 사용하여 엔티티 위치를 변경합니다. 예를 들면 다음과 같습니다. entity.Position + = entity.Velocity.Scale (ElapsedTime.Seconds) (여기서 "Seconds"는 부동 소수점 값이지만 동일한 접근 방식은 밀리 초 정수 값에도 적용됩니다).

요점은 보간법이 움직임에 사용되지 않는다는 것입니다. 기본 물리 엔진에는 "이전 상태"또는 "현재 상태"라는 개념이 없으며 위치와 속도 만 있습니다.

상태 변경 및 업데이트 패킷

플레이어가 변경을 제어하는 ​​캐릭터 엔티티의 속도가 변경되면, "아바타 이동"패킷이 엔티티의 동작 유형 (스탠드, 걷기, 달리기), 방향 (북동쪽) 및 현재 위치를 포함하는 서버로 전송됩니다. 이는 3D 1 인칭 게임 작동 방식과 다릅니다. 3D 게임에서는 플레이어가 움직일 때 속도 (방향)가 프레임마다 변경 될 수 있습니다. 모든 상태 변경을 전송하면 프레임 당 패킷을 효과적으로 전송하게되므로 너무 비쌉니다. 대신, 3D 게임은 상태 변경을 무시하고 고정 된 간격 (예 : 80-150ms마다)으로 "상태 업데이트"패킷을 보내는 것으로 보입니다.

게임에서 속도 및 방향 업데이트가 훨씬 덜 자주 발생하므로 모든 상태 변경을 전송하지 않아도됩니다. 모든 물리 시뮬레이션은 동일한 속도로 발생하고 결정 론적이지만 대기 시간은 여전히 ​​문제입니다. 이런 이유로, 나는 3D 게임과 유사한 일상적인 위치 업데이트 패킷을 보내지 만 지금은 250ms마다 훨씬 덜 자주 있지만, 좋은 예측으로 쉽게 500ms로 높일 수 있다고 생각합니다. 가장 큰 문제는 내가 표준에서 벗어났다는 것입니다. 다른 모든 문서, 안내서 및 샘플은 온라인으로 일상적인 업데이트를 보내고 두 상태 사이에서 보간합니다. 내 아키텍처와 호환되지 않는 것 같습니다. (매우 기본적인) "네트워크 물리"아키텍처에 더 가까운 더 나은 움직임 예측 알고리즘을 생각해 내야합니다.

그런 다음 서버는 패킷을 수신하고 스크립트를 기반으로 이동 유형에서 플레이어 속도를 결정합니다 (플레이어가 실행할 수 있습니까? 플레이어의 실행 속도를 얻습니다). 속도가 설정되면 속도를 방향과 결합하여 개체의 속도 인 벡터를 얻습니다. 일부 치트 감지 및 기본 유효성 검사가 발생하며 서버 측의 엔티티는 현재 속도, 방향 및 위치로 업데이트됩니다. 플레이어가 이동 요청으로 서버를 넘치지 않도록 기본 조절도 수행됩니다.

자체 엔티티를 업데이트 한 후 서버는 "아바타 위치 업데이트"패킷을 범위 내의 다른 모든 플레이어에게 브로드 캐스트합니다. 위치 업데이트 패킷은 원격 클라이언트의 클라이언트 측 물리 시뮬레이션 (세계 상태)을 업데이트하고 예측 및 지연 보상을 수행하는 데 사용됩니다.

예측 및 지연 보상

위에서 언급 한 바와 같이, 고객은 자신의 입장에 대해 권위가 있습니다. 부정 행위 나 이상이있는 경우를 제외하고는 서버에서 클라이언트의 아바타 위치를 변경하지 않습니다. 클라이언트의 아바타에는 외삽 ( "지금 이동하고 나중에 수정")이 필요하지 않습니다 . 플레이어가 보는 것은 정확합니다. 그러나 움직이는 모든 원격 엔터티에는 일종의 외삽 또는 보간이 필요합니다. 클라이언트의 로컬 시뮬레이션 / 물리 엔진 내에서 어떤 종류의 예측 및 / 또는 지연 보상이 명확하게 요구됩니다.

문제

나는 다양한 알고리즘으로 고생하고 있으며 많은 질문과 문제가 있습니다.

  1. 외삽, 보간 또는 둘 다해야합니까? 내 "장감"은 속도에 기초한 순수한 외삽 법을 사용해야한다는 것입니다. 상태 변화는 클라이언트에 의해 수신되고, 클라이언트는 지연을 보상하는 "예측 된"속도를 계산하고, 일반 물리 시스템은 나머지를 수행합니다. 그러나 다른 모든 샘플 코드 및 기사와는 상충됩니다. 모두 여러 상태를 저장하고 물리 엔진없이 보간을 수행하는 것으로 보입니다.

  2. 패킷이 도착하면 고정 시간 (예 : 200ms) 동안 패킷의 속도로 패킷의 위치를 ​​보간하려고 시도했습니다. 그런 다음 보간 위치와 현재 "오류"위치의 차이를 사용하여 새 벡터를 계산하고 전송 된 속도 대신 엔티티에 배치합니다. 그러나 다른 패킷이 해당 시간 간격으로 도착한다는 가정하에 다음 패킷이 도착할 때 "추측"하는 것은 매우 어렵습니다. 특히 모든 패킷이 고정 된 간격 (예 : 상태 변경)에 도달하지 않기 때문입니다. 개념에 근본적인 결함이 있습니까, 아니면 맞지만 수정 / 조정이 필요한가요?

  3. 원격 플레이어가 멈 추면 어떻게됩니까? 엔티티를 즉시 중지 할 수 있지만 다시 이동할 때까지 "잘못된"지점에 배치됩니다. 벡터를 추정하거나 보간하려고하면 이전 상태를 저장하지 않기 때문에 문제가 발생합니다. 물리 엔진은 "위치 X에 도달 한 후에 중지 할 필요가 없습니다"라고 말할 방법이 없습니다. 그것은 단지 속도를 이해하고 더 복잡하지 않습니다. "패킷 이동 상태"정보를 엔티티 또는 물리 엔진에 추가하는 것을 꺼려합니다. 기본 디자인 원칙을 위반하고 나머지 게임 엔진에서 네트워크 코드를 피하기 때문입니다.

  4. 엔티티가 충돌하면 어떻게됩니까? 세 가지 시나리오가 있습니다. 제어 플레이어가 로컬에서 충돌하거나, 위치 업데이트 중에 두 개체가 서버에서 충돌하거나, 원격 개체 업데이트가 로컬 클라이언트에서 충돌합니다. 모든 경우에있어 부정 행위를 제외하고는 충돌을 처리하는 방법을 잘 모르겠습니다. 두 상태 모두 "올바른"이지만 다른 시간대에 있습니다. 원격 엔터티의 경우 벽을 통과하는 것이 의미가 없으므로 로컬 클라이언트에서 충돌 감지를 수행하여 "중지"시킵니다. 위의 2 번 지점을 기준으로, "벽을 통해"엔티티를 지속적으로 이동 시키려고 시도하는 "보정 된 벡터"를 계산할 수 있습니다. 성공하지 않을 것입니다. 오류가 너무 높아져서 "스냅"될 때까지 원격 아바타가 고정됩니다. 위치. 게임은 어떻게이 문제를 해결합니까?


1
3D 또는 2D 게임은 어떤 종류의 서버를 사용합니까? 왜 게임을 위해 서버가 작동하지 않습니까?
AttackingHobo

1
@Roy T. 대역폭 트레이드 오프. 대역폭은 오늘날 컴퓨터 시스템에서 가장 중요한 리소스입니다.
FxIII

1
온라인 게임이 응답 시간에 의해 좌우되는 것은 사실이 아닙니다. 예를 들어 서버 클라이언트 간의 대기 시간이 20ms 인 10Mbit 회선 (1.25MB / s)에서 1.25kb 패킷을 보내는 데 20ms + 1ms가 걸립니다. 12.5kb 패킷을 보내는 데 30ms가 걸립니다. 빠른 속도의 두 배인 1.25kb 패킷은 여전히 ​​12.kb 패킷의 경우 20ms + 0.5ms, 20ms + 5ms를 사용합니다. 대기 시간은 제한 요인입니다 하지 대역폭. 어쨌든, 나는 얼마나 많은 데이터가 있는지 모르겠지만 50 개의 vector3 (25x 위치 + 25x 회전)을 보내는 것은 600 바이트에 불과합니다.이를 20ms마다 보내면 30kb / s의 비용이 듭니다. (+ 패킷 오버 헤드).
Roy T.

2
퀘이크 엔진은 첫 번째 버전부터 예측이 있습니다. 지진 예측은 그곳 과 다른 곳에서 설명 됩니다. 확인 해봐.
user712092

1
각 엔티티에 대해이 위치 + = 속도 * 델타 타임을 병렬로 수행합니까? Thief 1 엔진의 기반을 만든 Sean Barret의 반복 문제 가 있습니다 .
user712092

답변:


3

말할 것도없이 2D, 등각 투영, 3D는이 문제와 관련하여 모두 동일합니다. 3D의 많은 예를보고 순간 속도가있는 2D 옥타 트 제한 입력 시스템 만 사용한다고해서 지난 20 년 이상 진화 한 네트워킹 원칙을 버릴 수있는 것은 아닙니다.

게임 플레이가 손상되면 디자인 원칙이 저주받습니다!

이전과 현재를 버림으로써 문제를 해결할 수있는 몇 가지 정보를 버립니다. 이 데이터에 타임 스탬프와 계산 된 지연을 추가하여 외삽이 플레이어의 위치를 ​​더 잘 예측할 수 있고 보간이 시간의 경과에 따라 속도 변화를 더 매끄럽게 만들 수 있습니다.

위의 이유는 서버가 많은 상태 정보를 전송하고 입력을 제어하지 않는 큰 이유입니다. 또 다른 큰 이유는 사용중인 프로토콜에 따라 다릅니다. 수락 된 패킷 손실 및 고장난 UDP? 배달 및 재 시도가 보장되는 TCP? 어떤 프로토콜을 사용하든 이상한 시간에 패킷을 얻거나 지연되거나 쌓여서 활발한 활동을 할 수 있습니다. 클라이언트가 무슨 일이 일어나고 있는지 파악할 수 있도록 모든 이상한 패킷이 컨텍스트에 맞아야합니다.

마지막으로, 입력이 8 방향으로 매우 제한되어 있어도 실제 변경은 언제든지 발생할 수 있습니다. 250ms주기를 시행하면 빠른 플레이어를 실망시킬뿐입니다. 서버 수는 30 명 정도입니다. 당신이 수천에 대해 이야기하고 있다면 ... 심지어 그룹은 여러 개의 상자로 나뉘어져 있으므로 개별 서버는 합리적인로드 만 운반합니다.

Havok 또는 Bullet 실행과 같은 물리 엔진을 프로파일 링 한 적이 있습니까? 그것들은 실제로 매우 최적화되어 있고 매우 빠릅니다. ABC 작동이 느리고 필요하지 않은 것을 최적화한다고 가정하면 함정에 빠질 수 있습니다.


확실한 세이지 조언! 큰 그림을 쉽게 볼 수 있습니다. 이 경우 TCP를 사용하고 있습니다. "8 방향"문제는 입력 측면에서 큰 문제가되지 않습니다. 이는 보간과 외삽에 대한 문제입니다. 그래픽은 해당 각도로 제한되며 애니메이션 스프라이트를 사용합니다. 플레이어가 다른 각도 나 속도로 움직일 경우 게임 플레이는 "이상하게 보입니다".
ShadowChaser

1

따라서 서버는 본질적으로 "레퍼리"입니까? 이 경우 고객의 모든 것이 결정 론적이어야한다고 생각합니다. 각 클라이언트의 모든 항목이 항상 동일한 결과를 제공하는지 확인해야합니다.

첫 번째 질문으로, 로컬 플레이어가 다른 플레이어의 방향을 받으면 시간이 지남에 따라 자신의 움직임을 감소시키고 충돌을 적용 할 수있는 것 외에도 플레이어가 다음 차례에 방향을 예측할 수있는 방법을 알 수 없습니다 8 방향 환경.

각 플레이어의 "실제 위치"업데이트를 받으면 (아마도 서버에서 스 태거를 시도 할 수 있음) 예 플레이어의 위치와 방향을 보간해야합니다. "추측 된"위치가 매우 잘못된 경우 (즉, 마지막 방향 패킷이 전송 된 직후 플레이어가 방향을 완전히 변경 한 경우) 큰 차이가 있습니다. 즉, 플레이어가 위치를 점프하거나 다음 추측 위치로 보간 할 수 있습니다 . 시간이 지남에 따라 더 부드러운 보간이 제공됩니다.

엔터티가 충돌 할 때 결정 론적 시스템을 만들 수 있다면 각 플레이어는 충돌을 로컬로 시뮬레이션 할 수 있으며 결과는 실제와 너무 멀지 않아야합니다. 각 로컬 머신은 두 플레이어의 충돌을 시뮬레이션해야하며,이 경우 최종 상태가 차단되지 않고 수용 가능해야합니다.

서버 측의 경우, 심판 서버는 간단한 계산을 수행 하여 간단한 치트 방지 메커니즘으로 사용하기 위해 짧은 시간 동안 플레이어의 속도 를 확인 합니다 . 한 번에 1 초 이상 각 플레이어의 모니터링을 반복하면 치트 감지 기능을 확장 할 수 있으며 사기꾼을 찾는 데 시간이 더 오래 걸립니다.


고마워-특히 서버 쪽에서 필요한 것과 거의 비슷하게 들립니다. 한 가지 흥미로운 점은 플레이어가 8 개의 방향으로 고정되어 있지만 내부적으로는 3D 벡터입니다. 나는 지난 날에 이것에 대해 조금 더 생각했고, 보간이 전혀 구현되지 않았다는 사실을 고심하고 있습니다. 저는 매우 기본적인 통합을 사용하여 속도를 설정하고 위치를 기반으로 위치를 업데이트합니다. 각 업데이트를 벡터하십시오.
ShadowChaser 2016 년

이를 보간 또는 예측과 결합하는 방법을 잘 모르겠습니다. 패킷으로 전송 된 업데이트 된 위치를 고정 된 기간 (예 : 200ms)으로 통합 한 다음 200ms에서 해당 지점에 도달하는 데 필요한 벡터 (속도)를 결정했습니다. 다시 말해, 클라이언트 쪽에서 플레이어의 현재 잘못된 위치에 관계없이 200ms 내에 동일한 "추정 된 올바른 위치"에 도달해야합니다. 결국 캐릭터를 미친 방향으로 보내 게되었습니다. 200ms는 실제로 다음 패킷까지의 시간이어야하기 때문에 추정 할 수 없습니다.
ShadowChaser 2016 년

t + 1 에서 추측 한 올바른 위치에 잘못된 위치를 통합하기 전에 t 에서 t + 1 의 올바른 위치를 먼저 통합 했습니까 ?
Jonathan Connell

예-원래 통합에 올바른 위치를 사용하고 있는지 다시 확인했습니다. 원래는 버그 였지만 문제를 해결해도 여전히 눈에 띄게 개선되지는 않았습니다. 내 의심은 "+1"입니다. 패킷 사이의 시간에 따라 크게 달라져야합니다. 두 가지 문제가 있습니다. 정기 (250ms) 업데이트 외에 상태 변경을 보내면 언제 발생하는지 알 수 없습니다. 또한 서버가 플레이어에서 멀리 떨어져있는 엔티티에 대해 적은 수의 업데이트를 보내는 것이 합리적이므로 특정 간격으로 잠그기를 꺼려합니다. 패킷 간 시간이 변경 될 수 있습니다.
ShadowChaser 2016 년

1
예, 정해진 종류의 시간 단계를 포함하는 것은 좋은 생각이 아닙니다. 나는 8 방향 움직임의 불규칙성이 예측하기가 매우 어렵다 (불가능하지 않은가?) 걱정이된다. 그럼에도 불구하고, t + 1을 예측하기 위해 클라이언트의 평균 대기 시간을 사용하려고 시도 할 수 있으며 다른 플레이어를 항상 새로운 위치로 "텔레포트" 하는 임계 값을 초과 할 수 있습니다 .
Jonathan Connell

0

상태 변경 메시지에 속도를 포함시키고이를 사용하여 움직임을 예측할 수 없습니까? 예를 들어 속도가 바뀌 었다는 메시지가 나타날 때까지 속도가 변하지 않는다고 가정하십니까? 나는 당신이 이미 위치를 보내고 있다고 생각합니다. 때문에 이로 인해 "오버 슈트"가 발생한다면 다음 업데이트에서 올바른 위치를 가지게됩니다. 그런 다음 마지막 메시지의 속도를 사용하여 이미 업데이트를 수행하는 동안 위치를 밟고 새 위치로 메시지가 수신 될 때마다 위치를 덮어 쓸 수 있습니다. 즉, 위치가 변경되지 않지만 속도는 메시지를 보내야하지만 (게임에서 유효한 경우라도) 대역폭 사용량에 크게 영향을 미치지 않습니다.

보간은 여기서 중요하지 않습니다. 예를 들어 미래에 어떤 위치에 있을지, 가지고 있을지 여부, 어떤 방법을 사용하는지 등 을 알고 있을 때 외삽과 혼동 될 수 있습니까? (내가 설명하는 것은 하나의 간단한 접근법입니다)


-1

첫 번째 질문은 다음과 같습니다. 서버에 권한이있는 모델을 사용하는 데 어떤 문제가 있습니까? 환경이 2D인지 3D인지는 왜 중요합니까? 서버가 권위있는 경우 치트 보호가 훨씬 쉬워집니다.

필자의 샘플 대부분은 움직임 예측을 엔티티 자체에 밀접하게 결합시키는 것을 보았습니다. 예를 들어, 이전 상태를 현재 상태와 함께 저장합니다. 나는 그것을 피하고 엔티티를 "현재 상태"로 유지하고 싶습니다. 이것을 처리하는 더 좋은 방법이 있습니까?

예측을 수행 할 때 신뢰할 수있는 상태 / 델타가 서버에서 수신 될 때 클라이언트의 상태와 비교하여 클라이언트의 상태와 비교할 수 있도록 클라이언트에서 여러 상태 (또는 적어도 델타)를 유지해야합니다. 수정. 아이디어는 필요한 수 정량을 최소화하기 위해 가능한 한 결정론을 유지하는 것입니다. 이전 상태를 유지하지 않으면 서버에서 다른 문제가 발생했는지 알 수 없습니다.

플레이어가 멈 추면 어떻게됩니까? 위치가 너무 멀면 뒤로 또는 다른 이상한 방향으로 걸어야 할 수도 있기 때문에 올바른 위치로 보간 할 수 없습니다.

보간해야하는 이유는 무엇입니까? 신뢰할 수있는 서버는 잘못된 움직임을 무시해야합니다.

엔티티가 충돌하면 어떻게됩니까? 현재 플레이어가 무언가와 충돌하는 경우 대답은 간단합니다. 플레이어가 움직이지 않도록하십시오. 그러나 두 엔티티가 서버에서 동일한 공간을 차지하면 어떻게됩니까? 로컬 예측으로 인해 원격 엔터티가 플레이어 또는 다른 엔터티와 충돌하는 경우 어떻게합니까? 예측이 플레이어가 돌고 있던 벽 앞에 붙잡는 것이 불행한 경우, 예측은 결코 보상 할 수 없으며 일단 오류가 높아지면 개체는 새로운 위치로 스냅됩니다.

이러한 상황은 서버와 클라이언트간에 충돌이 발생하는 상황이므로 서버가 오류를 정정 할 수 있도록 클라이언트의 상태를 유지해야합니다.

빠른 답변에 대해 유감스럽게 생각합니다. 이 기사를 읽으십시오. 슈터에 대해서는 언급하지만 실시간 네트워킹이 필요한 모든 게임에서 작동해야합니다.


몇 가지 답변 : * 서버에 권한이있는 경우 모든 움직이는 엔티티를 추적하고 규칙적인 간격으로 위치를 업데이트해야합니다. 다시 말해, 물리 엔진을 실행해야하는데 비용이 많이들 수 있습니다. 확장 성은 내 주요 디자인 목표입니다. * 클라이언트 측에서 보간해야합니다. 그렇지 않으면 클라이언트로 전송 된 모든 서버 업데이트로 인해 엔티티가 점프합니다. 현재 내 보간은 물리 엔진에서 이루어집니다. 속도 만 설정합니다. 주나 델타가 없습니다.
ShadowChaser

나는 글렌의 모든 기사를 읽었지만, 그는 총격 사건 (즉, 높은 업데이트 빈도)만을 대상으로한다는 의견을 언급했다. 그의 기사 중 일부는 권위있는 고객에 대해 이야기합니다. 나는 서버의 모든 보간 / 물리학을하고 싶지 않아,하지만 그 :) 정말 유일한 방법이라면 내 마음을 바꿀 기꺼이
ShadowChaser

1
-1. 당신이 쓴 것은 주제에 대해 모호하게 만 만집니다. 모호한 느낌. 대답은 본질적으로 "이 긴 기사를 읽을 때"와 비슷하지만, 기사에서 유용한 정보를 포함하지 않습니다.
AttackingHobo

1
@AttackingHobo 동의합니다. 나는 서둘러 언급했지만 변명의 여지가 없습니다. 시간이 없다면 혼자 두는 것이 좋을 것입니다. 교훈을 얻었습니다.
Gyan 일명 Gary Buy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.