こんにちは、ちゃらいプログラマです。
前回の続きでLobby/Relayへの接続周りを説明していきます。
※前回の記事はこちら
Unity Lobby/Relay入門 (#1) - アヒルのある日
処理の流れ
ホスト、クライアントで若干異なります。
MultiGameManagerクラスを作成して処理を作成します。
接続
// 認証済判定
private bool m_isAuthentication = false;
// 認証ID
private string m_authenticationId = string.Empty;
// 接続
public async UniTask ConnectAsync()
{
if(!m_isAuthentication)
{
// "ユーザ識別ID"はアプリ毎に適切なIDを設定してください
var option = new InitializationOptions();
option.SetProfile( "ユーザ識別ID" );
await UnityServices.InitializeAsync( option );
await AuthenticationService.Instance.SignInAnonymouslyAsync();
// 上記で渡す"ユーザ識別ID"がゲーム起動時から変わらないのであれば
// 本処理は一度のみで問題ありません
m_isAuthentication = true;
// 参照時の処理負荷が激しいのでキャッシュしておきます
m_authenticationId = AuthenticationService.Instance.PlayerId;
// コールバック登録
Unity.Netcode.NetworkManager.Singleton.OnServerStarted += OnServerStarted;
Unity.Netcode.NetworkManager.Singleton.OnServerStopped+= OnServerStopped;
Unity.Netcode.NetworkManager.Singleton.OnClientStarted+= OnClientStarted;
Unity.Netcode.NetworkManager.Singleton.OnClientStopped+= OnClientStopped;
Unity.Netcode.NetworkManager.Singleton.OnTransportFailure+= OnTransportFailure;
}
}
// ホスト起動コールバック
private void OnServerStarted()
{
// ホストモードでゲーム開始した際に呼び出されます
}
// ホスト停止コールバック
private void OnServerStopped(bool isStop)
{
// ホストモードで接続が解除された際に呼び出されます
}
// クライアント起動コールバック
private void OnClientStarted()
{
// クライアントモードでゲーム開始した際に呼び出されます
// ホストモードでゲーム開始した際にも呼び出されます
}
// クライアント停止コールバック
private void OnClientStopped( bool isStop )
{
// クライアントモードで接続が解除された際に呼び出されます
}
// 切断コールバック
private void OnTransportFailure()
{
// ネットワークが切断された際に呼び出されます
}
ホスト側
- 接続
- Relayネットワークを生成
private async UniTask<string> CreateRelayAsync( int connectionNumMax )
{
// 接続最大数を渡してネットワークを生成します
var allocation = await RelayService.Instance.CreateAllocationAsync( connectionNumMax );
// 接続用のIDを取得しておきます
string roomId = await RelayService.Instance.GetJoinCodeAsync( allocation.AllocationId );
// 接続フォーマットを設定します
var serverData = new RelayServerData( allocation, "dtls" );
var transport = Unity.Netcode.NetworkManager.Singleton.GetComponent<UnityTransport>();
transport.SetRelayServerData( serverData );
return roomId;
}
- Lobbyを生成
// 接続ロビー情報
private Lobby m_lobby = null;
// ロビー生成
private async UniTask<Lobby> CreateLobbyAsync( string lobbyName, string roomId, int connectionNumMax )
{
// 接続用のIDを生成時のオプションに設定します
// アプリ毎に設定数は異なります(最小設定だと以下のようになります)
var options = new CreateLobbyOptions();
options.Data = new()
{
// フォーマットは
// "任意の文字列", "DataObject型"
{
"RoomID",
new DataObject(
visibility: DataObject.VisibilityOptions.Public,
value: roomId
},
};
// ロビー生成
m_lobby = await LobbyService.Instance.CreateLobbyAsync( lobbyName, connectionNumMax, options );
}
- ホストモードでゲーム開始
Unity.Netcode.NetworkManager.Singleton.StartHost();
- 一定時間毎にLobbyへHeartBeat送信
// ロビー接続ポーリングコルーチン
private Coroutine m_lobbyCoroutine = null;
// ロビー接続継続開始
private void StartLobbyHeartbeat()
{
StopLobbyHeartbeat();
m_lobbyCoroutine = StartCoroutine( LobbyHeartbeatCoroutine() );
}
// ロビー接続継続停止
private void StopLobbyHeartbeat()
{
if (m_lobbyCoroutine != null)
{
StopCoroutine( m_lobbyCoroutine );
m_lobbyCoroutine = null;
}
}
// ロビー接続ポーリング
private IEnumerator LobbyHeartbeatCoroutine()
{
var delay = new WaitForSeconds( 15 );
while (true)
{
LobbyService.Instance.SendHeartbeatPingAsync( m_lobby.Id );
yield return delay;
}
}
- 切断(任意のタイミングで)
クライアント側
- 接続
- Lobbyリスト取得と参加
private async UniTask<string> JoinLobbyAsync()
{
// 空いているロビーへ接続します
var queryLobbyOptions = new QueryLobbiesOptions();
queryLobbyOptions.Count = 20; // 検索数
queryLobbyOptions.Order= new()
{
new QueryOrder(
asc: false,
field: QueryOrder.FieldOptions.Created
),
};
var lobbies = await Lobbies.Instance.QueryLobbiesAsync( queryLobbyOptions );
string lobbyId = string.Empty;
string roomId = string.Empty;
foreach (var result in lobbies.Results)
{
lobbyId = result.Id;
// CreateLobbyAsync()にてオプションに設定した
// "RoomID"を参照して接続用IDを取得します
roomId = result.Data["RoomID"].Value;
break;
}
// ロビー参加
if(lobbyId != "")
{
m_lobby = await LobbyService.Instance.JoinLobbyByIdAsync( lobbyId );
}
return roomId;
}
- Relayネットワークへ接続
private async UniTask JoinRelayAsync( string roomId )
{
// 接続用のIDを元にネットワークへ接続します
var allocation = await RelayService.Instance.JoinAllocationAsync( roomId );
// 接続フォーマットを設定します
var serverData = new RelayServerData( allocation, "dtls" );
var transport = Unity.Netcode.NetworkManager.Singleton.GetComponent<UnityTransport>();
transport.SetRelayServerData( serverData );
}
- クライアントモードでゲーム開始
Unity.Netcode.NetworkManager.Singleton.StartClient();
- 切断(任意のタイミングで)
切断
// 切断
public async UniTask DisconnectAsync()
{
if(m_isAuthentication)
{
// ロビー接続継続停止
StopLobbyHeartbeat();
// ロビーから抜ける
await LobbyService.Instance.RemovePlayerAsync( m_lobby.Id, m_authenticationId );
m_lobby = null;
// Relay接続解除
Unity.Netcode.NetworkManager.Singleton?.Shutdown();
}
}
駆け足で説明しましたが、上記でホスト端末へ接続できるようになります。
次回はRPC周りの説明ができればと… また次回。