Search Unity

Cant get character selection working with multiplayer

Discussion in 'Multiplayer' started by Chris8115, Oct 31, 2016.

  1. Chris8115

    Chris8115

    Joined:
    Jan 19, 2015
    Posts:
    10
    I have 4 players prefabs in a list and in singleplayer the user can cycle through and pick a character and it will load it into the game but does anyone know a good way to do this in multiplayer
     
  2. IAMBATMAN

    IAMBATMAN

    Joined:
    Aug 14, 2015
    Posts:
    272
    Hello, I recently did this with the help of this thread https://forum.unity3d.com/threads/unet-spawning-different-player-prefabs-solved.387747/

    I used this script

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Networking;
    3. using UnityEngine.Networking.NetworkSystem;
    4.  
    5. public class NetworkCustom : NetworkManager
    6. {
    7.  
    8.     public int chosenCharacter = 0;
    9.     public GameObject[] characters;
    10.  
    11.     //subclass for sending network messages
    12.     public class NetworkMessage : MessageBase
    13.     {
    14.         public int chosenClass;
    15.     }
    16.  
    17.     public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId, NetworkReader extraMessageReader)
    18.     {
    19.         NetworkMessage message = extraMessageReader.ReadMessage<NetworkMessage>();
    20.         int selectedClass = message.chosenClass;
    21.         Debug.Log("server add with message " + selectedClass);
    22.  
    23.         GameObject player;
    24.         Transform startPos = GetStartPosition();
    25.  
    26.         if(startPos != null)
    27.         {
    28.             player = Instantiate(characters[chosenCharacter], startPos.position,startPos.rotation)as GameObject;
    29.         }
    30.         else
    31.         {
    32.             player = Instantiate(characters[chosenCharacter], Vector3.zero, Quaternion.identity) as GameObject;
    33.  
    34.         }
    35.  
    36.         NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
    37.  
    38.     }
    39.  
    40.     public override void OnClientConnect(NetworkConnection conn)
    41.     {
    42.         NetworkMessage test = new NetworkMessage();
    43.         test.chosenClass = chosenCharacter;
    44.  
    45.         ClientScene.AddPlayer(conn, 0, test);
    46.     }
    47.  
    48.  
    49.     public override void OnClientSceneChanged(NetworkConnection conn)
    50.     {
    51.         //base.OnClientSceneChanged(conn);
    52.     }
    53.  
    54.     public void btn1()
    55.     {
    56.         chosenCharacter = 0;
    57.     }
    58.  
    59.     public void btn2()
    60.     {
    61.         chosenCharacter = 1;
    62.     }
    63. }
    64.  
    And on the networkmanager there's a field called "Script" just drag this script in there.
    Then add all you player prefabs to the characters field, the int chosenCharacter is the index for your characters.

    Then I made this quick script

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.Networking;
    4.  
    5. public class ChooseHero : MonoBehaviour {
    6.  
    7.     public GameObject characterSelect;
    8.  
    9.     public void PickHero(int hero)
    10.     {
    11.         NetworkManager.singleton.GetComponent<NetworkCustom>().chosenCharacter = hero;
    12.         characterSelect.SetActive(false);
    13.     }
    14. }
    15.  
    So that I could use unity's buttons to pick my character. I added this script to an empty object that I called "Game Manager"

    This lets you pick your character before you join a game. IMPORTANT Make sure to register your player prefabs with the networkmanager.
     
  3. Chris8115

    Chris8115

    Joined:
    Jan 19, 2015
    Posts:
    10
    Thanks for the help i will test this with my project soon.
     
  4. Chris8115

    Chris8115

    Joined:
    Jan 19, 2015
    Posts:
    10
    I have the scripts in my game now but i'm confused on how to let players select their character in the lobby and have the lobby manager load them into the game. My script is a mix of your script and the default unity one for the lobbies. I have a empty game object with the Choose Hero script like you said but the lobby script is still looking for a player prefab so i'm just confused on how to set this up.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using UnityEngine.SceneManagement;
    4. using UnityEngine.Networking;
    5. using UnityEngine.Networking.Types;
    6. using UnityEngine.Networking.Match;
    7. using System.Collections;
    8.  
    9.  
    10. namespace Prototype.NetworkLobby
    11. {
    12.     public class LobbyManager : NetworkLobbyManager
    13.     {
    14.         static short MsgKicked = MsgType.Highest + 1;
    15.  
    16.         static public LobbyManager s_Singleton;
    17.  
    18.  
    19.         [Header("Unity UI Lobby")]
    20.         [Tooltip("Time in second between all players ready & match start")]
    21.         public float prematchCountdown = 5.0f;
    22.  
    23.         [Space]
    24.         [Header("UI Reference")]
    25.         public LobbyTopPanel topPanel;
    26.  
    27.         public RectTransform mainMenuPanel;
    28.         public RectTransform lobbyPanel;
    29.  
    30.         public LobbyInfoPanel infoPanel;
    31.         public LobbyCountdownPanel countdownPanel;
    32.         public GameObject addPlayerButton;
    33.  
    34.         protected RectTransform currentPanel;
    35.  
    36.         public Button backButton;
    37.  
    38.         public Text statusInfo;
    39.         public Text hostInfo;
    40.  
    41.  
    42.         //Client numPlayers from NetworkManager is always 0, so we count (throught connect/destroy in LobbyPlayer) the number
    43.         //of players, so that even client know how many player there is.
    44.         [HideInInspector]
    45.         public int _playerNumber = 0;
    46.  
    47.         //used to disconnect a client properly when exiting the matchmaker
    48.         [HideInInspector]
    49.         public bool _isMatchmaking = false;
    50.  
    51.         protected bool _disconnectServer = false;
    52.        
    53.         protected ulong _currentMatchID;
    54.  
    55.         protected LobbyHook _lobbyHooks;
    56.  
    57.         public int chosenCharacter = 0;
    58.         public GameObject[] characters;
    59.  
    60.  
    61.         void Start()
    62.         {
    63.             s_Singleton = this;
    64.             _lobbyHooks = GetComponent<Prototype.NetworkLobby.LobbyHook>();
    65.             currentPanel = mainMenuPanel;
    66.  
    67.             backButton.gameObject.SetActive(false);
    68.             GetComponent<Canvas>().enabled = true;
    69.  
    70.             DontDestroyOnLoad(gameObject);
    71.  
    72.             SetServerInfo("Offline", "None");
    73.         }
    74.            
    75.  
    76.         public void ReturnMM() {
    77.             SceneManager.LoadScene("MainMenu");
    78.         }
    79.  
    80.         public override void OnLobbyClientSceneChanged(NetworkConnection conn)
    81.         {
    82.             if (SceneManager.GetSceneAt(0).name == lobbyScene)
    83.             {
    84.                 if (topPanel.isInGame)
    85.                 {
    86.                     ChangeTo(lobbyPanel);
    87.                     if (_isMatchmaking)
    88.                     {
    89.                         if (conn.playerControllers[0].unetView.isServer)
    90.                         {
    91.                             backDelegate = StopHostClbk;
    92.                         }
    93.                         else
    94.                         {
    95.                             backDelegate = StopClientClbk;
    96.                         }
    97.                     }
    98.                     else
    99.                     {
    100.                         if (conn.playerControllers[0].unetView.isClient)
    101.                         {
    102.                             backDelegate = StopHostClbk;
    103.                         }
    104.                         else
    105.                         {
    106.                             backDelegate = StopClientClbk;
    107.                         }
    108.                     }
    109.                 }
    110.                 else
    111.                 {
    112.                     ChangeTo(mainMenuPanel);
    113.                 }
    114.  
    115.                 topPanel.ToggleVisibility(true);
    116.                 topPanel.isInGame = false;
    117.             }
    118.             else
    119.             {
    120.                 ChangeTo(null);
    121.  
    122.                 Destroy(GameObject.Find("MainMenuUI(Clone)"));
    123.  
    124.                 //backDelegate = StopGameClbk;
    125.                 topPanel.isInGame = true;
    126.                 topPanel.ToggleVisibility(false);
    127.             }
    128.         }
    129.  
    130.         public void ChangeTo(RectTransform newPanel)
    131.         {
    132.             if (currentPanel != null)
    133.             {
    134.                 currentPanel.gameObject.SetActive(false);
    135.             }
    136.  
    137.             if (newPanel != null)
    138.             {
    139.                 newPanel.gameObject.SetActive(true);
    140.             }
    141.  
    142.             currentPanel = newPanel;
    143.  
    144.             if (currentPanel != mainMenuPanel)
    145.             {
    146.                 backButton.gameObject.SetActive(true);
    147.             }
    148.             else
    149.             {
    150.                 backButton.gameObject.SetActive(false);
    151.                 SetServerInfo("Offline", "None");
    152.                 _isMatchmaking = false;
    153.             }
    154.         }
    155.  
    156.         public void DisplayIsConnecting()
    157.         {
    158.             var _this = this;
    159.             infoPanel.Display("Connecting...", "Cancel", () => { _this.backDelegate(); });
    160.         }
    161.  
    162.         public void SetServerInfo(string status, string host)
    163.         {
    164.             statusInfo.text = status;
    165.             hostInfo.text = host;
    166.         }
    167.  
    168.  
    169.         public delegate void BackButtonDelegate();
    170.         public BackButtonDelegate backDelegate;
    171.         public void GoBackButton()
    172.         {
    173.             backDelegate();
    174.             topPanel.isInGame = false;
    175.         }
    176.  
    177.         // ----------------- Server management
    178.  
    179.         public void AddLocalPlayer()
    180.         {
    181.             TryToAddPlayer();
    182.         }
    183.  
    184.         public void RemovePlayer(LobbyPlayer player)
    185.         {
    186.             player.RemovePlayer();
    187.         }
    188.  
    189.         public void SimpleBackClbk()
    190.         {
    191.             ChangeTo(mainMenuPanel);
    192.         }
    193.                
    194.         public void StopHostClbk()
    195.         {
    196.             if (_isMatchmaking)
    197.             {
    198.                 matchMaker.DestroyMatch((NetworkID)_currentMatchID, 0, OnDestroyMatch);
    199.                 _disconnectServer = true;
    200.             }
    201.             else
    202.             {
    203.                 StopHost();
    204.             }
    205.  
    206.            
    207.             ChangeTo(mainMenuPanel);
    208.         }
    209.  
    210.         public void StopClientClbk()
    211.         {
    212.             StopClient();
    213.  
    214.             if (_isMatchmaking)
    215.             {
    216.                 StopMatchMaker();
    217.             }
    218.  
    219.             ChangeTo(mainMenuPanel);
    220.         }
    221.  
    222.         public void StopServerClbk()
    223.         {
    224.             StopServer();
    225.             ChangeTo(mainMenuPanel);
    226.         }
    227.  
    228.  
    229.  
    230.         class KickMsg : MessageBase { }
    231.    
    232.         public void KickPlayer(NetworkConnection conn)
    233.         {
    234.             conn.Send(MsgKicked, new KickMsg());
    235.         }
    236.  
    237.  
    238.  
    239.  
    240.         public void KickedMessageHandler(NetworkMessage netMsg)
    241.         {
    242.             infoPanel.Display("Kicked by Server", "Close", null);
    243.             netMsg.conn.Disconnect();
    244.         }
    245.  
    246.         //===================
    247.  
    248.         public override void OnStartHost()
    249.         {
    250.             base.OnStartHost();
    251.  
    252.             ChangeTo(lobbyPanel);
    253.             backDelegate = StopHostClbk;
    254.             SetServerInfo("Hosting", networkAddress);
    255.         }
    256.  
    257.         public override void OnMatchCreate(bool success, string extendedInfo, MatchInfo matchInfo)
    258.         {
    259.             base.OnMatchCreate(success, extendedInfo, matchInfo);
    260.             _currentMatchID = (System.UInt64)matchInfo.networkId;
    261.         }
    262.  
    263.         public override void OnDestroyMatch(bool success, string extendedInfo)
    264.         {
    265.             base.OnDestroyMatch(success, extendedInfo);
    266.             if (_disconnectServer)
    267.             {
    268.                 StopMatchMaker();
    269.                 StopHost();
    270.             }
    271.         }
    272.  
    273.         //allow to handle the (+) button to add/remove player
    274.         public void OnPlayersNumberModified(int count)
    275.         {
    276.             _playerNumber += count;
    277.  
    278.             int localPlayerCount = 0;
    279.             foreach (PlayerController p in ClientScene.localPlayers)
    280.                 localPlayerCount += (p == null || p.playerControllerId == -1) ? 0 : 1;
    281.  
    282.             addPlayerButton.SetActive(localPlayerCount < maxPlayersPerConnection && _playerNumber < maxPlayers);
    283.         }
    284.  
    285.         // ----------------- Server callbacks ------------------
    286.  
    287.         //we want to disable the button JOIN if we don't have enough player
    288.         //But OnLobbyClientConnect isn't called on hosting player. So we override the lobbyPlayer creation
    289.         public override GameObject OnLobbyServerCreateLobbyPlayer(NetworkConnection conn, short playerControllerId)
    290.         {
    291.             GameObject obj = Instantiate(lobbyPlayerPrefab.gameObject) as GameObject;
    292.  
    293.             LobbyPlayer newPlayer = obj.GetComponent<LobbyPlayer>();
    294.             newPlayer.ToggleJoinButton(numPlayers + 1 >= minPlayers);
    295.  
    296.  
    297.             for (int i = 0; i < lobbySlots.Length; ++i)
    298.             {
    299.                 LobbyPlayer p = lobbySlots[i] as LobbyPlayer;
    300.  
    301.                 if (p != null)
    302.                 {
    303.                     p.RpcUpdateRemoveButton();
    304.                     p.ToggleJoinButton(numPlayers + 1 >= minPlayers);
    305.                 }
    306.             }
    307.  
    308.             return obj;
    309.         }
    310.  
    311.         public override void OnLobbyServerPlayerRemoved(NetworkConnection conn, short playerControllerId)
    312.         {
    313.             for (int i = 0; i < lobbySlots.Length; ++i)
    314.             {
    315.                 LobbyPlayer p = lobbySlots[i] as LobbyPlayer;
    316.  
    317.                 if (p != null)
    318.                 {
    319.                     p.RpcUpdateRemoveButton();
    320.                     p.ToggleJoinButton(numPlayers + 1 >= minPlayers);
    321.                 }
    322.             }
    323.         }
    324.  
    325.         public override void OnLobbyServerDisconnect(NetworkConnection conn)
    326.         {
    327.             for (int i = 0; i < lobbySlots.Length; ++i)
    328.             {
    329.                 LobbyPlayer p = lobbySlots[i] as LobbyPlayer;
    330.  
    331.                 if (p != null)
    332.                 {
    333.                     p.RpcUpdateRemoveButton();
    334.                     p.ToggleJoinButton(numPlayers >= minPlayers);
    335.                 }
    336.             }
    337.  
    338.         }
    339.  
    340.         public override bool OnLobbyServerSceneLoadedForPlayer(GameObject lobbyPlayer, GameObject gamePlayer)
    341.         {
    342.             //This hook allows you to apply state data from the lobby-player to the game-player
    343.             //just subclass "LobbyHook" and add it to the lobby object.
    344.  
    345.             if (_lobbyHooks)
    346.                 _lobbyHooks.OnLobbyServerSceneLoadedForPlayer(this, lobbyPlayer, gamePlayer);
    347.  
    348.             return true;
    349.         }
    350.  
    351.         // --- Countdown management
    352.  
    353.         public override void OnLobbyServerPlayersReady()
    354.         {
    355.             bool allready = true;
    356.             for(int i = 0; i < lobbySlots.Length; ++i)
    357.             {
    358.                 if(lobbySlots[i] != null)
    359.                     allready &= lobbySlots[i].readyToBegin;
    360.             }
    361.  
    362.             if(allready)
    363.                 StartCoroutine(ServerCountdownCoroutine());
    364.         }
    365.  
    366.         public IEnumerator ServerCountdownCoroutine()
    367.         {
    368.             float remainingTime = prematchCountdown;
    369.             int floorTime = Mathf.FloorToInt(remainingTime);
    370.  
    371.             while (remainingTime > 0)
    372.             {
    373.                 yield return null;
    374.  
    375.                 remainingTime -= Time.deltaTime;
    376.                 int newFloorTime = Mathf.FloorToInt(remainingTime);
    377.  
    378.                 if (newFloorTime != floorTime)
    379.                 {//to avoid flooding the network of message, we only send a notice to client when the number of plain seconds change.
    380.                     floorTime = newFloorTime;
    381.  
    382.                     for (int i = 0; i < lobbySlots.Length; ++i)
    383.                     {
    384.                         if (lobbySlots[i] != null)
    385.                         {//there is maxPlayer slots, so some could be == null, need to test it before accessing!
    386.                             (lobbySlots[i] as LobbyPlayer).RpcUpdateCountdown(floorTime);
    387.                         }
    388.                     }
    389.                 }
    390.             }
    391.  
    392.             for (int i = 0; i < lobbySlots.Length; ++i)
    393.             {
    394.                 if (lobbySlots[i] != null)
    395.                 {
    396.                     (lobbySlots[i] as LobbyPlayer).RpcUpdateCountdown(0);
    397.                 }
    398.             }
    399.  
    400.             ServerChangeScene(playScene);
    401.         }
    402.  
    403.         // ----------------- Client callbacks ------------------
    404.    
    405.  
    406.         public override void OnClientConnect(NetworkConnection conn)
    407.         {
    408.  
    409.             base.OnClientConnect(conn);
    410.  
    411.             infoPanel.gameObject.SetActive(false);
    412.  
    413.             conn.RegisterHandler(MsgKicked, KickedMessageHandler);
    414.  
    415.             if (!NetworkServer.active)
    416.             {//only to do on pure client (not self hosting client)
    417.                 ChangeTo(lobbyPanel);
    418.                 backDelegate = StopClientClbk;
    419.                 SetServerInfo("Client", networkAddress);
    420.             }
    421.         }
    422.  
    423.  
    424.         public override void OnClientDisconnect(NetworkConnection conn)
    425.         {
    426.             base.OnClientDisconnect(conn);
    427.             ChangeTo(mainMenuPanel);
    428.         }
    429.  
    430.         public override void OnClientError(NetworkConnection conn, int errorCode)
    431.         {
    432.             ChangeTo(mainMenuPanel);
    433.             infoPanel.Display("Cient error : " + (errorCode == 6 ? "timeout" : errorCode.ToString()), "Close", null);
    434.         }
    435.  
    436.         public class NetworkCustom : NetworkManager
    437.         {
    438.  
    439.             public int chosenCharacter = 0;
    440.             public GameObject[] characters;
    441.  
    442.             //subclass for sending network messages
    443.             public class NetworkMessage : MessageBase
    444.             {
    445.                 public int chosenClass;
    446.             }
    447.  
    448.             public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId, NetworkReader extraMessageReader)
    449.             {
    450.                 NetworkMessage message = extraMessageReader.ReadMessage<NetworkMessage>();
    451.                 int selectedClass = message.chosenClass;
    452.                 Debug.Log("server add with message " + selectedClass);
    453.  
    454.                 GameObject player;
    455.                 Transform startPos = GetStartPosition();
    456.  
    457.                 if(startPos != null)
    458.                 {
    459.                     player = Instantiate(characters[chosenCharacter], startPos.position,startPos.rotation)as GameObject;
    460.                 }
    461.                 else
    462.                 {
    463.                     player = Instantiate(characters[chosenCharacter], Vector3.zero, Quaternion.identity) as GameObject;
    464.  
    465.                 }
    466.  
    467.                 NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
    468.  
    469.             }
    470.  
    471.             public override void OnClientConnect(NetworkConnection conn)
    472.             {
    473.                 NetworkMessage test = new NetworkMessage();
    474.                 test.chosenClass = chosenCharacter;
    475.  
    476.                 ClientScene.AddPlayer(conn, 0, test);
    477.             }
    478.  
    479.  
    480.             public override void OnClientSceneChanged(NetworkConnection conn)
    481.             {
    482.                 //base.OnClientSceneChanged(conn);
    483.             }
    484.  
    485.             public void btn1()
    486.             {
    487.                 chosenCharacter = 0;
    488.             }
    489.  
    490.             public void btn2()
    491.             {
    492.                 chosenCharacter = 1;
    493.             }
    494.         }
    495.  
    496.     }
    497. }
    498.  
     
  5. IAMBATMAN

    IAMBATMAN

    Joined:
    Aug 14, 2015
    Posts:
    272
    Hmmm.. I'm not sure, when I implemented this I didn't use a lobby. I've also never used a lobby in UNET, but doesn't the lobby require a special lobby player prefab?

    There's someone asking about using this scirpt and the lobby at the same time, in the forum post I linked above.

    The problem is because this code

    Code (CSharp):
    1. public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId, NetworkReader extraMessageReader)
    2.             {
    3.                 NetworkMessage message = extraMessageReader.ReadMessage<NetworkMessage>();
    4.                 int selectedClass = message.chosenClass;
    5.                 Debug.Log("server add with message " + selectedClass);
    6.                 GameObject player;
    7.                 Transform startPos = GetStartPosition();
    8.                 if(startPos != null)
    9.                 {
    10.                     player = Instantiate(characters[chosenCharacter], startPos.position,startPos.rotation)as GameObject;
    11.                 }
    12.                 else
    13.                 {
    14.                     player = Instantiate(characters[chosenCharacter], Vector3.zero, Quaternion.identity) as GameObject;
    15.                 }
    16.                 NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
    17.             }
    Runs when joining the lobby, instead of joining the game. But I wouldn't know a way around it.
     
  6. Chris8115

    Chris8115

    Joined:
    Jan 19, 2015
    Posts:
    10
    Okay, thanks for the reply i will look into it and see if i can Frankenstein something together lol.
     
  7. lullaharsh

    lullaharsh

    Joined:
    Sep 9, 2012
    Posts:
    29
    Did you fix it yet? Please, I need help on this topic too. I can run IAMBATMAN's script without lobby, but with lobby it becomes a pain in the head.
     
  8. Chris8115

    Chris8115

    Joined:
    Jan 19, 2015
    Posts:
    10
  9. ForbiddenDay

    ForbiddenDay

    Joined:
    Mar 10, 2015
    Posts:
    2
    Following that link how do you go about making the int version of the color code like he mentions or how did you get it to work cause I cant seem to find out how? Any point in the right direction will be greatly appreciated, I am just stumped at trying to get this to work and nothing else I have done works either.
     
  10. mcbauer

    mcbauer

    Joined:
    Oct 10, 2015
    Posts:
    524
    Does anyone have a solution for this yet? Seems like a pretty legit topic for anyone wanting to make games these days.