캠프에서 포톤을 이용한 팀 프로젝트가 점점 마무리되는 단계이다.
포톤으로 동기화를 하면서 플레이어 동기화 같은 것들이 어려울 줄 알았는데, 의외의 복병이 바로 게임 로직 동기화였다.
서버 (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
'개발 > Unity 내일배움캠프 TIL' 카테고리의 다른 글
Unity 제네릭 싱글턴 (Generic Singleton) (0) | 2023.11.13 |
---|---|
최종프로젝트를 앞두며 (0) | 2023.10.20 |
Unity 기존 게임을 포톤 PUN2로 동기화하기 (1) | 2023.10.18 |
Unity 포톤으로 멀티플레이 구현해보기 (0) | 2023.10.17 |
Unity2D 사이드뷰 게임의 좋은 움직임 만들기 (1) | 2023.10.16 |