본문 바로가기
개발/Unity 내일배움캠프 TIL

Unity 포톤 동기화 작업 시 주의할 점들

by 석시 2023. 10. 19.



캠프에서 포톤을 이용한 팀 프로젝트가 점점 마무리되는 단계이다.

포톤으로 동기화를 하면서 플레이어 동기화 같은 것들이 어려울 줄 알았는데, 의외의 복병이 바로 게임 로직 동기화였다.

서버 (or 마스터 클라이언트) 에서 처리해야하는 함수와 개별 클라이언트에서 각각 처리해야하는 함수들의 구분이 필요했었는데, 초기 코드 작성 단계에서 그것을 제대로 고려하지 않은 점이 가장 큰 패착이었다.

프로젝트의 완성도가 아쉬운만큼 그 아쉬운 점에 대해 적어보려 한다.


플레이어블 캐릭터를 Instantiate할 때

private void StartGame()
{
    int idx = PhotonNetwork.LocalPlayer.ActorNumber;
   
    if (idx == 1)
    {
        GameObject prefab = Resources.Load<GameObject>("Player");
        _bluePlayer = PhotonNetwork.Instantiate(prefab.name, new Vector3(-3.63f, 0.46f, 0), Quaternion.identity);
        photonView.RPC("SetBluePlayer", RpcTarget.All, _bluePlayer);
        PlayerRigidBody = _bluePlayer.GetComponent<Rigidbody2D>();
    }
    else if (idx == 2)
    {
        GameObject prefab = Resources.Load<GameObject>("Player_Black");
        _blackPlayer = PhotonNetwork.Instantiate(prefab.name, new Vector3(-7.63f, 0.46f, 0), Quaternion.identity);
        photonView.RPC("SetBlackPlayer", RpcTarget.All, _blackPlayer);
        PlayerRigidBody = _blackPlayer.GetComponent<Rigidbody2D>();
    }

}

우리 프로젝트 코드였는데, 문제가 많다.

위 문제에서 상황이 대체 무엇이냐면

아래에서 윗 방향으로 (Velocity.y > 0) 지형을 뚫고 점프할 때 지형 Collider를 일시적으로 비활성화해주는 기능을 구현한 것이다.

이걸 원래는 Client에서 껐다 켰다 해주는게 맞을 것이다.

문제는 여기서 Transform하고 Animator를 동기화해주는데 내가 조종하고 있는 캐릭터가 아닌 다른 플레이어의 캐릭터 Transform을 동기화해주는 과정에서 그 캐릭터의 지형 Collider 기능은 작동하지 않아서 발생하는 문제인 것이다.

여기서 잘 생각해야 한다.

해결책이 있을텐데, 1. 서버 상에서 지형 Collider를 꺼주는 방법 2. 클라이언트에서 캐릭터의 Collider를 꺼주는 방법

우리는 1번 방법을 선택했는데, 2번을 하려면 전제되어야 하는 것이, 내 캐릭터를 제외한 다른 캐릭터에서는 부착된 Collider가 떨어져있어야 한다는 것이다. (추가로 지형과 부딪히지 않아 떨어지는 것을 없애기 위해 rigidbody까지도!)

이거를 프리팹 Instantiate시 일일히 초기화해줘야하는 점이 우리를 1번 방법을 선택하게 된 이유가 되겠다.

하지만 이제와서 생각해보면 2번 방법이 맞았던 것 같은데, 지형의 Collider를 끄는 기능이 아무리 생각해봐도 적절치 못한 것도 있고, (위 움짤의 왼쪽 화면을 보자. 2번 플레이어가 걸려 있다가 1번 플레이어가 통과할 때 같이 통과된다.)

추가적인 문제를 방지하기 위해 다른 플레이어의 Transform, Animator를 제외한 다른 기능의 컴포넌트는 원래 제거하는 게 맞는 것이다!

즉, 내가 생성한 캐릭터 (IsMine) 오브젝트와 다른 사람이 생성한 캐릭터의 초기화 방법이 각각 달라야 한다는 것이다.

이걸 못해서 많이 해멨으니…. 다음에 할 땐 실수를 방지할 수 있을 것이다.


게임 로직 동기화

내가 유니티를 쓰기 전에 다뤄봤던 툴이, 로블록스하고 메이플스토리 월드였다.

해당 툴은 기본적으로 멀티플레이를 전제로 만들어졌기 때문에 내가 함수를 실행할 때부터 다음의 네 가지를 결정할 수 있다.

Server Only : 서버에서만 호출되고, 서버에서 실행 Server : 서버, 클라이언트에서 호출 가능하고, 서버에서 실행 Client : 서버, 클라이언트에서 호출 가능하고, 각 클라이언트들에서 실행 Client Only : 클라이언트에서만 호출되고, 클라이언트에서 실행

포톤에서 함수를 해당 방식으로 일일히 지정해줄 수는 없지만, 확실한 것은 ”서버 (or 마스터 클라이언트) 에서 실행되는 함수와 클라이언트에서 실행되는 함수를 철저히 구분해야 한다”라는 것이다.

#region을 통해 나눠도 될테고, 가장 좋은 것은 스크립트 자체를 나눠버리는 것이 되겠다.

시간이 난다면 포톤으로 앞선 호출 위치와 실행 위치를 지정해줄 수 있는 키워드를 가진 함수 프리셋을 만드는 것도 좋을 것이다.

아니면 이미 있나? 찾는데 성공한다면 수정하여 작성하도록 하겠다.


Uploaded by N2T