개요
최근 작업중인 프로젝트에서 실시간 pvp모드를 개발하고 있었다.
프로토타입은 포톤을 이용해서 동기화를 진행한 후 플레이를 해봤고,
이제 회사의 TCP서버로 이전해 달라는 지시가 내려와 작업을 진행하였다.
포톤의 경우에는 TransformView 컴포넌트가 있어서
위치동기화의 경우 아주 쉽게 구현할 수 있는데
직접 위치 동기화를 구현할려면 아무리 정보를 모아서 한번에 보낸다 해도
매 프레임 패킷을 보내는거는 무리가 있다.
그래서 데드레커닝 기법을 활용하여 위치 동기화를 구현한 사례를 적는다.
본문
마우스로 이동하는게임이었다면 꽤 간단한 문제였을것이다.
예를들어 LOL이라면
유저가 마우스로 목적지를 클릭하면
그때 한번만 출발지와 목적지를 동기화 하고
양측 클라이언트는 결과가 같다는 보장이있는 길찾기 알고리즘을 사용하면 된다.
하지만 키보드로 조작(또는 조이패드, 가상스틱 등등)은 캐릭터가 '바로 앞'으로 이동하는 개념이고
바라보는 방향도 영향을 미치기때문에 위치에 민감하다.
따라서 이 경우에는 동기화 빈도를 어쩔수없이 높일수밖에 없긴하다.
작업중인 프로젝트의 경우는 후자였다.
그래서 구현한 방법은 다음과 같다.
1. 위치동기화는 무조건 고정적으로 0.2초마다 보낸다.
'데드레커닝을 이용하면 인풋이 변경할때만 보내야 하는게 아닌가?' 라고 처음엔 나도 생각을 했지만
그렇게 할 경우 미세한 틀어짐이 반복되면 결국 나비효과가 되어
실제위치와 타 클라이언트속의 아바타의 위치가 많이 틀어지게 된다.
그래서 일정주기로 '강제 보정'을 해주지 않으면 안되는 상황이 일어나게 된다.
그래도 패킷주기가 0.2초이기 때문에 예측과 보간은 필수이다.
2. 이동을 시작하면 이동시작 패킷을 보낸다.
이거는 뒤에 추가설명이 필요한 내용이다
bool변수를 하나 만들어서 오브젝트의 이동시작 패킷을 받으면
아바타 오브젝트의 이동중이라는 표시를 해준다.
3. 목적지에 도착했는데도 새 위치 패킷을 받지않았거나, 이동중지 패킷을 받지않았다면 계속 이동한다.
[그림 1]에서 캡슐A는 동기화 오브젝트, POS A는 받은 목적지 좌표이다.
처음 이동시작을 받은 후 목적지 패킷을 받으면,
그 목적지로 향하는 방향벡터를 계산해둔다.
그 이후 목적지에 도착했는데 아직 0.2초가 안지나서 다음 목적지를 받지 못했다면,
또는 이동중지 패킷을 받지않아서 이동중지인지 확실하지 않다면
계산한 방향을 토대로 그 방향 그대로 계속 보낸다.
이때 만약 이후 받은 패킷에따라 방향이 틀렸거나 사실은 이동중지였다면
이후 받은 패킷에 있는 진짜목적지로 강제보정을 진행한다.
이 경우에는 캐릭터가 앞서가다가 갑자기 되돌아가는 듯 보이게 된다.
결론
이렇게 간단하게 데드레커닝 기법을 활용하여
위치동기화를 구현했다.
하지만 아쉬움이 남는건 사실이다.
사실 순간 판정이 중요한 게임이라면
위치를 '예측'해버렸기 때문에
판정을 어디서하냐에 따라 다르지만
원래라면은 맞지 않아야할 히트도 맞을수 있기 때문이다.
그렇지만 위치동기화만 두고 본다면
확실히 서버의 부담은 덜었고 위치도 꽤 자연스럽게 맞는다.
이후에는 판정과 동기화 속도를 둘다 잡을 수 있는 방법을 생각해봐야겠다.
참고한 글
'Unity > Network' 카테고리의 다른 글
[Unity] 오픈 소스 게임 서버 Nakama를 알아보자 (0) | 2024.10.24 |
---|---|
[Unity] HTTP 통신 모듈 빌더패턴으로 재구성 (0) | 2023.03.08 |
[Unity] HTTP REST api 통신 모듈 구현 (8) | 2023.02.14 |