Help us understand the problem. What is going on with this article?

UnityのUNETにおけるローカルLAN対戦の為のNetworkDiscovery

More than 1 year has passed since last update.

概要

細かい挙動までは書きませんが、UNETを調べるとLAN対戦をするとき

  • サーバIP決め打ち+NetworkManagerのみ使用
  • NetworkDiscoveryでサーバを探してNetworkManagerを使う
  • UNET Matching でサーバやクライアントを探してNetworkManagerを使う

の3パターンがあります。今回は真ん中の事を書きます。

あと、マジな話をするとNetworkManagerもNetworkDiscoveryも殆どのケースで継承したカスタム版を作ります。Unity標準のままで使う事は無いです。そうしないと管理できない事多過ぎです…

NetworkDiscoveryの中身

NetworkDiscoveryのサーバ側は、自分の所在(IPアドレス)をLAN内にブロードキャストパケットを流すことで宣伝して回る
NetworkDiscoveryのクライアント側は、NetworkDiscoveryのサーバが流しているブロードキャストパケットを受け取った時に専用の関数を呼ぶ

という機能だけを持っている、と覚えておきましょう。
それ以外の実際のサーバ立ち上げや、クライアント接続などは全てNetworkManager側でやります。

NetworkDiscoveryのサーバ側でプログラマが書くべきこと

NetworkManager側のStartHost()を最初に呼んでおきます。(純粋なサーバークライアントモデルの場合はStartServer()です)
その後にNetworkDiscovery内で
Initialize()して
StartAsServer()を呼びます。そうするとNetworkDiscoveryは自動に定期的に(デフォルトで1秒ごとに)ブロードキャストパケットを流します。

定期実行の停止

ゲームを始めます。対戦相手を締め切りました。ゲーム終わるまで追加のプレイヤーは受け付けないようにしたいです。みたいな場合は
StopBroadcast()してあげましょう。そして再びクライアント側を受け付けるときはStartBroadcast()を呼びます。

NetworkDiscoveryのクライアント側でプログラマが書くべきこと

サーバ側と異なり、NetworkManagerのStartClient(NetworkManager.singleton.StartClient(); )は いきなり呼ばないようにします
なぜなら、この時点ではサーバのIPアドレスが分かっていないからです。

NetworkDiscovery内で
Initialize()して
StartAsClient()を呼びます。
そうすると、このクライアント側はNetworkDiscoveryのサーバが流しているブロードキャストパケットを受け取れるようになります。
受け取り先の関数は

public override void OnReceivedBroadcast(string fromAddress, string data)

です。

上に挙げた関数の中で、引数として受け取ったfromAdress(サーバのローカルIPアドレス)を 接続先であるNetworkManagerのnetworkAdress(NetworkManagerのクライアントが接続する先のサーバアドレス)にセットしてから 、NetworkManager.singleton.StartClient(); を呼びます。

よろしいでしょうか。
以下、NetworkDiscoveryの継承先で書くサンプルコードです。自動でサーバに再接続もしてくれます。
(CustomNetworkDiscovery : NetworkDiscovery)

        /// <summary>
        /// NetworkDiscoveryのクライアント側がサーバの信号を受信したときに呼ばれる
        /// この関数は 本クラス内のどこかでStartAsClient()を呼ばないと機能しないし、サーバ側で呼ばれることは無い 
        /// 初期設定だと、クライアント上で約1秒間隔でこの関数が呼ばれる
        /// </summary>
        /// <param name="fromAddress">NetworkDiscoveryで見つけたサーバ側のIPアドレス</param>
        /// <param name="data"></param>
        public override void OnReceivedBroadcast(string fromAddress, string data)
        {
            //NetworkManagerのnetworkAddress(つまり、サーバのアドレス)に見つけたアドレスを入れる
            NetworkManager.singleton.networkAddress = fromAddress;
            //既にこのクライアントのNetworkManagerがサーバに接続済みなら何もしない。しかしクライアント側が切断して再接続の時はうまいことreturnせずにスルーして再接続する
            if (NetworkManager.singleton.IsClientConnected()==true)
            {
                return;
            }

            Debug.LogFormat("OnReceivedBroadcast; fromAddress: {0}, data: {1}", fromAddress, data);
            //NetworkManagerのクライアントが繋げる先のサーバアドレスを上で指定しているので、NetworkManagerのクライアントを開始できる
            NetworkManager.singleton.StartClient();
        }

余談、勝手にサーバになるやつ

最初に起動した人がサーバになる、という仕組みを作りたくなったら、
最初にNetworkDiscoveryのクライアントとして起動して、数秒待ってもサーバが見つからなければサーバとして振る舞う、って書くと良いです。
(この時にNetworkTransportのShutdownとか書いたほうが良いと思うよ!)

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away