주의 사항:Photon TrueSync와 Thunder는 서비스 종료되었으며 앞으로도 업데이트 및 릴리즈는 없을 예정입니다. 기존 어플리케이션에 영향은 없습니다만 현재 개발중인 어플리케이션에 대해서는 마이그레이션을 장려합니다.

TrueSync 튜토리얼 파트 2

튜토리얼 목차

이 튜토리얼 시리즈에서는 Photon TrueSync 를 이용하여 Unity 로 간단한 멀티플레이어 게임을 만드는 방법에 대해서 설명합니다. 파트 1에서는 TrunSync 를 다운로드하여 설치하고 게임 클라이언트들이 Photon 클라우드에 연결하고 Photon 룸에 참여하는 기본적인 Photon Unity Network 에 대한 핵심사항을 배웠습니다.

파트 2에서 학습할 내용:

각 플레이어당 박스를 인스턴스화한 게임 클라이언트가 룸에 연결 되었습니다. 플레이어들은 자신의 상자를 주위로 움직일 수 있으며 모든 움직임은 각 플레이어의 input이 한 클라이언트에서 다른 클라이언트로 전송하여 동기화 됩니다.

TrueSyncManager 프리팹과 컴포넌트

튜토리얼 파트 1에서 만들었던 "Game" 신을 오픈하세요. 이제 신에 TrueSyncManager 를 넣어주세요 ( Unity 메뉴:Game Object/TrueSync/TrueSyncManager). 이제 신의 계층구조는 다음과 같을 것 입니다:

Scene hierarchy with TrueSyncManager
TrueSyncManager가 들어있는 신 계층구조.

TrueSyncManager 프리팹에는 TrueSyncManager 라고 부르는 컴포넌트가 포함되어 있으며 이 컴포넌트는 TrueSync 업데이트와 lockstep 시뮬레이션을 담당하고 있습니다.

TrueSyncManager Component
TrueSyncManager 컴포넌트.

대부분의 TrueSync 옵션은 이 튜토리얼 파트4에서 다루게 될 다른 에셋에서 설정되므로, 여기에서 필요한 것은 플레이어 프리팹을 추가하는 것입니다.

신 저장을 잊지마세요. 이제 신에 TrueSyncManager 오브젝트가 포함되어 있습니다.

플레이어 프리팹 생성하기

플레이어 프리팹은 게임 세션/룸에 연결된 모든 플레이에의 인스턴스화된 복사본을 가지고 있는 게임 오브젝트입니다.

다음 섹션에서 보게될 것 처럼 언제라도 코드를 통해 오브젝트들을 인스턴스화 할 수 있으나, TrueSync 에는 플레이어가 제어할 객체들을 자동적으로 생성할 수 있는 편리한 방법이 있습니다.

이제 간단하게 TrueSync 큐브를 생성하기 위해서 Unity 메뉴를 사용할 것인데, 이 메뉴는 예제에서 필요한 결정론전 물리 컴포넌트에 이미 포함되어 있습니다. "GameObject/TrueSync/Cube" 를 눌러 큐브를 생성합니다.

아래의 그림에 보인 것 처럼 TSRigidbody 컴포넌트를 설정해주세요. 중력의 영향이 없이 코드를 통해 움직임을 제어 할 것입니다. 게임 오브젝트의 태그는 "Player" 로 되어 있어야 하니 확인 해 주세요.

TSRigidbody Component
TSRigidbody 컴포넌트.

이제 게임 오브젝트의 이름을 "PlayerBox"으로 변경하고 "Tutorial" 폴더로 드래그 하여 새로운 프리팹으로 저장합니다.

이제 신에서 게임 오브젝트를 반드시 삭제 하시고 이전에 생성되었던 TrueSyncManager 오브젝트 내의 프리팹 레퍼런스를 추가합니다. 이렇게 하기 위해서는 TrueSyncManager의 플레이어 프리팹 갯수를 1로 변경하고 아래 그림과 같이 "Tutorial" 폴더에서 프리팹을 열려진 슬롯으로 드래그합니다.

Player prefab referenced in TrueSyncManager
TrueSyncManager에서 참조되는 플레이어 프리팹.

각 클라이언트에서 TrueSync는 룸에 연결된 각 플레이어에 대하여 플레이어 프리팹 복사본을 생성할 것 입니다. TrueSync는 오프라인 모드에서도 동작하므로, 에디터에서 "Game" 신에 대하여 테스트로 실행하여 PlayerBox(Clone) 객체가 계층구조(아래 그림 참조)에서 자동으로 생성 되는지를 체크할 수 있습니다.

Instantiated player prefab in the scene
신에서 인스턴스화된 플레이어 프리팹.

이 파트를 끝낸 후 신 저장을 잊지 마세요.

Player 프리팹에 TrueSyncBehaviour 추가하기

TrueSync는 lockstep 시스템이므로 동기화에 필요한것은 플레이어의 input 하나 입니다. 이 튜토리얼에서는 플레이어가 자신이 가지고 있는 상자만을 제어하게 할 것이므로 이 기능을 구현하기 위한 스크립트를 추가할 것 입니다.

"Tutorial" 폴더에서 C# 스크립트를 생성하고 "PlayerMovement.cs"로 이름을 부여 합니다. 이제 다음과 같이 코드를 작성합니다.

C#

using UnityEngine;
using System.Collections;
using TrueSync;

public class PlayerMovement : TrueSyncBehaviour {

}

스크립트는 "TrueSyncBehaviour" 에서 상속을 받았기 때문에 Unity 에서 기본적으로 사용하는 콜백다신 다른 콜백을 사용할 것 입니다. 다른 콜백을 사용하는 이유는 게임 오브젝트가 결정론전 엔진이 아닌 Unity 대신 lockstep 게임 루프에서 제어되어야 하기 때문입니다.

이제 이전에 생성한 PlayerBox 프리팹에 이 스크립트를 붙여 TrueSync 가 프리팹 복사본을 인스턴스화 시킬 때 "PlayerMovement.cs" 가 일부분이 되게 됩니다.

항상 신을 저장하여 프리팹들과 레퍼런스들이 같이 저장되도록 해 주세요.

Input 수집 및 큐에 넣기

lockstep 시스템은 모든 플레이어의 input을 동시에 사용하여 모든 클라이언트에서 동시에 시뮬레이션을 수행하므로 프레임 단위 결과는 항상 동일합니다.

동일한 결과를 얻기위해서, Unity의 입력을 사용하여 게임 오브젝트를 직접 조작하거나 게임 상태의 모든 값을 변경 할 수 없습니다.

직접 조작하는 대신, Unity 로 부터 플레이어의 input 값을 수집하여 모든 게임 클라이언트들에게 배포할 TrunSync의 input 시스템 큐에 넣는 코드를 추가할 것 입니다. 여기에는 나중에 설명해 드릴 다른 update 메소드에서 사용되는 로컬 값도 포함됩니다.

다음은 Unity의 input 축 값을 TrueSync input 큐에 등록하는 코드입니다. 이 코드를 "PlayerMovement.cs" 에 추가해주세요.

C#

public override void OnSyncedInput() {
    FP accell = Input.GetAxis ("Vertical");
    FP steer = Input.GetAxis ("Horizontal");

    TrueSyncInput.SetFP (0, accell);
    TrueSyncInput.SetFP (1, steer);
}

로컬 플레이어 오브젝트에서만 호출되는 "OnSyncedInput" 커스텀 콜백 내부에서 이 작업을 수행하는 것에 주의해주세요. 원격 플레이어가 소유한 객체들은 자신의 기기에서만 실행되는 이 콜백을 갖게 될 것 입니다. TrueSync 가 input 을 모든 기기 사이에 전달해줍니다.

이기종 기기와 플랫폼 사이에서 모두 결정론적 계산을 위해, float 를 FixedPoint (FP) 로 변환했다는 것이 또한 중요합니다. 다음 세션에서 이 사항에 대해 더 설명을 할 것 입니다.

상자 움직이기

이제 TrueSync는 큐에 넣어진 축 input 값이 있으며 기기간에 분배하였으므로, 플레이어 상자를 움직이는데 사용 해 보겠습니다. 이 작업은 또 다른 커스텀 콜백인 "OnSyncedUpdate" 에서 진행될 것이며, 모든 플레이어(로컬 플레이어도 포함)의 특정 틱/프레임의 모든 input 을 사용 할 수 있을 때 TrueSync 에 의해 호출됩니다.

C#

public override void OnSyncedUpdate () {
    FP accell = TrueSyncInput.GetFP (0);
    FP steer = TrueSyncInput.GetFP (1);

    accell *= 10 * TrueSyncManager.DeltaTime;
    steer *= 250 * TrueSyncManager.DeltaTime;

    tsTransform.Translate (0, 0, accell, Space.Self);
    tsTransform.Rotate (0, steer, 0);
}

TrueSyncInput 큐에서 FixedPoint (FP) input 값을 얻어와 TrueSync 버전의 DeltaTime 과 속도 팩터를 곱하고 있다는 점을 주의해주세요.

보정을 원하시면 지금 Unity 에디터에서 고정 속도 요소를 FixedPoint 속성으로 교체할 수 있습니다.

두 개의 값이 상자를 이동/회전 시키는데 사용됩니다. "Translate" 와 "Rotate" 메소드를 이용하여 이동 및 회전시키지만 Unity 의 transform 이 아닌 "TSTransform" 컴포넌트에 적용하고 있다는 점을 주의 해 주세요.

tsTransform 변수는 "TrueSyncBehaviour" 에서 상속된 스크립트의 사전-참조된 "TSTransform" 컴포넌트 입니다.

대부분의 Unity 의 서브시스템이 결정론을 보장 해주지 않으므로 TrueSync는 모든 게임 플레이 코드에서 결정론적이어야 하는 것을 요구하게 되므로 이렇게 하는 것이 필요합니다.

TrueSync 에는 쉽게 lockstep 게임을 쉽게 작성하기 위해 Unity의 API 와 유사한 콤포넌트들이 많이 포함되어 있습니다: 2개의 커스텀 결정론적 물리 엔진(2D와 3D), Transform 컴포넌트(TSTransform), FixedPoint 타입 (FP), 난수 발생 (TSRandom), 수학 라이브러리(TSVector, TSMatrix, TSQuaternion) 등.

플레이어 프리팹이 TrueSync 큐로 input 하는 스크립트가 있으므로 상자를 움지이기 위해 이 input 을 사용하기 위해 커스텀 업데이트 콜백을 사용합니다. 멀티플레이어 모드에서 코드를 테스트 해 봅니다(언제든지 에디터에서 직접 신을 실행하여 오프라인/싱글 플레이어 모드로 코드를 테스트 할 수 있습니다).

프로젝트 탭에서 "PlayerMovement.cs" 스크립트를 "PlayerBox" 붙였는지 확인하는 것을 잊지 마세요.

지금 하면 좋은 것은 플레어어 상자들이 돌아다닌 것을 잘 볼 수 있도록 카메라 위치를 잡는 것 입니다. 트랜스폼 컴포넌트에는 다음 값으로 설정하는 것을 제안해드립니다.

Camera transform in game scene
게임 신 내의 카메라 트랜스폼.

테스트하기

두 개의 신(Tutorial/Menu 과 Tutorial/Game)이 빌드 설정에 모두 포함 되었고 Tutorial/Menu 가 첫 번째 신인지 확인 해 주세요(Unity 가 시작시 로드할 신).

빌드를 선택하고 두 카피본을 실행하거나, 한 카피본은 실행하고 하나는 Unity 에디터에서 Menu 신을 실행하세요.

두 클라이언트가 Photon 에 접속된 후 각 클라이언트가 자신의 상자를 제어하는 game 신이 로드되는 것을 볼 수 있어야 합니다.

이제 (link?) 파트3에서 동시에 총알을 쏘는 방법을 배워보도록 하겠습니다.

Back to top