실시간 편: 두 플레이어 동기화하기

내가 움직인 캐릭터를 상대 화면에도 표시해 봅니다.

두 게임 화면을 같은 룸에 연결합니다. WASD 키로 캐릭터를 움직이고 스페이스 키를 누르면 양쪽 화면에서 같은 캐릭터가 잠깐 커집니다.

기본편에서 준비한 GS2 학습용 프로젝트와 Unity 프로젝트를 사용합니다. 이 페이지에서는 새 RealtimePractice 씬을 만들고 SDK로 연결합니다.

1. Realtime 네임스페이스 만들기

관리 콘솔에서 학습용 프로젝트의 Tokyo 리전을 엽니다.

  1. Realtime → Namespace list → Create namespace 를 엽니다.
  2. 다음 값을 입력하고 생성합니다.
항목값
이름adventure-sync
서버 종류오브젝트 동기화(sync)
서버 사양realtime1.nano

2. 로그인할 씬 만들기

  1. Unity의 File → New Scene 에서 빈 씬을 만들고 RealtimePractice로 저장합니다.
  2. AdventureLogin.cs를 Assets에 저장합니다. 같은 파일이 이미 있다면 기존 파일을 사용합니다.
  3. 빈 Login 오브젝트를 만들고 AdventureLogin을 추가합니다.
  4. 관리 콘솔의 Deploy → Default → Output list 에서 ApplicationClientId와 ApplicationClientSecret을 가져와 Client Id / Client Secret 에 입력합니다.
  5. Account Namespace 는 Studio에서 계정을 만들었다면 Account, SDK 코스라면 adventure-account로 설정합니다. Account Slot 은 realtime-a로 설정합니다.
  6. Edit → Project Settings → Player → Other Settings → Active Input Handling 을 Both 로 설정합니다. 재시작을 요청하면 Unity를 재시작합니다.
  7. 같은 Player 설정의 Resolution and Presentation → Run In Background 를 켭니다. 다른 창을 조작하는 동안에도 빌드한 앱이 동기화를 계속하도록 하는 설정입니다.

3. 동기화할 캐릭터 만들기

다음 두 파일을 Assets에 저장합니다.

이동 코드는 Transform을 움직입니다. 위치를 다른 화면으로 보내는 역할은 다음 단계에서 추가할 NetworkTransform이 담당합니다.

var move = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
transform.position += move.normalized * (3f * Time.deltaTime);
if (Input.GetKeyDown(KeyCode.Space))
    GetComponent<NetworkEntity>().Rpc(nameof(AdventureRoomEmote.Wave), RpcTarget.All);

RPC는 지정한 처리를 다른 참가자의 화면에서도 실행하는 기능입니다. 여기서는 [NetworkRpc]가 붙은 Wave가 캐릭터를 0.3초 동안 크게 만듭니다.

[NetworkRpc]
public IEnumerator Wave(NetworkRpcInfo info)
{
    transform.localScale = Vector3.one * 1.5f;
    yield return new WaitForSeconds(0.3f);
    transform.localScale = Vector3.one;
}

캐릭터마다 조작 권한을 가진 플레이어를 정합니다. 내 입력으로 상대 캐릭터까지 움직이지 않도록 이동 스크립트를 Controlled Behaviours 에 등록합니다. 여기에 등록한 스크립트는 조작 권한을 가진 화면에서만 동작합니다.

  1. GameObject → 3D Object → Capsule 을 만들고 이름을 NetworkPlayer로 지정합니다.
  2. 다음 컴포넌트를 추가합니다.
컴포넌트설정
Network EntitySchema는 비워 둠. Controlled Behaviours에 이 오브젝트의 AdventureRoomPlayer 하나 추가
Network TransformPosition Axes는 All, Rotation Axes는 None
Adventure Room Player기본 설정 사용
Adventure Room Emote기본 설정 사용
  1. NetworkPlayer를 Project 창으로 드래그해 Prefab으로 만듭니다. Hierarchy에 남은 Capsule은 삭제합니다.

4. 연결용 오브젝트 만들기

  1. Project 창에서 Create → GS2 → Realtime → Prefab Catalog 를 선택해 PracticeCatalog를 만듭니다.
  2. Prefabs 에 항목을 하나 추가하고 Id 를 1, Prefab 을 NetworkPlayer로 설정합니다.
  3. AdventureRoom.cs를 Assets에 저장합니다.
  4. 빈 Room 오브젝트를 만들고 AdventureRoom을 추가합니다. NetworkWorld와 NetworkSession도 추가됩니다.
  5. Network World → Prefab Catalog 에 PracticeCatalog, Adventure Room → Login 에 Login 오브젝트의 AdventureLogin을 할당합니다.
  6. GameObject → 3D Object → Plane 으로 바닥을 만듭니다.
  7. GameObject → Camera 로 카메라를 만들고 이름은 Main Camera, Tag는 MainCamera로 설정합니다. 위치는 (0, 12, -10), 회전은 (50, 0, 0)으로 설정합니다.
  8. GameObject → Light → Directional Light 로 조명을 만들고 회전을 (50, -30, 0)으로 설정합니다.

연결 코드는 룸 이름으로 IP 주소, 포트, 암호화 키를 가져와 로그인한 플레이어의 액세스 토큰과 함께 전달합니다.

session.Connect(login.Session.AccessToken.Token,
    get.IpAddress, get.Port, get.EncryptionKey);
await UniTask.WaitUntil(
    () => session.State == NetworkSessionState.Ready || session.State == NetworkSessionState.Disconnected,
    cancellationToken: this.GetCancellationTokenOnDestroy());

연결이 완료되면 Ready가 호출되어 Prefab ID 1의 캐릭터를 생성합니다.

world.Instantiate(1,
    new Vector3(Random.Range(-3f, 3f), 1, Random.Range(-3f, 3f)),
    Quaternion.identity);

5. 두 화면에서 움직이기

  1. 씬을 저장하고 File → Build Profiles 에서 데스크톱 빌드를 만듭니다. 씬 목록에 RealtimePractice를 넣고 다른 씬의 체크를 해제해 이번에는 RealtimePractice만 활성화합니다.
  2. 빌드한 앱을 실행하고 로그인 화면의 저장 슬롯을 realtime-a로 지정해 로그인 을 누릅니다. Unity Editor에서도 재생하고 저장 슬롯을 realtime-b로 지정해 로그인합니다.
  3. 관리 콘솔에서 adventure-sync의 Room list → Create room 을 열고 이름을 practice로 지정해 생성합니다. 알림 대상 사용자 ID 목록은 비워 둡니다.
  4. 목록을 갱신합니다. practice에 IP 주소와 포트가 표시되면 앱과 Unity Editor 양쪽에서 룸 이름 practice의 이 룸에 연결 을 누릅니다.
  5. 양쪽에 캐릭터 두 명이 표시되면 한쪽 게임 화면을 클릭하고 WASD 키를 누릅니다. 양쪽 화면에서 같은 캐릭터가 움직입니다.
  6. 스페이스 키를 눌러 양쪽 화면에서 그 캐릭터가 잠깐 커지는지 확인합니다.

6. 조작하는 플레이어 바꾸기

  1. B 화면의 내 연결 ID 를 A의 조작 권한을 받을 상대 연결 ID 에 입력합니다.
  2. A가 소유한 오브젝트의 이 오브젝트의 조작 권한 넘기기 를 누릅니다. 오브젝트 번호를 기록합니다.
  3. A에서 WASD를 눌러도 그 캐릭터는 움직이지 않습니다. B에서는 원래 캐릭터와 넘겨받은 캐릭터가 모두 움직입니다.
  4. B의 입력란에 A의 연결 ID를 넣고 기록한 오브젝트 번호의 조작 권한을 A에게 돌려줍니다. 다시 각자 한 명씩 조작할 수 있게 됩니다.

entity.TransferOwnership(otherConnectionId)로 조작 권한을 넘깁니다. 소유자가 바뀌면 Controlled Behaviours의 이동 스크립트도 새 소유자의 화면에서 활성화됩니다.

7. 연결을 끊고 다시 연결하기

A에서 연결 끊기 를 누르면 B 화면에서 A의 캐릭터가 사라집니다. A를 같은 룸에 다시 연결하면 새 캐릭터가 나타나고 B의 캐릭터는 현재 위치에 표시됩니다.

확인이 끝나면 양쪽 화면에서 연결을 끊습니다. 관리 콘솔의 adventure-sync 룸 목록에서 실습용 practice를 삭제합니다.

서버에서 적 HP와 승패를 관리하는 구현은 GSL로 적을 움직이는 튜토리얼(새 탭)에서 규칙 정의부터 Unity 조작까지 확인할 수 있습니다.

튜토리얼 첫 페이지로