リアルタイム編:2人のキャラクターを同期する
二つのゲーム画面を同じルームにつなぎます。WASD キーでキャラクターを動かし、スペースキーを押すと両方の画面で同じキャラクターが一瞬大きくなります。
基本編で用意した GS2 の学習用プロジェクトと Unity プロジェクトを使います。このページでは新しい RealtimePractice シーンを作り、SDK から接続します。
1. リアルタイム用のネームスペースを作る
マネージメントコンソールで学習用プロジェクトの東京リージョンを開きます。
- Realtime → ネームスペースリスト → ネームスペースを新規作成を開きます。
- 次の値を入力して作成します。
| 項目 | 値 |
|---|---|
| 名前 | adventure-sync |
| サーバの種類 | オブジェクト同期(sync) |
| サーバのスペック | realtime1.nano |
2. ログインするシーンを作る
- Unity の File → New Sceneで空のシーンを作り、
RealtimePracticeとして保存します。 - AdventureLogin.cs を
Assetsに保存します。同じファイルがすでにある場合は、そのファイルを使います。 - 空の
Loginオブジェクトを作り、AdventureLoginを追加します。 - マネージメントコンソールの Deploy → Default → アウトプットリストから、
ApplicationClientIdとApplicationClientSecretを Client Id / Client Secret に入力します。 - Account Namespace は、Studio でアカウントを作った場合は
Account、SDK コースの場合はadventure-accountにします。Account Slot はrealtime-aにします。 - Edit → Project Settings → Player → Other Settings → Active Input Handlingを Both にします。再起動を求められたら Unity を再起動します。
- 同じ Player 設定の Resolution and Presentation → Run In Backgroundをオンにします。別のウィンドウを操作している間も、ビルドしたアプリで同期を続けるための設定です。
3. 同期するキャラクターを作る
次の二つのファイルを Assets に保存します。
- AdventureRoomPlayer.cs:移動とスペースキーの入力。
- AdventureRoomEmote.cs:全員の画面で実行する動作。
移動処理は Transform を動かします。位置を他の画面へ送る処理は、次の手順で追加する NetworkTransform が担当します。
var move = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
transform.position += move.normalized * (3f * Time.deltaTime);
if (Input.GetKeyDown(KeyCode.Space))
GetComponent<NetworkEntity>().Rpc(nameof(AdventureRoomEmote.Wave), RpcTarget.All);RPC は、指定した処理をほかの参加者の画面でも実行する仕組みです。ここでは [NetworkRpc] を付けた Wave が、キャラクターを0.3秒だけ大きくします。
[NetworkRpc]
public IEnumerator Wave(NetworkRpcInfo info)
{
transform.localScale = Vector3.one * 1.5f;
yield return new WaitForSeconds(0.3f);
transform.localScale = Vector3.one;
}キャラクターごとに操作権を持つプレイヤーを決めます。自分の入力で相手のキャラクターも動かしてしまわないよう、移動処理を Controlled Behaviours に登録します。この欄のスクリプトは、操作権を持つ画面でだけ動きます。
- GameObject → 3D Object → Capsuleを作り、名前を
NetworkPlayerにします。 - 次のコンポーネントを追加します。
| コンポーネント | 設定 |
|---|---|
| Network Entity | Schema は空欄。Controlled Behaviours に、このオブジェクトの AdventureRoomPlayer を1件追加 |
| Network Transform | Position Axes は All、Rotation Axes は None |
| Adventure Room Player | 追加したまま使う |
| Adventure Room Emote | 追加したまま使う |
NetworkPlayerを Project ウィンドウにドラッグして Prefab にします。Hierarchy に残った Capsule は削除します。
4. 接続用のオブジェクトを作る
- Project ウィンドウで Create → GS2 → Realtime → Prefab Catalogを選び、
PracticeCatalogを作ります。 - Prefabsに1件追加し、Idを
1、PrefabをNetworkPlayerにします。 - AdventureRoom.cs を
Assetsに保存します。 - 空の
Roomオブジェクトを作ってAdventureRoomを追加します。NetworkWorldとNetworkSessionも追加されます。 - Network World → Prefab Catalogに
PracticeCatalog、Adventure Room → LoginにLoginオブジェクトのAdventureLoginを割り当てます。 - GameObject → 3D Object → Planeで地面を作ります。
- GameObject → Cameraでカメラを作り、名前を
Main Camera、Tag をMainCameraにします。位置を(0, 12, -10)、回転を(50, 0, 0)にします。 - GameObject → Light → Directional Lightでライトを作り、回転を
(50, -30, 0)にします。
接続コードは、ルーム名からIPアドレス・ポート・暗号鍵を取得し、ログインしたプレイヤーのアクセストークンと一緒に渡します。
session.Connect(login.Session.AccessToken.Token,
get.IpAddress, get.Port, get.EncryptionKey);
await UniTask.WaitUntil(
() => session.State == NetworkSessionState.Ready || session.State == NetworkSessionState.Disconnected,
cancellationToken: this.GetCancellationTokenOnDestroy());接続が完了すると Ready が呼ばれ、Prefab ID 1 のキャラクターを生成します。
world.Instantiate(1,
new Vector3(Random.Range(-3f, 3f), 1, Random.Range(-3f, 3f)),
Quaternion.identity);5. 二つの画面で動かす
- シーンを保存し、File → Build Profilesでデスクトップ向けのビルドを作ります。シーンリストに
RealtimePracticeを入れ、今回はほかのシーンのチェックを外して、RealtimePracticeだけを有効にします。 - ビルドしたアプリを起動し、ログイン画面の保存先を
realtime-aにして ログインを押します。Unity Editor でも再生し、こちらの保存先はrealtime-bにしてログインします。 - マネージメントコンソールで
adventure-syncの ルームリスト → ルームを作成を開き、ルーム名をpracticeにして作成します。通知先ユーザーIDリストは空のまま使います。 - 一覧を更新し、
practiceの情報にIPアドレスとポートが表示されたら、アプリと Unity Editor の両方で、ルーム名practiceの このルームに接続を押します。 - 両方に二体のキャラクターが表示されたら、片方のゲーム画面をクリックして WASD キーを押します。同じキャラクターが両方の画面で動きます。
- スペースキーを押し、両方の画面でそのキャラクターが一瞬大きくなることを確かめます。
6. 操作する人を入れ替える
- Bの画面に表示された 自分の接続 ID を、Aの 操作権を渡す相手の接続 ID 欄に入力します。
- Aが所有するオブジェクトの このオブジェクトの操作権を渡すを押します。オブジェクト番号を控えておきます。
- Aで WASD キーを押しても、そのキャラクターは動かなくなります。Bでは、元から持っていたキャラクターと、受け取ったキャラクターの両方が動きます。
- Bの入力欄にAの接続IDを入れ、控えたオブジェクト番号の操作権をAへ返します。再び、それぞれ一体ずつ操作できる状態になります。
操作権を渡す呼び出しは entity.TransferOwnership(相手の接続ID) です。所有者が変わると、Controlled Behaviours の移動スクリプトも、操作できる側で有効になります。
7. 切断して接続し直す
Aの 切断を押します。Bの画面からAのキャラクターが消えます。Aで同じルームへ接続し直すと、新しいキャラクターが現れ、Bのキャラクターは現在の位置に表示されます。
試し終わったら、両方の画面で切断します。マネージメントコンソールの adventure-sync のルームリストから、実習で作った practice を削除します。
サーバー側で敵のHPや勝敗を管理する実装は、GSLで敵を動かすチュートリアル(別タブ)に、ルール定義からUnityでの操作まで載っています。