나는 현재 다소 단순한 멀티 플레이어 플랫 포머를 만들고 있습니다. 지연 시간을 숨기는 데 사용되는 기술에 대한 기사를 많이 읽었지만 여전히 특정 개념에 대해 이해하지 못했습니다. 주제가 매우 흥미롭고 아이디어를 직접 시도하는 것을 좋아하지만 gamedev stackexchange를 요청하는 것이 내 질문에 더 효율적이라고 생각합니다. 나는 현재 상황과 그 과정에서 어떤 질문이 생겼는지 설명하기 위해 최선을 다할 것입니다.
지금은 단일 플레이어 만 서버와 동기화하고 싶습니다. 이론적으로 클라이언트 측 예측을 가진 플레이어는 자신의 움직임에 영향을 미치는 외부 요인이 없기 때문에 서버 수정이 필요하지 않다고 가정했습니다. 따라서 제 프로토 타입은 현재 서버 수정없이 서버와 동기화 된 플레이어가 한 명뿐입니다.
게임 네트워킹에 익숙하다면 상황 섹션을 건너 뛸 수도 있지만 그 과정에서 잘못된 일이 있었을 수도 있습니다.
클라이언트 루프 (프레임 당 한 번, ~ 16.67ms마다 한 번씩)
단순화 된 클라이언트 루프는 다음과 같습니다.
로컬 입력 (WASD)을 확인하고 조치로 패키지하십시오 (예 :)
Type=MoveLeft, Time=132.0902, ID=15
. 패키지 된 작업은 나중에 보내도록 유지합니다. 또한 게임의 로컬 물리 시뮬레이션에 원하는 동작을 직접 적용합니다. 예를 들어MoveLeft
액션 이있는 경우 플레이어 속도에서 왼쪽으로 힘을가합니다.조치를 보내려면 확인하십시오. 클라이언트 대역폭을 남용하지 않으려면 특정 간격 (예 : 30ms)으로 패키지 된 작업 만 보내십시오.
서버 수정 사항을 적용하십시오. 특정 시점에서 서버가 수신 한 델타 및 수정 사항을 처리하여 게임의 로컬 시뮬레이션에 적용합니다. 이 특정 질문에 대해서는 사용되지 않습니다.
로컬 물리를 업데이트합니다. 메인 플레이어에서 물리 루프를 실행하십시오. 기본적으로 이것은 플레이어의 움직임에 대한 클라이언트 측 예측을 수행합니다. 이것은 플레이어의 속도에 중력을 추가하고, 플레이어의 속도를 자신의 위치에 적용하고, 길을 따라 충돌을 수정합니다. .
물리학 및 기타 섹션에 대해서는 질문에 필요하지 않다고 생각하기 때문에 몇 가지 구체적인 세부 사항을 건너 뛰고 있지만 질문과 관련이 있는지 알려주십시오.
서버 루프 (15ms마다)
단순화 된 서버 루프는 다음과 같습니다.
조치를 처리하십시오. 클라이언트로부터받은 조치 패키지를 확인하여 서버 물리 시뮬레이션에 적용하십시오. 예를 들어 5 개의
MoveLeft
동작을 수신 할 수 있으며 속도에 5 번 힘을가합니다 . 전체 액션 패키지는 액션이 발생하자마자 적용되는 클라이언트 에 대해 하나의 "프레임" 에서 실행된다는 점에 유의해야 합니다.게임 로직을 업데이트하십시오. 우리는 게임 물리, 플레이어 이동 및 충돌 수정 등을 업데이트합니다. 또한 나중에 플레이어에게 전송되는 중요한 이벤트 (예 : 플레이어의 체력 저하, 플레이어 사망 등)도 패키지합니다.
수정 사항을 보내십시오. 우리는 정기적으로 (예 : 35ms마다) 최근에 다른 선수 (예 : 선수 위치, 건강 등)에 델타를 보냅니다. 이 부분은 현재 단일 플레이어의 시뮬레이션으로 클라이언트 및 서버에서 동일한 결과를 수정하지 않고 클라이언트 측 예측이 올바르게 작동하도록하기 위해 구현되지 않았습니다.
문제
현재 시스템은 간단한 상황에서 잘 작동하며 간단한 수평 이동으로 매우 유사한 결과를 얻었음을 기쁘게 생각합니다 (부정확도는 부동 소수점 정밀도 오류로 인한 것입니다).
프로토 타입 그래픽은 무시하십시오. 흰색 사각형 = 플레이어, 빨간색 사각형 = 장애물, 파란색 = 배경
그러나 점프하고 고립 된 장애물에 가까이 이동하는 것과 같이 시간에 민감한 움직임을 한 후에 동기화 오류가 발생합니다.
이론적으로, 나는 클라이언트가 자신의 입장에 영향을 미치는 외부 요인이 없기 때문에 둘 다 항상 동일한 결과로 끝날 것으로 기대합니다. 그러나 실제로는 문제를 이해한다고 생각합니다.
이와 같은 장애물을 뛰어 넘는 것은 플레이어의 타이밍에 따라 크게 달라 지므로, 속도가 위치에 적용될 때 의 작은 변화 는 결과에 영향을 줄 것입니다 (예 : 클라이언트가 서버는 나중에 전체 작업 패키지를 수신하고 소량의 시간 동안 장애물에 붙어있어 최종 결과를 변경하므로 서버가 수행합니다. 클라이언트와 서버가 처리하는 방법의 차이점은 주로 클라이언트가 발생하는 모든 작업을 수행하는 반면 서버는 수신하는 모든 작업을 대량으로 수행한다는 것입니다.
질문
이 긴 맥락은 마침내 내 질문에 이르게합니다 (이 글을 읽어 주셔서 감사합니다) : 서버와 동기화 된 플레이어가 하나 뿐인 경우에도 서버 수정이 필요하거나 시간에 민감한 상황에서 비 동기화를 피하기 위해 특정 기술을 사용해야합니까? ?
나는 어떤 가능한 해결책을 생각했는데, 그중 일부는 내가 덜 편안합니다.
서버 수정을 구현하십시오. 이것이 정상적인 동작이라고 가정하고 오류가 발생하면이를 수정하십시오. 어쨌든 그것을 구현하고 싶었지만 지금까지 내가 한 일이 수용 가능한지 확인하고 싶었습니다.
제공된 클라이언트 시간을 사용하여 원하는 조치를 적용하십시오. 나는 이것이 지연 보상과 유사 할 것이라고 생각한다. "시간으로 돌아가서"움직임을 점검해야한다. 서버 수정을 적용하는 것과 마찬가지로, 시간을 거슬러 올라간 후 다음 조치를 다시 적용하십시오. 나는 그 아이디어를 정말로 싫어한다. 복잡하고 비용이 많이 드는 것처럼 보이며 클라이언트가 제공 한 시간을 신뢰해야합니다 (시간이 비교적 합법적으로 보이는지 실제로 확인하려고하지만).
GameDevelopment StackExchange에 내 모든 문제를 해결할 훌륭한 새로운 아이디어를 요청하십시오.
방금 게임 네트워킹의 세계에서 시작하고 있으므로 위의 개념을 수정 / 비판 / 모욕하거나 Wonderful World of Networking에서의 여정에 도움이되는 아이디어 / 자원을 자유롭게 제공하십시오. 다른 곳에서 내 대답을 찾을 수 있다면 용서하십시오.
소중한 시간 감사합니다.