본문 바로가기

카테고리 없음

UNITY 게임개발트랙 - 내일배움캠프 48일차 TIL

팀 프로젝트 개발 - 포톤

이번 팀 프로젝트를 개발하며 멀티플레이를 구현하기 위해 처음으로 포톤을 사용했다. 포톤은 멀티플레이 게임용 유니티 패키지인데, 포톤이 제공해주는 서버와 API들을 통해 네트워크에 대해 자세히 알지 못해도 쉽게 멀티플레이 게임을 개발할 수 있다. 이번 프로젝트에는 PUN2를 사용했다.

문제의 시작

팀원들 모두 포톤을 사용하는 것이 처음이다 보니, 어떤 식으로 개발을 해야 하는지 몰랐다. 그래서 와이어프레임을 작성하고 업무를 분담하고 각자 파트를 개발할 때, 일단 로컬에서의 작동만 고려하며 개발하고, 나중에 포톤을 연결했을 때의 경우는 고려하지 않아서 대참사가 발생했다. 나의 경우는 컷씬 제작과 레벨 디자인을 맡았었다. 레밸 내에 구현된 기능들로는 컷씬 재생 후 플레이어 오브젝트 생성, 플레이어들의 부활, 점프시 플레이어가 윗 발판에 머리를 부딛히지 않게 하는 기능, 체크포인트 업데이트, 그리고 그 외 움직이는 장애물들이나 기믹 들이 있었다. 플레이어의 부활의 경우 플레이어 사망을 이벤트로 처리하여, 플레이어 오브젝트를 비활성화했다가 플레이어 오브젝트의 위치를 체크포인트의 위치로 이동하고 다시 재활성화하는 메서드를 구독해둠으로써 구현했었다. 점프시 플레이어가 윗 발판에 머리를 부딛히지 않게 하는 기능은, 플레이어의 RigidBody의 Velocity의 y값을 읽어서, 해당 값이 양수이면 점프를 하고 있다는 의미이므로 지형의 콜라이더를 비활성화하고, 음수이면 낙하중이라는 뜻이므로 지형의 콜라이더를 활성화하고, 이 과정을 코루틴으로 구현했었다. 이 두 기능들 모두 로컬에서 혼자 테스트할 때는 아무 문제가 없었다. 하지만 포톤을 연결하고 온라인으로 테스트를 해보니 전혀 작동하지 않았다. 조사 결과 동기화의 문제였다.

동기화

Transform, Animator, Rigidbody의 경우 해당 PhotonView 컴포넌트를 추가해주면 손쉽게 동기화를 구현할 수 있다. 하지만 함수나 이벤트의 경우, 이렇게 간단한 방식으로는 동기화를 구현할 수 없었다. 함수나 메서드의 경우, Remote Procedure Calls(RPCs)를 통해 동기화와 비슷한 효과를 낼 수 있다. RPC를 사용하면 해당 메서드를 클라이언트에서 실행하는 것이 아니라 서버에서 호출한다. 포톤의 경우 photonView.RPC()메서드를 통해 호출하는데, 타깃을 정해서 어떤 클라이언트들을 타깃으로 호출할지 정할 수 있다.

//메서드를 원격호출하려면 [PunRPC] 속성을 적용해야 한다.
[PunRPC]
void ChatMessage(string a, string b)
{
    Debug.Log("ChatMessage " + a + " " + b);
}

//호출하는 방식은 다음과 같다.
PhotonView photonView = PhotonView.Get(this);
photonView.RPC("ChatMessage", PhotonTargets.All, "jup", "and jup!");

이벤트를 동기화하고 싶을 경우, PhotonNetwork.RaiseEvent를 통해 네트워크 객체에 관계 없이 이벤트들을 전송할 수 있다. 이렇게 동기화에 대해 공부하며, 작동하지 않는 기능들을 고쳐나갔다. 이렇게 동기화를 구현하며 새삼 느낀 것은, 개발할 때 미리 서버에서 실행되어야 할 메서드와 클라이언트에서만 실행해야 할 메서드를 미리 구분해두며 개발하면 편할 것 같다는 생각이 들었다. 다음에 포톤을 사용한 프로젝트를 개발할 때는 꼭 그래야겠다...