Realtime: Synchronize two players

Show a character you control on another player’s screen.

Connect two game windows to the same room. Move a character with WASD, then press Space to briefly enlarge that character on both screens.

Use the GS2 tutorial project and Unity project from the basics. On this page, create a new RealtimePractice scene and connect through the SDK.

1. Create a Realtime namespace

In the management console, open the Tokyo region of your tutorial project.

  1. Open Realtime → Namespace list → Create namespace.
  2. Enter the following values and create it.
FieldValue
Nameadventure-sync
Server typeObject synchronization (sync)
Server specificationrealtime1.nano

2. Create a scene with login

  1. In Unity, create an empty scene with File → New Scene and save it as RealtimePractice.
  2. Save AdventureLogin.cs in Assets. If you already have the file, use that copy.
  3. Create an empty Login object and add AdventureLogin.
  4. From Deploy → Default → Output list in the management console, copy ApplicationClientId and ApplicationClientSecret into Client Id / Client Secret.
  5. Set Account Namespace to Account if you created accounts with Studio, or adventure-account for the SDK course. Set Account Slot to realtime-a.
  6. Set Edit → Project Settings → Player → Other Settings → Active Input Handling to Both. Restart Unity if prompted.
  7. In the same Player settings, enable Resolution and Presentation → Run In Background. This keeps synchronization running in the built app while you use another window.

3. Create the synchronized character

Save these two files in Assets.

The movement code changes the Transform. NetworkTransform, added in the next steps, sends the position to the other screens.

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);

An RPC runs a specified action on other participants’ screens too. Here, Wave, marked with [NetworkRpc], enlarges the character for 0.3 seconds.

[NetworkRpc]
public IEnumerator Wave(NetworkRpcInfo info)
{
    transform.localScale = Vector3.one * 1.5f;
    yield return new WaitForSeconds(0.3f);
    transform.localScale = Vector3.one;
}

Each character has a player who owns its controls. Register the movement script under Controlled Behaviours so your input does not move the other player’s character. Scripts in this list run only on the owner’s screen.

  1. Create GameObject → 3D Object → Capsule and name it NetworkPlayer.
  2. Add the following components.
ComponentSettings
Network EntityLeave Schema empty. Add this object’s AdventureRoomPlayer to Controlled Behaviours
Network TransformPosition Axes: All; Rotation Axes: None
Adventure Room PlayerKeep the defaults
Adventure Room EmoteKeep the defaults
  1. Drag NetworkPlayer into the Project window to create a Prefab. Delete the Capsule remaining in the Hierarchy.

4. Create the connection object

  1. In the Project window, choose Create → GS2 → Realtime → Prefab Catalog and create PracticeCatalog.
  2. Add one entry to Prefabs, with Id 1 and Prefab NetworkPlayer.
  3. Save AdventureRoom.cs in Assets.
  4. Create an empty Room object and add AdventureRoom. NetworkWorld and NetworkSession are added automatically.
  5. Assign PracticeCatalog to Network World → Prefab Catalog, and the Login object’s AdventureLogin to Adventure Room → Login.
  6. Create the ground with GameObject → 3D Object → Plane.
  7. Create GameObject → Camera, name it Main Camera, and set its Tag to MainCamera. Set position to (0, 12, -10) and rotation to (50, 0, 0).
  8. Create GameObject → Light → Directional Light and set its rotation to (50, -30, 0).

The connection code looks up the room’s IP address, port, and encryption key by name, then passes them along with the logged-in player’s access token.

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());

Once connected, Ready is called and spawns the character with Prefab ID 1.

world.Instantiate(1,
    new Vector3(Random.Range(-3f, 3f), 1, Random.Range(-3f, 3f)),
    Quaternion.identity);

5. Move characters in two windows

  1. Save the scene and create a desktop build under File → Build Profiles. Add RealtimePractice to the scene list, uncheck the other scenes, and enable only RealtimePractice for this build.
  2. Start the built app, set the login screen’s account slot to realtime-a, and click Log in. Enter Play Mode in the Unity Editor too, set its slot to realtime-b, and log in.
  3. In the management console, open Room list → Create room for adventure-sync. Create a room named practice. Leave the notification user ID list empty.
  4. Refresh the list. When practice shows an IP address and port, click Connect to this room with room name practice in both the app and Unity Editor.
  5. Once both windows show two characters, click one game window and press WASD. The same character moves in both windows.
  6. Press Space and check that the character briefly grows on both screens.

6. Transfer control to the other player

  1. Copy My connection ID from B’s screen into A’s Connection ID to transfer control to field.
  2. For an object owned by A, click Transfer control of this object. Note its object number.
  3. WASD on A no longer moves that character. On B, it moves both the original character and the transferred one.
  4. Enter A’s connection ID on B and return control of the noted object to A. Each player can control one character again.

Transfer control with entity.TransferOwnership(otherConnectionId). When ownership changes, the movement script in Controlled Behaviours becomes enabled on the new owner’s screen.

7. Disconnect and reconnect

Click Disconnect on A. A’s character disappears from B’s screen. Reconnect A to the same room: a new character appears, while B’s character is shown at its current position.

When finished, disconnect both windows. In the management console, delete the practice room from adventure-sync’s room list.

To manage enemy HP and game results on the server, see the GSL enemy tutorial (new tab), from defining rules to trying them in Unity.

Back to the tutorial