Skip to content

UNet Multiple Character Solution

Shawnc edited this page Feb 7, 2018 · 1 revision

Dead ends

  • Add components according to the character type after a playerPrefab is spawned: Unity does not support adding NetworkBehaviour to a spawned GameObject
  • Bind every possible component to playerPrefab and disable some of them according to the character type: Too hard to organize component relationships on that prefab. Dirty component references.

Solution

Unreal Method

Let playerPrefab be a 'player controller',and the characters are Pawns/Characters in Unreal concepts. A player controller can possess a character.

Pros: this method is universal, easily comprehensible, fully-controlled

Cons: you have to implement possess, and native helper components like NetworkTransform and NetworkAnimator cannot help you anymore.

P.S: I haven't think over how to implement this feature, will research on Unreal's implementation further.

Spawn-time Replacement (Our Way!)

If your game has a lobby scene, a traditional way to share information between lobbyPlayer and gamePlayer is to customize OnLobbyServerSceneLoadedForPlayer

// class NetworkLobbyPlayer
public override bool OnLobbyServerSceneLoadedForPlayer(GameObject lobbyPlayer,
                                                       GameObject gamePlayer);

This callback runs when the server notices a client has finished loading game scene. By default it spawns a game player prefab and transfer the control from lobbyPlayer to gamePlayer. But we can ignore the existing gamePlayer and create a new character for this client, which requires ReplacePlayerForConnection

public static bool ReplacePlayerForConnection(Networking.NetworkConnection conn,
                                              GameObject player, 
                                              short playerControllerId);

From server's view, clients are just connections. We can get a client's connection from a NetworkIdentity that is spawned for that client, for us that is, the lobbyPlayer.

var clientConn = lobbyPlayer.GetComponent<NetworkIdentity>().connectionToClient;

Then we spawn a new character prefab for the client to 'possess'.

var newPlayer = Instantiate(characterPrefab);           // instantiate on server side
NetworkServer.Spawn(newPlayer);	                   // tell all clients to spawn
NetworkServer.Destroy(gamePlayer);                      // discard auto-created gamePlayer

No need to worry about synchronization problem. The Spawn method of NetworkServer will ensure that every client scene will create a same copy when they are ready.

Finally, we return false for OnLobbyServerSceneLoadedForPlayer to prevent transfer of player control, because we have destroyed the game player and given the control to newPlayer by replacement.