실시간 편: 두 플레이어 동기화하기
두 게임 화면을 같은 룸에 연결합니다. WASD 키로 캐릭터를 움직이고 스페이스 키를 누르면 양쪽 화면에서 같은 캐릭터가 잠깐 커집니다.
기본편에서 준비한 GS2 학습용 프로젝트와 Unity 프로젝트를 사용합니다. 이 페이지에서는 새 RealtimePractice 씬을 만들고 SDK로 연결합니다.
1. Realtime 네임스페이스 만들기
관리 콘솔에서 학습용 프로젝트의 Tokyo 리전을 엽니다.
- Realtime → Namespace list → Create namespace 를 엽니다.
- 다음 값을 입력하고 생성합니다.
| 항목 | 값 |
|---|---|
| 이름 | adventure-sync |
| 서버 종류 | 오브젝트 동기화(sync) |
| 서버 사양 | realtime1.nano |
2. 로그인할 씬 만들기
- Unity의 File → New Scene 에서 빈 씬을 만들고
RealtimePractice로 저장합니다. - AdventureLogin.cs를
Assets에 저장합니다. 같은 파일이 이미 있다면 기존 파일을 사용합니다. - 빈
Login오브젝트를 만들고AdventureLogin을 추가합니다. - 관리 콘솔의 Deploy → Default → Output list 에서
ApplicationClientId와ApplicationClientSecret을 가져와 Client Id / Client Secret 에 입력합니다. - Account Namespace 는 Studio에서 계정을 만들었다면
Account, SDK 코스라면adventure-account로 설정합니다. Account Slot 은realtime-a로 설정합니다. - Edit → Project Settings → Player → Other Settings → Active Input Handling 을 Both 로 설정합니다. 재시작을 요청하면 Unity를 재시작합니다.
- 같은 Player 설정의 Resolution and Presentation → Run In Background 를 켭니다. 다른 창을 조작하는 동안에도 빌드한 앱이 동기화를 계속하도록 하는 설정입니다.
3. 동기화할 캐릭터 만들기
다음 두 파일을 Assets에 저장합니다.
- AdventureRoomPlayer.cs: 이동과 스페이스 키 입력.
- AdventureRoomEmote.cs: 모든 화면에서 실행할 동작.
이동 코드는 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 에 등록합니다. 여기에 등록한 스크립트는 조작 권한을 가진 화면에서만 동작합니다.
- GameObject → 3D Object → Capsule 을 만들고 이름을
NetworkPlayer로 지정합니다. - 다음 컴포넌트를 추가합니다.
| 컴포넌트 | 설정 |
|---|---|
| Network Entity | Schema는 비워 둠. Controlled Behaviours에 이 오브젝트의 AdventureRoomPlayer 하나 추가 |
| Network Transform | Position Axes는 All, Rotation Axes는 None |
| Adventure Room Player | 기본 설정 사용 |
| Adventure Room Emote | 기본 설정 사용 |
NetworkPlayer를 Project 창으로 드래그해 Prefab으로 만듭니다. Hierarchy에 남은 Capsule은 삭제합니다.
4. 연결용 오브젝트 만들기
- Project 창에서 Create → GS2 → Realtime → Prefab Catalog 를 선택해
PracticeCatalog를 만듭니다. - Prefabs 에 항목을 하나 추가하고 Id 를
1, Prefab 을NetworkPlayer로 설정합니다. - AdventureRoom.cs를
Assets에 저장합니다. - 빈
Room오브젝트를 만들고AdventureRoom을 추가합니다.NetworkWorld와NetworkSession도 추가됩니다. - Network World → Prefab Catalog 에
PracticeCatalog, Adventure Room → Login 에Login오브젝트의AdventureLogin을 할당합니다. - GameObject → 3D Object → Plane 으로 바닥을 만듭니다.
- GameObject → Camera 로 카메라를 만들고 이름은
Main Camera, Tag는MainCamera로 설정합니다. 위치는(0, 12, -10), 회전은(50, 0, 0)으로 설정합니다. - 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. 두 화면에서 움직이기
- 씬을 저장하고 File → Build Profiles 에서 데스크톱 빌드를 만듭니다. 씬 목록에
RealtimePractice를 넣고 다른 씬의 체크를 해제해 이번에는RealtimePractice만 활성화합니다. - 빌드한 앱을 실행하고 로그인 화면의 저장 슬롯을
realtime-a로 지정해 로그인 을 누릅니다. Unity Editor에서도 재생하고 저장 슬롯을realtime-b로 지정해 로그인합니다. - 관리 콘솔에서
adventure-sync의 Room list → Create room 을 열고 이름을practice로 지정해 생성합니다. 알림 대상 사용자 ID 목록은 비워 둡니다. - 목록을 갱신합니다.
practice에 IP 주소와 포트가 표시되면 앱과 Unity Editor 양쪽에서 룸 이름practice의 이 룸에 연결 을 누릅니다. - 양쪽에 캐릭터 두 명이 표시되면 한쪽 게임 화면을 클릭하고 WASD 키를 누릅니다. 양쪽 화면에서 같은 캐릭터가 움직입니다.
- 스페이스 키를 눌러 양쪽 화면에서 그 캐릭터가 잠깐 커지는지 확인합니다.
6. 조작하는 플레이어 바꾸기
- B 화면의 내 연결 ID 를 A의 조작 권한을 받을 상대 연결 ID 에 입력합니다.
- A가 소유한 오브젝트의 이 오브젝트의 조작 권한 넘기기 를 누릅니다. 오브젝트 번호를 기록합니다.
- A에서 WASD를 눌러도 그 캐릭터는 움직이지 않습니다. B에서는 원래 캐릭터와 넘겨받은 캐릭터가 모두 움직입니다.
- B의 입력란에 A의 연결 ID를 넣고 기록한 오브젝트 번호의 조작 권한을 A에게 돌려줍니다. 다시 각자 한 명씩 조작할 수 있게 됩니다.
entity.TransferOwnership(otherConnectionId)로 조작 권한을 넘깁니다. 소유자가 바뀌면 Controlled Behaviours의 이동 스크립트도 새 소유자의 화면에서 활성화됩니다.
7. 연결을 끊고 다시 연결하기
A에서 연결 끊기 를 누르면 B 화면에서 A의 캐릭터가 사라집니다. A를 같은 룸에 다시 연결하면 새 캐릭터가 나타나고 B의 캐릭터는 현재 위치에 표시됩니다.
확인이 끝나면 양쪽 화면에서 연결을 끊습니다. 관리 콘솔의 adventure-sync 룸 목록에서 실습용 practice를 삭제합니다.
서버에서 적 HP와 승패를 관리하는 구현은 GSL로 적을 움직이는 튜토리얼(새 탭)에서 규칙 정의부터 Unity 조작까지 확인할 수 있습니다.