이번 숫자야구 게임은 멀티플레이 게임이므로 서버와 클라이언트 스크립트를 나눠서 작성해야 한다.
멀티플레이를 만드는 방식은 여러 가지가 있는데 그 중 릴레이 서버를 이용해 이번 게임을 만들기로 했다.
1. Relay Server 작동 방식
1단계. 할당 요청
호스트 플레이어가 CreateAllocationAsync() 를 호출하면, 유니티의 릴레이 서비스는 게임을 위한 '전용 중계 서버(Allocation)'를 할당하고, 이 서버를 식별하는 고유한 ID 인 AllocationId 를 반환합니다.
이 AllocationId 는 릴레이 서버의 '주소'와 같은 역할을 합니다.
Allocation
: RelayService 에서 할당 받은 릴레이 서버 인스턴스를 나타내는 객체.
AllocationId, RelayServer, ConnectionData 가 포함되어 있다.
2단계. 초대 코드 생성
게스트 플레이어가 이 서버에 접속하려면 AllocationId 가 필요하지만, 이 ID 는 길고 복잡해서 사용자가 직접 입력하기 어렵다.
그래서 유니티는 GetJoinCodeAsync() 메서드를 제공합니다. 이 메서드는 AllocationId 를 짧고 간편한 JoinCode 로 변환해 줍니다.
3단계. 게스트 접속
게스트 플레이어는 이 JoinCode 를 사용해 서버에 접속 요청을 보냅니다. 유니티 릴레이 서비스는 JoinCode를 다시 AllocationId 로 변환하여 올바른 릴레이 서버로 게스트를 연결해 줍니다.
using UnityEngine;
using System.Threading.Tasks;
using Unity.Netcode;
using Unity.Services.Authentication;
using Unity.Services.Core;
using Unity.Services.Relay;
using Unity.Services.Relay.Models;
using Unity.Netcode.Transports.UTP;
using Unity.Networking.Transport.Relay;
namespace VR_MNB.InGame.Server
{
public class InGameServerManager : NetworkBehaviour
{
private string joinCode;
/// <summary>
/// 호스트로 시작하고 조인 코드를 생성하는 함수
/// </summary>
public async Task<string> StartHostWithRelay()
{
// 1. Unity Services 초기화 (및 익명 인증)
await UnityServices.InitializeAsync();
// TODO: 추후 로그인 되어 있지 않으면 오류메시지 보내는 로직으로 변경 필요
if (AuthenticationService.Instance.IsSignedIn == false)
{
await AuthenticationService.Instance.SignInAnonymouslyAsync();
}
// 2. Relay 서버 할당 생성 및 Join Code 얻기
int maxConnections = 2;
Allocation allocation = await RelayService.Instance.CreateAllocationAsync(maxConnections);
joinCode = await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId);
Debug.Log("Relay Join Code: " + joinCode);
// 3. NetworkManager 에 Relay 서버 정보 설정
var relayServerData = new RelayServerData(
host: allocation.RelayServer.IpV4,
port: (ushort)allocation.RelayServer.Port,
allocationId: allocation.AllocationIdBytes,
connectionData: allocation.ConnectionData,
hostConnectionData: new byte[0], // 호스트는 hostConnectionData가 필요 없으므로 빈 배열 사용
key: allocation.Key,
isSecure: true,
isWebSocket: false
);
UnityTransport transport = NetworkManager.Singleton.GetComponent<UnityTransport>();
transport.SetRelayServerData(relayServerData);
// 4. host 시작
NetworkManager.Singleton.StartHost();
return joinCode;
}
/// <summary>
/// 클라이언트로 게임에 참여하는 함수
/// </summary>
public async void StartClientWithRelay(string joinCode)
{
// 1. Unity Services 초기화 (및 익명 인증)
await UnityServices.InitializeAsync();
// TODO : 익명이 아닌 유저 정보 받아와야 함
if (AuthenticationService.Instance.IsSignedIn == false)
{
await AuthenticationService.Instance.SignInAnonymouslyAsync();
}
// 2. Join Code 로 Relay 서버 할당에 참여
JoinAllocation joinAllocation = await RelayService.Instance.JoinAllocationAsync(joinCode);
// 3. NetworkManager 에 Relay 서버 정보 설정
var relayServerData = new RelayServerData(
host: joinAllocation.RelayServer.IpV4,
port: (ushort)joinAllocation.RelayServer.Port,
allocationId: joinAllocation.AllocationIdBytes,
connectionData: joinAllocation.ConnectionData,
hostConnectionData: joinAllocation.HostConnectionData,
key: joinAllocation.Key,
isSecure: true,
isWebSocket: false
);
UnityTransport transport = NetworkManager.Singleton.GetComponent<UnityTransport>();
transport.SetRelayServerData(relayServerData);
// 4. 클라이언트 시작
NetworkManager.StartClient();
}
}
}
위의 방식을 적용해서 위와 같이 InGameServerManager 를 작성할 수 있습니다.
'Project > Unity Bootcamp 13th' 카테고리의 다른 글
| UCA : Game Developer 시험 대비 유니티 핵심 내용 정리 (0) | 2025.09.08 |
|---|---|
| [VR 숫자야구 게임] | #1 Unity6 Assembly Define (1) | 2025.08.18 |
| [오버워치 디펜스 모바일] | #3 유니티 State Machine Behaviours (0) | 2025.07.01 |
| [오버워치 디펜스 모바일] | #2 오브젝트 풀 (4) | 2025.06.30 |
| [오버워치 디펜스 모바일] | #1 게임 기획의 종류 (1) | 2025.06.23 |