【Unity】シンプルなネットワーク対応サンプル

2024年5月14日


UnityのNetCodeを使った2Dプロジェクトの作成は、マルチプレイヤーゲーム開発において効果的です。簡単にネットワーク同期が実現でき、リアルタイムのインタラクションが可能になります。初心者にも扱いやすく、カスタマイズも容易です。

NetCodeで2Dネットワークアプリのシンプルなサンプルを作る

NetCodeはUnityで利用できるネットワークライブラリの一つで、マルチプレイヤーゲームの開発を容易にするために設計されています。ここでは、Unityで2Dマルチプレイヤーゲームのサンプルプロジェクトを作成する手順を説明します。

新しいプロジェクトを作成する

Unity Hubから2Dのプロジェクト(MultiPlayerSample)を作成します

パッケージマネージャーでGameObjectsのNetcodeをインストールする

  • エディタのメニューから、Window>PackageManagerを選択します。
  • PackageManagerから、追加(+·)を選択します。> Add package by name…でパッケージを追加します
  • パッケージ名フィールドにcom.unity.netcode.gameobjectsと入力(またはコピー&ペースト)し、[Add]を選択します。

インストール後

基本的なコンポーネントを作成する

マルチプレイヤーゲームの基本的な構成要素を作成します。

ネットワークマネージャーの作成とトランスポートの選択

ネットワークマネージャーを追加し、プロジェクトにUnityトランスポートを追加します。NetworkManagerは、プロジェクトのネットコード関連の設定をすべて設定するコンポーネントです。Unity Transportは、Netcodeがサーバーとクライアント間の通信に使用するトランスポート層です。詳細については、こちらをご覧ください。

  • [Hierarchy]ウィンドウを右クリックします。
  • [Create Empty] を選択し、空のゲームオブジェクトを作成します
  • 名前をNetworkManagerに変更します
  • [Inspector] [ Add Component](コンポーネントの追加) をクリックし、NetworkManagerコンポーネントを選択します。

検索窓で、一部入力がわかりやすいです

[NetworkManagerゲームオブジェクト]の[NetworkManagerコンポーネント]で、NetworkTransportフィールドを見つけます。
「Select transport…」(トランスポートを選択)をクリックします。
UnityTransportを選択します。

シーンを保存します。

接続されたプレーヤーごとにオブジェクトを生成する

ここではプレイヤーオブジェクトを追加し、接続しているプレイヤーごとに生成(スポーン)させます。

[Hierarchyウィンドウ]で右クリックし、2D Object > Sprite > Circleを作成します。
名前をPlayerに変更します。
Playerを選択した状態で、Inspector Netcode > NetworkObjectコンポーネントを追加します。

ネットワーク転送用のコードを作成し、アタッチします

Playerを選択した状態でClientNetworkTransformスクリプトをPlayerにアタッチします

using Unity.Netcode.Components;

public class ClientNetworkTransform : NetworkTransform
{
    protected override bool OnIsServerAuthoritative()
    {
        return false;
    }
}
インフォメーション

このメソッド OnIsServerAuthoritative は、サーバーがオブジェクトのトランスフォームに対して権限を持つかどうかを判断するためのものです。ここで false を返すことによって、「このクライアントが権限を持つ」と定義しています。つまり、このクラスを使用するオブジェクトのトランスフォームは、クライアントによって制御され、サーバーはそのトランスフォームを受け入れるだけになります。

Network Rigidbody 2Dコンポーネントをアタッチ

続けて、PlayerにInspector でNetcode > Network Rigidbody 2Dコンポーネントを追加します。

Playerが落下しないようにします

自動的にRigidbody2Dがアタッチされていますので、Body TypeをKinematicに変更します

Player移動スクリプトの作成

次のスクリプトをPlayerにアタッチします

using Unity.Netcode;
using UnityEngine;

public class PlayerController : NetworkBehaviour
{
    [SerializeField]
    float moveSpeed = 4;

    Rigidbody2D rb;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        if (!IsOwner) return;
        Move();
    }

    void Move()
    {
        float moveHorizontal = Input.GetAxisRaw("Horizontal");
        float moveVertical = Input.GetAxisRaw("Vertical");
        Vector2 movement = new Vector2(moveHorizontal, moveVertical).normalized;
        rb.velocity = movement * moveSpeed;
    }
}
  • [Projectウィンドウ][Assetsフォルダ]を選択します
  • [Assetsフォルダ]内を右クリックし、Create > FolderでPrefabsでフォルダを作成します
  • 先ほど作成した[Prefabsフォルダ]にドラッグして、PlayerからPrefabを作成します。
  • 名前をPlayerPrefabに変更します
  • Playerをシーンから削除します。
ヒント

Playerオブジェクトをシーンから削除するのは、このネットワークPrefabをNetworkManagerコンポーネントのPlayer Prefabプロパティに割り当てるためです。ライブラリは、Playerオブジェクトをシーン内に配置されたNetworkObjectとして定義することをサポートしていません。

  • [Hierarchyウィンドウ]の[NetworkManagerゲームオブジェクト] を選択します。
  • [NetworkManager コンポーネント]で、Player Prefab フィールドを探します。
  • 作成したPlayerPrefabをこのフィールドにドラッグします。
インフォメーション

このPrefabをPlayer Prefabスロットにドロップすると、クライアントがゲームに接続した時に、自動的にこのPrefabを接続クライアントのキャラクターとしてスポーンするようにライブラリに指示することになります。もしPlayer PrefabとしてPrefabが設定されていなければ、プレイヤーオブジェクトは生成されません。

ホストの役割とクライアントの役割を選択できるようにします

次のスクリプトを作成し、[NetworkManagerゲームオブジェクト]にアタッチします

using Unity.Netcode;
using UnityEngine;

public class Selector : MonoBehaviour
{
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.H))
        {
            NetworkManager.Singleton.StartHost();
        }

        if (Input.GetKeyDown(KeyCode.C))
        {
            NetworkManager.Singleton.StartClient();
        }
    }

    // デバッグ用に画面に選択モードを表示
    private void OnGUI()
    {
        // GUIStyleのインスタンスを作成
        GUIStyle myStyle = new GUIStyle
        {
            // フォントサイズを設定
            fontSize = 36
        };

        // テキストの色を設定(オプション)
        myStyle.normal.textColor = Color.white;

        if (NetworkManager.Singleton.IsHost)
        {
            GUI.Label(new Rect(0, 0, 100, 50), "Host", myStyle);
        }
        else if (NetworkManager.Singleton.IsClient)
        {
            GUI.Label(new Rect(0, 0, 100, 50), "Client", myStyle);
        }
    }
}

シーンを保存します。

ビルドにシーンを追加する

インフォメーション

NetworkManagerで’Enable Scene Management’が有効になっている場合(サーバーがクライアントにロードするシーンをコントロールできる)、現在のシーンがビルドに追加されていることを確認する必要があります。このオプションはデフォルトで有効になっています。

  • エディター左上のFile > Build Settingsをクリックします。
  • Add Open Scenesをクリックします。

Windowモードでゲームを起動できるようにする(全画面ではないモード)

テストしやすいように、全画面表示ではなく、ウィンドウで実行・ウィンドウの移動ができるようにします

  • エディター左上のEdit > Project Settings…をクリックします。
  • [Playerタブ]を選択します。
  • [Resolution and Presentation]を展開します。
  • Resolution > Fullscreen Modeから、Fullscreen WindowをWindowedに変更します。
  • Unityエディターのメインウィンドウに戻り、シーンを保存します。

テストで実行してみる

  • エディターを実行して、Hキーを押下して、Circleのゲームオブジェクトが作成されるのを確認します
  • 上下左右キーで移動できることを確認します
インフォメーション

ホスト側を先に生成する必要がありますので、Cキーではゲームオブジェクトは作成されません

ビルドして、ホスト側、クライアント側としてテストしてみる

今回のサンプルでは、ホスト側を、ビルドして実行している方、クライアント側をUnityエディターで実行している方として構成します

  • エディター左上のFile > Build And Runをクリックします。
  • [Projectフォルダー]内に[Builds]という新しいフォルダーを作成します。
  • 実行ファイル作成。NewworkSampleとして保存します。
  • プロジェクトがビルドされ、新しいウィンドウで起動します。
  • Unityエディター側も実行します
  • 新しいウィンドウの方で、「H」キーを押下します
  • Unityエディターの方で、「C」キーを押下します
  • それぞれのウィンドウをクリックしてフォーカスを変更し、上下左右キーで移動できることを確認します

実行中の様子

画面上半分が、ビルドして実行しているウィンドウ、下半分がUnityエディターで実行中のウィンドウになります

参考

NetCodeのホスト、サーバー、クライアント

UnityのNetCodeでは、ネットワーク接続の設定において「ホスト」、「サーバー」、「クライアント」という異なる役割があります。それぞれの役割について詳しく説明します。

ホスト

ホストは、サーバーとクライアントの機能を兼ね備えています。つまり、ホストは自身のゲーム状態を管理しつつ、他のクライアントとのデータの同期も行います。ホストモデルは、特に小規模なマルチプレイヤーゲームや、プレイヤーがサーバーとしても機能する必要がある場合に適しています。

サーバー

サーバーはゲームの状態を中央で管理し、ゲームのロジックを処理します。クライアントからの入力を受け取り、それに基づいてゲームの状態を更新し、その結果をすべてのクライアントに送信します。サーバーは通常、クライアントからは独立しており、ゲームの公正性を保つために中立的な役割を果たします。

クライアント

クライアントはゲームのユーザーインターフェースを担当し、プレイヤーの入力をサーバーに送信します。サーバーからのデータを受け取り、それに基づいて画面上の表示を更新します。クライアントはサーバーの決定に従い、自身のゲームの状態を更新します。

違いと役割

  • ホスト: サーバーとしての役割も担いながら、自らもクライアントとしてゲームに参加します。これにより、ホストがゲーム状態を直接管理し、他のプレイヤーと対話することができます。
  • サーバー: ゲームの全体的な論理と状態を管理し、クライアント間のデータの同期を担当します。サーバーはプレイヤーの一方的な入力に基づく処理を行い、その結果をクライアントに配布します。
  • クライアント: サーバーから送られてくるデータをもとに、プレイヤーの画面にゲーム状態を反映します。クライアントは基本的に受動的な役割を担い、サーバーからの指示に従います。

NetCodeは、これらの役割を効率的に管理し、大規模なマルチプレイヤーゲームでも高いパフォーマンスを提供するよう設計されています。それぞれの役割が明確に分離されていることで、ゲームのスケーラビリティと管理が容易になります。

リンク