//tips
//通信システム内容確認
TCPのプログラミングで何が行われているかを確認する。
void StartListener(int port)
{
//ソケット生成
m_listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
//使用するポート番号割り当て
m_listener.Bind(new IPEndPoint(IPAddress.Any,port));
//待受開始
m_listener.Listen(1);
m_state = State.AcceptClient;
}
ソケットクラスの変数m_listenerにインスタンスを生成。これは待受専用なのでリスニングソケットと呼ばれる。これでいつ接続要求されても対応できるようになる。
インスタンス生成時に、ソケット(接続口のこと)の種類をSocketType.Stream、プロトコルにProtocolType.TCPを指定する。
次に、引数portで指定されたポート番号を割り当てている。Bind関数を使って、関連するエンドポイントを指定。エンドポイントは通常ネットワーク端末などを指すが、ここではネットワークアドレスを指定する。
Listen関数を使うことでリスニングソケットを待ち受け状態にする。
クライアントからの接続要求を受け付けるためにAccept関数を呼び出し、接続要求があるまで処理をブロッキングする。
void AcceptClient()
{
if(m_listener != null && m_listener.Poll(0, SelectMode.SelectRead))
{
m_socket = m_listener.Accept();
m_isConnected = true;
}
}
Accept関数を呼び出すと、クライアントと接続が完了するまで処理が継続するので、その間アプリの他の処理はできなくなる。
このままでは使いづらいため、Poll関数でクライアントからのデータ受信を監視して、受信した時だけAccept関数を呼び出すようにすることもできる。
これでサーバー側の待ち受け準備ができたのでクライアントからの接続も見ていく。
クライアント側でも通信ソケットを生成。
通信相手となる端末IPアドレスとポート番号を指定して接続処理を行う。相手が待ち受け状態になっていれば接続できる。
void ClientProcess()
{
m_socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
m_socket.NoDelay = true;
m_socket.SendBufferSize = 0;
m_socket.Connect(m_address, m_port);
}
サーバとの接続を行うためのソケット生成し、作成したソケットは小さなパケットをバッファリングしないようにSocket.NoDelayプロパティ を作動させ、m_socket.SendBufferSizeを0にしている。
Connect関数を使い、m_socketに接続先のサーバIPアドレスとポート番号を指定して接続要求を行う。
Connect関数もブロッキング関数なので、接続が完了するまで次の処理を行うことができない。
ここまでの流れでサーバとクライアントを接続できるようになったので、データの送受信も絡めて考えてみる。
//マルチプレイヤーゲームのセッティング
MLAPIを使用したマルチプレイのセッティングをgithubの下記からMLAPIをダウンロードして行おうとしたがエラー。
https://github.com/MidLevel/MLAPI
Githubの古いバージョンをダウンロードする場合はmasterボタンをクリックし、その中のtagを押すことで旧バージョンのマスターデータに切り替えることができ、そこからダウンロードできる。
それでも難しそうだったので一旦Photon Unity Networking 2へ切り替える。
下記を参考にし、設定していく。
https://connect.unity.com/p/pun2deshi-meruonraingemukai-fa-ru-men-sono1
まずはphotonへの登録から。
https://www.photonengine.com/
登録が終わったらUnity asset storeからPUN2をダウンロードし、アプリケーションナンバーを求められるので先ほどPUN2のサイトで新規アプリを作成した際に表示されたコードを貼り付ける。
バージョンと地域修正などをインスペクターで行い、シーン作成に移っていく。
自分のところで作成したら相手のところに同期されて出現するネットワークオブジェクトを作成していく。
Cubeを作成して、add componentでphoton viewをアタッチする。アタッチしたものをprefab化。ヒエラルキーのcubeは消去しておく。
空オブジェクトをヒエラルキーに追加し、スクリプトも新たに付け加える。
スクリプトの中身は下記。
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
// MonoBehaviourではなくMonoBehaviourPunCallbacksを継承して、Photonのコールバックを受け取れるようにする
public class SampleScene : MonoBehaviourPunCallbacks
{
private void Start() {
// PhotonServerSettingsに設定した内容を使ってマスターサーバーへ接続する
PhotonNetwork.ConnectUsingSettings();
}
// マスターサーバーへの接続が成功した時に呼ばれるコールバック
public override void OnConnectedToMaster() {
// "room"という名前のルームに参加する(ルームが無ければ作成してから参加する)
PhotonNetwork.JoinOrCreateRoom("room", new RoomOptions(), TypedLobby.Default);
}
// マッチングが成功した時に呼ばれるコールバック
public override void OnJoinedRoom() {
// マッチング後、ランダムな位置に自分自身のネットワークオブジェクトを生成する
var v = new Vector3(Random.Range(-3f, 3f), Random.Range(-3f, 3f));
PhotonNetwork.Instantiate("GamePlayer", v, Quaternion.identity);
}
}
この段階でplayボタンを押すと若干遅れてcubeが生成されるシーンを見ることができる。
Unity上では動いたので今度はビルドして確認してみる。
Build settingsからAdd open sceneで現在のシーンを追加、player settingsからはfull screenモードからwindowに変更する。
Build and runでデモを表示した状態で、unityのエディターでも再生すると、cubeオブジェクトが2つ生成される。これは異なるデバイスで参加した2人のプレイヤーを表示しているということである。