Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to sync game states?

Discussion in 'Multiplayer' started by wertymk, May 27, 2010.

  1. wertymk

    wertymk

    Joined:
    Dec 13, 2009
    Posts:
    104
    I have a simple tank game where from the main menu, which is a single scene, you can select a map and host a server or join a server via direct ip.

    If you host a game it first loads the selected scene with Application.LoadLevel and then starts the server with Network.InitializeServer. Once this is done I spawn a tank for the host with Network.Instantiate and the game logic kicks in and the game runs fine for the host.

    If you join a game you just type in the ip and port and hit connect. The client connects to the server with Network.Connect. I then detect the connection on the server with OnPlayerConnected and send the client an rpc which causes it to load the same scene the host has. After the client has finished loading the level it sends an rpc to the host which spawns a tank for the client with Network.Instantiate.

    Everything works fine up to this point. Nothing else but the level and the client's tank transfers to the client and I get a lot of 'networkview doesn't exist' errors. The host can see the client moving and shooting around, but the client doesn't see the host.

    I guess I somehow need to sync the game states, transfer everything that is going on on the host to the client. But I don't really know where to begin, any help would be appreciated.
     
  2. wertymk

    wertymk

    Joined:
    Dec 13, 2009
    Posts:
    104
    Here's the code I'm using, in case someone can make any sense of it. I'm guessing I should do something in SetLevel or OnLevelWasLoaded, but what?

    Code (csharp):
    1. var connectToIP : String = "127.0.0.1";
    2. var connectPort : int = 25001;
    3. var playerName : String = "";
    4. var selectedLevel:int = 0;
    5. var levelNames:String[] = ["level 1", "level 2"];
    6.  
    7. private var spawn:spawnscript;
    8.  
    9. function Awake(){
    10.     spawn = GameObject.Find("code").GetComponent(spawnscript);
    11.     DontDestroyOnLoad(this);
    12. }
    13.  
    14. //Obviously the GUI is for both client&servers (mixed!)
    15. function OnGUI ()
    16. {
    17.  
    18.     if (Network.peerType == NetworkPeerType.Disconnected){
    19.     //We are currently disconnected: Not a client or host
    20.         GUILayout.Label("Connection status: Disconnected");
    21.        
    22.        
    23.         GUILayout.BeginHorizontal();
    24.         GUILayout.BeginVertical();
    25.         connectToIP = GUILayout.TextField(connectToIP, GUILayout.MinWidth(100));
    26.         connectPort = parseInt(GUILayout.TextField(connectPort.ToString()));
    27.         playerName= GUILayout.TextField(playerName, 25);
    28.        
    29.         //print(selectedLevel);
    30.         if (GUILayout.Button ("Connect as client"))
    31.         {
    32.             //Connect to the "connectToIP" and "connectPort" as entered via the GUI
    33.             //Ignore the NAT for now
    34.             Network.useNat = false;
    35.             Network.Connect(connectToIP, connectPort);
    36.         }
    37.         GUILayout.EndVertical();
    38.         GUILayout.BeginVertical();
    39.         selectedLevel = GUILayout.SelectionGrid(selectedLevel, levelNames, 1);
    40.         if (GUILayout.Button ("Start Server"))
    41.         {
    42.             //Start a server for 32 clients using the "connectPort" given via the GUI
    43.             //Ignore the nat for now   
    44.             Network.useNat = false;
    45.             selectedLevel += 1;
    46.             Application.LoadLevel(selectedLevel);
    47.             Network.InitializeServer(16, connectPort);
    48.         }
    49.         GUILayout.EndVertical();
    50.         GUILayout.EndHorizontal();
    51.        
    52.     }
    Code (csharp):
    1.  
    2. class Player{
    3.     var gamePlayer;
    4.     var tank:Transform;
    5.     var frags:int;
    6.     var team:int;
    7. }
    8.  
    9. var spawnPoints:GameObject[];
    10.  
    11. function Awake(){
    12.     DontDestroyOnLoad(this);
    13. }
    14.  
    15. var level:int;
    16. var serverLevel:int;
    17.  
    18.  
    19.  
    20. var scoreboard:String;
    21.  
    22. var players:Player[] = new Player[16];
    23.  
    24. public var playerPrefab : Transform;
    25.  
    26. function OnLevelWasLoaded(lev:int){
    27.     if(Network.isServer){
    28.         serverLevel = Application.loadedLevel;
    29.         spawnPoints = GameObject.FindGameObjectsWithTag("Respawn");
    30.         var gamePlayer = new Player();
    31.         gamePlayer.gamePlayer = Network.player;
    32.         gamePlayer.tank = null;
    33.         gamePlayer.frags = 0;
    34.         gamePlayer.team = 0;
    35.    
    36.         for (slot in players){
    37.             if(slot.gamePlayer == null){
    38.                 slot = gamePlayer;
    39.                 break;
    40.             }
    41.         }
    42.         Spawnplayer(Network.player);
    43.         UpdateScoreboard();
    44.     }else if(Network.isClient){
    45.         networkView.RPC("RequestSpawn", RPCMode.Server, Network.player);
    46.     }
    47. }
    48.  
    49. function OnPlayerConnected(newPlayer: NetworkPlayer) {
    50.     //A player connected to me(the server)!
    51.     print("player connected");
    52.     networkView.RPC("SetLevel", RPCMode.Others, serverLevel);
    53.    
    54.     var gamePlayer = new Player();
    55.     gamePlayer.gamePlayer = newPlayer;
    56.     gamePlayer.tank = null;
    57.     gamePlayer.frags = 0;
    58.     gamePlayer.team = 0;
    59.    
    60.     for (slot in players){
    61.         if(slot.gamePlayer == null){
    62.             slot = gamePlayer;
    63.             break;
    64.         }
    65.     }
    66.     UpdateScoreboard();
    67. }  
    68.  
    69. function OnPlayerDisconnected(disconnectedPlayer:NetworkPlayer){
    70.     for(slot in players){
    71.         if (slot.gamePlayer == disconnectedPlayer){
    72.             var nv:NetworkView = slot.tank.GetComponent(NetworkView);
    73.             Network.Destroy(nv.viewID);
    74.             slot = new Player();
    75.         }
    76.     }
    77.     UpdateScoreboard();
    78. }
    79.  
    80. //~ function OnConnectedToServer(){
    81.     //~ Application.LoadLevel(level);
    82. //~ }
    83.  
    84. @RPC
    85. function Spawnplayer(newPlayer:NetworkPlayer){
    86.     //Called on the server only
    87.    
    88.     var point:int = Mathf.Round(Random.value * spawnPoints.length);
    89.     if(point == spawnPoints.length){
    90.         point--;
    91.     }
    92.     var spawnPoint:Transform = spawnPoints[point].transform;
    93.    
    94.     var playerNumber : int = parseInt(newPlayer+"");
    95.     //Instantiate a new object for this player, remember; the server is therefore the owner.
    96.     var myNewTrans : Transform = Network.Instantiate(playerPrefab, spawnPoint.position, spawnPoint.rotation, playerNumber);
    97.     for(slot in players){
    98.         if(slot.gamePlayer == newPlayer){
    99.             slot.tank = myNewTrans;
    100.             break;
    101.         }
    102.     }
    103.    
    104.     //Get the networkview of this new transform
    105.     var newObjectsNetworkview : NetworkView = myNewTrans.networkView;
    106.    
    107.     //Call an RPC on this new networkview, set the player who controls this player
    108.     newObjectsNetworkview.RPC("SetPlayer", RPCMode.AllBuffered, newPlayer);//Set it on the owner
    109. }
    110.  
    111. function UpdateScoreboard(){
    112.     if(Network.isServer){
    113.         var serverScoreboard = "Kills:\n";
    114.         for (slot in players){
    115.             if (slot.gamePlayer != null){
    116.                 serverScoreboard = serverScoreboard + "player" + slot.gamePlayer + ": " + slot.frags + "\n";
    117.             }  
    118.         }
    119.         scoreboard = serverScoreboard;
    120.         networkView.RPC("SendScoreboard", RPCMode.Others, serverScoreboard);
    121.     }
    122. }
    123.  
    124. @RPC
    125. function SendScoreboard(serverScoreboard:String){
    126.     scoreboard = serverScoreboard;
    127. }
    128.  
    129. @RPC
    130. function RequestSpawn(newPlayer:NetworkPlayer){
    131.     Spawnplayer(newPlayer);
    132. }
    133.  
    134. @RPC
    135. function SetLevel(serverLevel:int){
    136.     level = serverLevel;
    137.     print(level);
    138.     Application.LoadLevel(level);
    139. }
     
  3. LoganBarnett

    LoganBarnett

    Joined:
    Feb 18, 2010
    Posts:
    11
    Not sure if you're still having this issue or not, but you need to call Network.Instantiate on the client when it connects. From what it looks like here you're sending an RPC to the server to do the spawn. When the client instantiates the object, the client owns it and can change it.

    I have a networking game that works (you can't run it well in the web player I've noticed, so try a native build). You can pull down the source from here: http://github.com/LoganBarnett/Droids