이제 네트워크를 통해 다중 접속해 주인공 캐릭터의 이동, 회전및 애니메이션이 제대로 동기화되는지 확인해보자. 지금까지 구현된 상태로 빌드해 실행 파일을 생성한다..
메뉴에서 [Edit]-[Project Settings..]를 선택해 Project Settings 윈도우를 연 후 [Player]섹션을 선택한다. Resolution and Presentation에서 Fullscreen Mode를 [Windowed]로 변경하고 가로 및 세로 해상도를 적절히 설정한다.
메뉴에서 [File]-[Build Settings...]를 선택해 Build Settings 창을 연다. [Build And Run] 버튼을 클릭하면 저장할 경로를 물으면 Builds라는 폴더를 새로 생성하고 실행 파일명을 입력한 다음 Save를 눌러 저장한다. 빌드과정이 끝나면 자동으로 게임이 실행된다. 이제 유니티도 실행하면 2번째로 입장하게 되고 2개의 윈도우를 보면 각자의 게임속에서 네트워크 유저가 움직이는걸 확인할 수 있다
OnPhotonSerializeView 콜백 함수
같은 룸에 입장한 네트워크 객체간 데이터를 동기화 시키는 2번째 방법은 OnPhotonSerializeView 콜백 함수를 사용하는 것이다. 앞서 구현한것 처럼 PhotonTransformView와 PhotonAnimatorview는 컴포넌트만 추가하면 간단히 동기화 처리가 되지만, 좀 더 세밀한 보정이 필요할 때는 이 콜백 함수가 유용하다.
우선 Resources폴더에 있는 Player프리팹을 선택하고 PhotonTransform 컴포넌트를 제거한다. 그다음 Movement 스크립트를 다음과 같이 수정한다.
먼저 Movement 클래스에 IPunObservable 인터페이스를 추가한다.
public class Movement : MonoBehaviourPunCallbacks, IPunObservable {
OnPhotonSerializeView 콜백 함수의 첫 번째 인자인 PhotonStream.IsWriting 속성이 true이면 데이터를 전송하는 것을 의미한다. PhotronView.IsMine 속성이 true일 경우 네트워크 객체는 자신의 캐릭터이다. 자신의 캐릭터 transform정보는 같은 룸에 입장한 모든 객체에게 전송되어야 하고 false일 경우 다른 네트워크의 객체의 transform 정보를 수신해야 한다.
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
// 자신의 로컬 캐릭터인 경우 자신의 데이터를 다른 네트워크 유저에게 송신
if (stream.IsWriting) {
stream.SendNext(transform.position);
stream.SendNext(transform.rotation);
} else {
receivePos = (Vector3)stream.ReceiveNext();
receiveRot = (Quaternion)stream.ReceiveNext();
}
}
데이터를 전송하는 것은 PhotonStream.SendNext() 함수를 이용해 전달하며 데이터를 수신할 때는 PhotonStream.ReceiveNext()를 이용한다. 전송하는 데이터의 개수와 데이터타입은 수신할 데이터의 개수와 타입이 일치해야 한다. 수신한 데이터는 receivePos, receiveRot에 저장되고 Update() 함수에서 사용된다.
Update()함수에서 PhtonView.IsMine 속성으로 자신의 캐릭터는 직접 컨트롤 하고 타 네트워크 유저 캐릭터는 수신받은 데이터로 이용해 이동 시킨다. 이때 이동할 좌표는 Vector3.Lerp 함수를 이용해 보간하고 회전값은 Quaternion.Slerp함수를 사용해 보간한다.
void Update() {
// 자신이 생성한 네트워크 객체만 컨트롤
if (pv.IsMine) {
Move();
Turn();
} else
{
// 수신된 좌표로 보간한 이동처리
transform.position = Vector3.Lerp(transform.position,
receivePos,
Time.deltaTime * damping);
// 수신된 회전값으로 보간한 회전처리
transform.rotation = Quaternion.Slerp(transform.rotation,
receiveRot,
Time.deltaTime * damping);
}
}
스크립트를 수정한 후 Player 프리팹의 PhotonView컴포넌트를 보면 Observable Serch 속성이 [Auto]로 되어 있기 때문에 Player(Movement) 스크립트가 자동 적용되어 있다. [Manual]이라면 직접 드래그해서 추가해야 한다.
로직을 변경했으므로 다시 Build해서 테스트 해보자
큰 차이는 없어보이지만 OnPhotonSerializeView 콜백 함수를 이용해 직접 데이터를 송수신해 처리했다.