😺

Unity Multiplayer Networkingを使ってみる

2024/06/01に公開

UnityでオンラインマルチプレイといえばPhotonが有名ですが、Unity自体も同様のサービスを提供しています。
https://docs-multiplayer.unity3d.com/

どちらも無料で使うことができますが、PhotonFusionのFREE100CCUプランは1カスタマー1アプリまでの制限があります。また20CCUプランは開発のみにしか使えません。
https://www.photonengine.com/fusion/pricing

それに対してUnity Gaming ServiceのRelayは50CCUまで無料となっていますので、無料で利用する分にはPhotonFusionより有利です。
https://unity.com/solutions/gaming-services/pricing

そう思ってUnity Multiplayer Networkingを試してみたのですが、Photonに比べるとけっこう面倒なことが多いので、備忘録としてまとめておきます。

使用バージョン

  • Unity 2022.3.24f1
  • Lobby 1.1.2
  • Relay 1.0.5
  • Netcode for GameObjects 1.8.1

概要

Photonは1つにほぼまとまっていますが、Unity Multiplayer NetworkingではLobby/Relay/Netcodeに分かれています。これら3つを合わせたものがだいたいPhotonと同等になるかと思います。

分かれているせいでかなりわかりずらいですが、おそらく一般的には

  1. Lobbyでマッチング
  2. Relayを使ってゲーム同士をネットワーク接続
  3. Netcodeを使って同期プレイを実装

のような流れになるかと思われます。

それぞれの使い方については公式にサンプルやドキュメント、またネット上にも試している方がいるのでここでは書きません。

以下には自分が試していてハマったことを記述しておきます。

Lobby

  • アプリを終了してもロビーに残る
    • とりあえずDashboardのLobbyの設定で、Disconnect Removal Timeを最小(10s)に設定しておく
    • Application.wantToQuitなどでILobbyService.RemovePlayerAsyncを呼ぶと良い
    • OnDisableOnDestroyILobbyService.RemovePlayerAsyncを呼んでもダメ
      • Task.Resultでブロックすると固まるのでさらにダメ
  • LobbyEventCallbacksの設定が面倒
    • LobbyChangedでほぼすべて受け取ることがでるので、これだけで十分
    • LobbyChangedのコールバックの中でILobbyChanges.ApplyToLobbyを呼ぶと変更を反映できる
  • LobbyEventCallbacks.LobbyChangedPlayerJoinedを検出したタイミングで、UpdateLobbyAsyncでロビーデータを更新するとJoinしたプレイヤーに伝わらない
    • UpdateLobbyAsyncの前にTask.Delay(1000)を入れると伝わる
  • 基本的にプレイヤーはPlayerIdで扱われるが、一部のコールバック(PlayerLeftPlayerData.Changedなど)ではPlayerIndexが使用される
    • PlayerIndexは固定ではなく、誰かがLeaveしたりすると振り直される

Netcode

  • クライアントからネットワークオブジェクトを生成できない
  • クライアントがOwnerなのに動かせない
    • NetworkTransformOnIsServerAuthoritativeが常に真を返すせいです
    • NetworkTransformを継承したクラスを作成し、OnIsServerAuthoritativefalseを返すようにしたコンポーネントを使用します

Discussion