【Unity】シンプルなネットワーク対応サンプル
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は、これらの役割を効率的に管理し、大規模なマルチプレイヤーゲームでも高いパフォーマンスを提供するよう設計されています。それぞれの役割が明確に分離されていることで、ゲームのスケーラビリティと管理が容易になります。
ディスカッション
コメント一覧
まだ、コメントがありません