【Unity】マルチプレイゲーム制作入門!第7回~Steamworksを使って通信しよう~

講座トップに戻る

はじめに

前回はSteamworksを使うための環境構築を行いました。

今回はSteamworksのロビー機能を使って、インターネット越しに通信をしていきたいと思います。

今回の最終形はこんな感じになります!

タイトル画面にLobbyIDを入力する欄があり指定したIDの部屋に入室できるようなりました。

動画では分かりにくいですが、実際に複数のPCを使って通信しています。

Steamworksでロビー実装

Steamworksにはロビー機能があります。

Steamマッチメイキングとロビー (Steamworks ドキュメント)

その機能を使ってホストがロビーを作り、クライアントがロビーに入出する形で通信を行います。

SteamLobbyというスクリプトを作成しましょう。

コードがとても長いため以下のGitHubページからコードをコピーしてきてください。

https://github.com/nopopo190/NetworkTutorial/blob/main/Assets/Scripts/Steam/SteamLobby.cs

それではSteamworksのロビー作成とロビー入室方法について解説していきます。

Lobbyの作成

まずはロビーの作成方法から見ていきましょう。

ロビー作成の手順は以下のようになります。

  • ロビー作成時のコールバックの作成
  • ロビーの作成とコールバックの設定

ロビー作成コールバック作成

ロビーが作成されたときに呼び出す関数を作成し、コールバックに登録する必要があります。

まずCallResult<LobbyCreated_t>型の変数を定義します。

private CallResult<LobbyCreated_t> m_crLobbyCreated;

そしてコールバックに登録する関数を作成します。


//ロビー作成コールバック用関数
private void OnCreateLobby(LobbyCreated_t pCallback, bool bIOFailure)
{
    //ロビー作成成功していなかった場合
    if (pCallback.m_eResult != EResult.k_EResultOK || bIOFailure)
    {
        return;
    }

    //ホストのアドレス(SteamID)を登録
    SteamMatchmaking.SetLobbyData(
        new CSteamID(pCallback.m_ulSteamIDLobby),
        s_HostAddressKey,
        SteamUser.GetSteamID().ToString());

    //ロビーID保存(画面にロビーIDを表示させる際に使用するので変数に入れておく)
    LobbyID = pCallback.m_ulSteamIDLobby;

    //サーバー開始コールバック
    NetworkManager.Singleton.ConnectionApprovalCallback = ApprovalCheck;
    //ホスト開始
    NetworkManager.Singleton.StartHost();
    //シーンを切り替え
    NetworkManager.Singleton.SceneManager.LoadScene("Game", LoadSceneMode.Single);
}

OnCreateLobby関数はロビーが作成完了した際に呼び出されるので、Title.csでやっていたStartHost関数の呼び出しや、シーンの切り替えなどもしています。

新しく行っている処理は以下の部分になります。

//ホストのアドレス(SteamID)を登録
SteamMatchmaking.SetLobbyData(
    new CSteamID(pCallback.m_ulSteamIDLobby),//ロビーID
    s_HostAddressKey,//設定するキー
    SteamUser.GetSteamID().ToString());//設定する値

SteamMatchmaking.SetLobbyData関数を使うと任意のKeyとValueを登録することができます。

この値はロビーに入っているメンバーは誰でも取得することができます。

Steamworksを使ったクライアントの接続にはホストのSteamIDが必要になるので、ここで登録しています。

あとはStart関数で最初に作ったコールバックに今作った関数を登録しましょう。

//コールバックの作成と関数の登録
m_crLobbyCreated = CallResult<LobbyCreated_t>.Create(OnCreateLobby);

これでロビー作成時のコールバックができました。

ロビーの作成とコールバックの設定

ロビーの作成はSteamMatchmaking.CreateLobby関数を使います。

SteamAPICall_t hCreateLobby = SteamMatchmaking.CreateLobby(
ELobbyType.k_ELobbyTypePublic,//ロビーの公開・非公開
4);//ロビーの最大人数

戻り値(hCreateLobby )を先ほど作成したコールバック用変数のSet関数で登録します。

m_crLobbyCreated.Set(hCreateLobby);

これでロビーが作成されたときに先ほどのコールバックが呼び出されます。

以上でロビーの作成とコールバックの設定が完了しました。

Lobbyに入室

次にロビーの入室方法を見ていきましょう。

ロビー入室の手順は以下のようになります。

  • ロビー入室時のコールバック作成
  • ロビーへの入室

ロビー入室時のコールバック作成

作成時と同じく、ロビー入室時に呼び出す関数を作成し、コールバックに登録する必要があります。

まずCallback<LobbyEnter_t>型の変数を定義します。

//ロビー入室コールバック
private Callback<LobbyEnter_t> m_lobbyEnter;

そしてコールバックに登録する関数を作成します。

// ロビー入室コールバック用関数
private void OnLobbyEntered(LobbyEnter_t callback)
{
    //入室失敗時
    if ((EChatRoomEnterResponse)callback.m_EChatRoomEnterResponse != EChatRoomEnterResponse.k_EChatRoomEnterResponseSuccess)
    {
        return;
    }

    //ホストのSteamIDを取得
    string hostAddress = SteamMatchmaking.GetLobbyData(
        new CSteamID(callback.m_ulSteamIDLobby),
        s_HostAddressKey);

    //ホスト(CreateLobbyした本人)もここを通るのでクライアント接続しないようにリターン
    if (hostAddress == SteamUser.GetSteamID().ToString()) { return; }

    //ロビーID保存
    LobbyID = callback.m_ulSteamIDLobby;

    //Netcodeでクライアント接続
    var stp = (SteamNetworkingSocketsTransport)NetworkManager.
Singleton.NetworkConfig.NetworkTransport;
    stp.ConnectToSteamID = ulong.Parse(hostAddress);
    //ホストに接続
    bool result = NetworkManager.Singleton.StartClient();

    //切断時
    NetworkManager.Singleton.OnClientDisconnectCallback += OnClientDisconnect;
}

先ほどロビー作成の際にホストのSteamIDをロビーデータに登録していました。

そのSteamIDを取得しているのが以下の部分です。

GetLobbyDataに設定時に登録したKeyを渡すと、設定した値が取得できます。

//ホストのSteamIDを取得
string hostAddress = SteamMatchmaking.GetLobbyData(
    new CSteamID(callback.m_ulSteamIDLobby),//ロビーID
    s_HostAddressKey);//設定したキー

Netcodeでクライアントが接続する部分に関しても少し異なってきます。

以前はStartClient関数を呼び出すだけでしたが、Steamworkで接続する場合はNetworkTransportのConnectToSteamIDにホストのSteamIDを設定する必要があります。

//NetworkTransportにホストのSteamIDを設定
var stp = (SteamNetworkingSocketsTransport)NetworkManager.
Singleton.NetworkConfig.NetworkTransport;
stp.ConnectToSteamID = ulong.Parse(hostAddress);
//ホストに接続
bool result = NetworkManager.Singleton.StartClient();

あとはStart関数で最初に作ったコールバックに今作った関数を登録しましょう。

m_lobbyEnter = Callback<LobbyEnter_t>.Create(OnLobbyEntered);

これでロビー入室時のコールバックができました。

ロビーへの入室

ロビーの入室はSteamMatchmaking.JoinLobby関数を使います。

引数に入室するLobbyIDを渡す必要があります。

SteamMatchmaking.JoinLobby(lobbyID);

これでロビーの入室が完了しました。

気づいた方もいるかもしれませんが、ロビー作成時と入室時のコールバックの変数型はよく見る違います。

作成時がCallResultで入室時がCallbackになっています。

正直に言うと私も説明できるほど明確に違いが分かっているわけではありません。

違いについてはこちらの公式リファレンスに書いてありますので確認してみてください。

Steamworks API概要 (Steamworks ドキュメント)

またSteamworksには他にも様々な機能が備わっているので、気になった方は公式リファレンスを見てください。

今回はホストにロビーIDを聞く形を想定していますが、ロビー検索画面などを作成することもできます。

Features (Steamworks Documentation)

タイトル画面の整えよう

TitleシーンのSteamMangaerオブジェクトに先ほど作成したSteamLobbyをアタッチしましょう。

次にロビーIDを入力するInputFieldを追加します。

そしてTitle.csを以下のように変更します。

using Steamworks;
using TMPro;
using UnityEngine;

public class Title : MonoBehaviour
{
    [SerializeField]
    TMP_InputField m_joinLobbyID;

    public void StartHost()
    {
        //ロビー作成
        SteamLobby.Instance.CreateLobby();
    }

    public void StartClient()
    {
        //ロビー入室
        SteamLobby.Instance.JoinLobby((CSteamID)ulong.Parse(m_joinLobbyID.text));
    }
}

変更できたら先ほど作成したInputFieldを登録しておきます。

Steamworksを使った接続をする準備はこれで完了です!

画面にLobbyIDを表示しよう

あとは作成したロビーのIDさえ分かれば接続できるはずです。

ロビーIDを表示するためにLobbyID.csを作成します。

using TMPro;
using UnityEngine;

public class LobbyID : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI m_lobbyIdText;

    private void Start()
    {
        //ロビー作成or入室時に記憶しておいたLobbyIDを設定
        m_lobbyIdText.text = SteamLobby.Instance.LobbyID.ToString();
    }
}

そしてGameシーンのCanvas以下にLobbyIDというオブジェクトを作成しアタッチします。

表示するTextオブジェクトも作成し、スクリプトにアタッチしておきます。

動作確認してみよう

ここまで出来たら動作確認してみましょう!

PCを複数台用意する必要があるので、1台しか持っていない人は誰かに協力してもらいましょう。

クライアント側はLobbyIDを入力してからClientボタンを押してください。

しっかり別々のPCでもネットワーク越しに接続できるようになりました!

動画ではIDを手で打つのが面倒だったのでコピーボタンを作っています。

GUIUtility.systemCopyBufferに値を入れるとクリップボードにコピーできます。

GUIUtility.systemCopyBuffer = m_lobbyIdText.text;

まとめ

今回でSteamworksを使ってインターネット越しの通信ができるようになりました。

これでこの講座は終了です。

最後まで読んでいただきありがとうございました!

👇あなたにお勧めの書籍

コメント