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

simple intro to multiplayer?

Discussion in 'Multiplayer' started by psx, Feb 12, 2008.

  1. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    I'm working on an idea for a simple two player game and have been looking through the networking example but it's not really sinking in. I'd like to make something like air hockey. Basically, each player controls a paddle, and there's a puck in the middle. Players can knock the puck around with their paddle.

    So there's the puck, two paddles, a box to contain the puck and some goal colliders.

    My thoughts on making this a multiplayer game are that I'd start with my game scene with the above items. I'd then create a 'local player controller' game object and script, where mouse and/or keyboard input would control one of the paddles. I'd then create a 'remote player controller' game object and script, to take input from the other player (networkView?, RPC?) and control the other puck.

    Would anyone be willing to knock up a simple example of a loader scene, where you can create a server or join an existing game, and allow 1 player to control 1 paddle, and the second player to control the other paddle and be able to knock a puck/ball around whatever surface? Getting from the loader scene to the game scene, setting up the networking stuff, and (this is way confusing to me!) allowing both players to have the same viewpoint (player A is behind his paddle, player B behind his).

    To hopefully make what I'm asking easier to understand, I've worked up a basic starting point (attached zip). The controls aren't great, but hopefully it makes sense where I want to go with it.

    Thanks!
    psx
     

    Attached Files:

  2. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    anyone? I'm reading a ton and it seems like this is a bit harder than I realized because it relies on physics. Can someone confirm if that's true?

    Also, can anyone help me setup a simple 'create/join server' scene that works in concert with a single game scene? Maybe even walking through recreating one piece of the network example, like the loader or chat or something? I think it'd help supplement the example quite well.

    Thanks!
    psx
     
  3. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    Well, to be honest: I don't really believe in "simple intros to multiplayer"... Even your "simple example" might turn out more involved than one might expect at first. What I would (highly) recommend before jumping into multiplayer is reading a good book on the subject.

    One book I can really recommend is "Networkd Virtual Environments - Design and Implementation". By Sandeep Singhal and Michael Zyda. It may seem a little outdated here and there, but I think the main concepts are still quite valid, and I had quite a bit of fun reading it.

    What I really like about this book is that there's no code in it, which gets outdated a minute after the book is released anyways. Instead, you get more of a high-level approach. That way, I would say reading this book and playing with the concepts portrayed in the book in Unity should get you up and running real quick... And you'll definitely appreciate the ease of the Unity networking APIs while reading that (or another good) book on the subject ;-)


    Obviously, there's also the networking example project - but I think it's a good idea to get a good foundation on networking first... There's probably also quite a few good Web links available (some of which are also linked from the networking section of the Unity manual, as far as I remember ;-) ).

    Hope this helps,
    Jashan
     
  4. Martin-Schultz

    Martin-Schultz

    Joined:
    Jan 10, 2006
    Posts:
    1,377
    I second PSX's request. The idea would be great for a super simple example. Although I have some experience with networking games, it helps sometimes to see a simple example and how it is done the Unity way. Anyway, some simple Pong game or so would be cool. :)
     
  5. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    Thanks Holtsch! I've already got a basic understanding of networking. My real job is centered around multi-user applications in flash/flex. Not so much game oriented, but I get the basic concepts involved when it comes to games(I think!).

    Where I'm stuck, is how to get started the Unity way. I mean, I don't understand how and where you initiate a server in a loader scene, and then keep the Network connection alive and make use of it in your game scene(s). Right now, I'm of just testing locally so I don't need to worry about all the issues that come up with connections between peers, NAT stuff, etc.

    psx
     
  6. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    Well, have you tried:

    http://unity3d.com/support/resources/example-projects/networking-example

    http://unity3d.com/support/documentation/Manual/Networked Multiplayer.html

    http://unity3d.com/support/documentation/ScriptReference/MasterServer.RegisterHost.html

    http://unity3d.com/support/documentation/ScriptReference/Network.html

    http://unity3d.com/support/documentation/ScriptReference/MasterServer.RequestHostList.html

    ("more advanced stuff")
    http://unity3d.com/support/documentation/ScriptReference/Network.TestConnection.html


    Hm... I remember also seeing one example with a GUI to connect to games registered with the master server. Ah - thank Google:

    http://unity3d.com/support/documentation/Components/net-MasterServer.html

    I guess that should get you up and running real quick "in the Unity way" ;-) ... my feeling is that this stuff is really nicely documented. RPCs accept bools and byte[] as parameters now, though (that's new in 2.0.2, docs not updated, yet).

    Does this help?

    Btw, one really cool thing about Unity networking is that you don't really ever have to worry much about NAT-stuff ;-)

    Jashan
     
  7. psx

    psx

    Joined:
    Aug 25, 2005
    Posts:
    80
    Thanks again man. I've pretty much read all of the docs and stuff, but today it finally clicked together! I almost have an example ready to post but I've got to clean it up a bit. I'll try to post it in the morning.

    psx
     
  8. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    PSX, did you ever post this little nugget?
     
  9. jamesflowerdew

    jamesflowerdew

    Joined:
    Apr 29, 2009
    Posts:
    10
    I'm finding the multiuser stuff to be a bit hellish, can anyone help?

    A geniune working example would really help.

    The Unity network examples don't work here (Vista Unity2.5).

    I'm used to the Shockwave multiuser server, so I'm used to what I guess is called "PPC" but via an online dedicated server.

    I am finding the following...

    Resgistered hosts are frequently being lost on the master server.

    Even when they are, usually clicking "connect" does annoyingly little.

    Often clicking "retest connection" will help.

    My Vista machine will (shakily) allow communication between two windows (editor-published or published-published)after a few tries but I cannot access my colleague's "server" remotely, and he can't access mine.

    Yes, my firewall is off, yes, I've read http://unity3d.com/support/resources/example-projects/networking-example etc, no, there is no point in editing my security settings any further(casual gamers aren't generally fond of configuring vista).

    On the rare occasions when it works, the "other player" game object is controlled by network views, a spawn script, and an init script and that bit works (albeit crudely).

    It is the initial connection between "server","client", and "master server" that worries me.

    Here is my code (It is a "god" script, so it's all in there...theoretically):

    //DontDestroyOnLoad(this);

    private var gameName = "whatever";
    private var serverPort = 25002;
    private var timeoutHostList = 0.0;
    private var lastHostListRequest = -1000.0;
    private var hostListRefreshTimeout = 10.0;
    private var natCapable : ConnectionTesterStatus = ConnectionTesterStatus.Undetermined;
    private var filterNATHosts = false;
    private var probingPublicIP = false;
    private var doneTesting = false;
    private var timer : float = 0.0;
    private var windowRect = Rect (Screen.width-300,0,300,100);
    private var hideTest = false;
    private var testMessage = "Undetermined NAT capabilities";
    private var plevel: String = "barracks" ;
    private var disconnectedLevel : String = "empty";
    // Enable this if not running a client on the server machine
    //MasterServer.dedicatedServer = true;

    function OnFailedToConnectToMasterServer(info: NetworkConnectionError)
    {
    Debug.Log(info);
    }
    function OnServerInitialized() {
    Network.RemoveRPCsInGroup(0);
    Network.RemoveRPCsInGroup(1);
    networkView.RPC( "OffToPlay", RPCMode.AllBuffered, plevel, lastLevelPrefix + 1);
    testMessage =("I am the server");
    }
    function OnFailedToConnect(info: NetworkConnectionError)
    {
    Debug.Log(info);
    }

    function OnGUI ()
    {
    windowRect = GUILayout.Window (0, windowRect, MakeWindow, "Server Controls");

    }

    function Awake ()
    {
    MasterServer.ipAddress = "83.221.146.11"; // Different location than the default one
    MasterServer.port = 23457;
    // If server initialize server, register host, etc
    // If client request host list, etc
    // Start connection test
    natCapable = Network.TestConnection();

    // What kind of IP does this machine have? TestConnection also indicates this in the
    // test results
    if (Network.HavePublicAddress()){
    Debug.Log("This machine has a public IP address");
    }else{
    Debug.Log("This machine has a private IP address");
    }
    DontDestroyOnLoad(this);
    networkView.group = 1;
    }

    function Update() {
    // If test is undetermined, keep running
    if (!doneTesting) {
    TestConnection();
    }
    }

    function TestConnection() {
    // Start/Poll the connection test, report the results in a label and react to the results accordingly
    natCapable = Network.TestConnection();
    switch (natCapable) {
    case ConnectionTesterStatus.Error:
    testMessage = "Problem determining NAT capabilities";
    doneTesting = true;
    break;

    case ConnectionTesterStatus.Undetermined:
    testMessage = "Undetermined NAT capabilities";
    doneTesting = false;
    break;

    case ConnectionTesterStatus.PrivateIPNoNATPunchthrough:
    testMessage = "Cannot do NAT punchthrough, filtering NAT enabled hosts for client connections, local LAN games only.";
    filterNATHosts = true;
    Network.useNat = true;
    doneTesting = true;
    break;

    case ConnectionTesterStatus.PrivateIPHasNATPunchThrough:
    if (probingPublicIP)
    testMessage = "Non-connectable public IP address (port "+ serverPort +" blocked), NAT punchthrough can circumvent the firewall.";
    else
    testMessage = "NAT punchthrough capable. Enabling NAT punchthrough functionality.";
    // NAT functionality is enabled in case a server is started,
    // clients should enable this based on if the host requires it
    Network.useNat = true;
    doneTesting = true;
    break;

    case ConnectionTesterStatus.PublicIPIsConnectable:
    testMessage = "Directly connectable public IP address.";
    Network.useNat = false;
    doneTesting = true;
    break;

    // This case is a bit special as we now need to check if we can
    // cicrumvent the blocking by using NAT punchthrough
    case ConnectionTesterStatus.PublicIPPortBlocked:
    testMessage = "Non-connectble public IP address (port " + serverPort +" blocked), running a server is impossible.";
    Network.useNat = false;
    // If no NAT punchthrough test has been performed on this public IP, force a test
    if (!probingPublicIP)
    {
    Debug.Log("Testing if firewall can be circumnvented");
    natCapable = Network.TestConnectionNAT();
    probingPublicIP = true;
    timer = Time.time + 10;
    }
    // NAT punchthrough test was performed but we still get blocked
    else if (Time.time > timer)
    {
    probingPublicIP = false; // reset
    Network.useNat = true;
    doneTesting = true;
    }
    break;
    case ConnectionTesterStatus.PublicIPNoServerStarted:
    testMessage = "Public IP address but server not initialized, it must be started to check server accessibility. Restart connection test when ready.";
    break;
    default:
    testMessage = "Error in test routine, got " + natCapable;
    }
    //Debug.Log(natCapable + " " + probingPublicIP + " " + doneTesting);
    }

    function MakeWindow (id : int) {
    GUILayout.Label(testMessage);
    if (GUILayout.Button ("Retest connection"))
    {
    Debug.Log("Redoing connection test");
    probingPublicIP = false;
    doneTesting = false;
    natCapable = Network.TestConnection(true);
    }

    if (Network.peerType == NetworkPeerType.Disconnected)
    {
    GUILayout.BeginHorizontal();
    GUILayout.Space(10);
    // Start a new server
    if (GUILayout.Button ("Start Server")){
    Network.useNat = !Network.HavePublicAddress();
    Network.InitializeServer(32, serverPort);
    MasterServer.RegisterHost(gameName, "Barracks", "qwe game for all");
    } // Refresh hosts
    if (GUILayout.Button ("Refresh available Servers") || Time.realtimeSinceStartup > lastHostListRequest + hostListRefreshTimeout){
    MasterServer.RequestHostList (gameName);
    lastHostListRequest = Time.realtimeSinceStartup;
    }
    GUILayout.FlexibleSpace();
    GUILayout.EndHorizontal();
    GUILayout.Space(5);
    var data : HostData[] = MasterServer.PollHostList();
    for (var element in data)
    {
    GUILayout.BeginHorizontal();

    // Do not display NAT enabled games if we cannot do NAT punchthrough
    if ( !(filterNATHosts element.useNat) )
    {
    var name = element.gameName + " " + element.connectedPlayers + " / " + element.playerLimit;
    GUILayout.Label(name);
    GUILayout.Space(5);
    var hostInfo;
    hostInfo = "[";
    // Here we display all IP addresses, there can be multiple in cases where
    // internal LAN connections are being attempted. In the GUI we could just display
    // the first one in order not confuse the end user, but internally Unity will
    // do a connection check on all IP addresses in the element.ip list, and connect to the
    // first valid one.
    for (var host in element.ip)
    {
    hostInfo = hostInfo + host + ":" + element.port + " ";
    }
    hostInfo = hostInfo + "]";
    //GUILayout.Label("[" + element.ip + ":" + element.port + "]");
    GUILayout.Label(hostInfo);
    GUILayout.Space(5);
    GUILayout.Label(element.comment);
    GUILayout.Space(5);
    GUILayout.FlexibleSpace();
    if (GUILayout.Button("Connect"))
    {
    // Enable NAT functionality based on what the hosts if configured to do
    Network.useNat = element.useNat;
    if (Network.useNat)
    print("Using Nat punchthrough to connect");
    else
    print("Connecting directly to host");
    Network.Connect(element.ip, element.port);
    }
    }
    GUILayout.EndHorizontal();
    }
    }else{

    if (GUILayout.Button ("Disconnect"))
    {
    Network.Disconnect();
    MasterServer.UnregisterHost();
    }
    GUILayout.FlexibleSpace();
    }
    GUI.DragWindow (Rect (0,0,1000,1000));
    }



    // Keep track of the last level prefix (increment each time a new level loads)
    private var lastLevelPrefix = 0;




    @RPC
    function OffToPlay(level : String, levelPrefix : int)
    {
    Debug.Log("Loading level " + level + " with prefix " + levelPrefix);
    lastLevelPrefix = levelPrefix;

    Network.SetSendingEnabled(0, false);
    Network.isMessageQueueRunning = false;
    Network.SetLevelPrefix(levelPrefix);
    Application.LoadLevel(level);
    yield;
    yield;
    Network.isMessageQueueRunning = true;
    Network.SetSendingEnabled(0, true);
    for (var go in FindObjectsOfType(GameObject)){
    go.SendMessage("OnNetworkLoadedLevel", SendMessageOptions.DontRequireReceiver);
    }
    }

    function OnDisconnectedFromServer ()
    {
    Application.LoadLevel(disconnectedLevel);
    }

    @script RequireComponent(NetworkView)
     
  10. HenriKay

    HenriKay

    Joined:
    Oct 2, 2010
    Posts:
    6
    I just found this. Hope it helps
     
  11. Udyrfrykte

    Udyrfrykte

    Joined:
    Feb 14, 2010
    Posts:
    156
    That's a good guide. From my experience the networking mindset takes a bit getting used to.
    Last few weeks I've created two threads and felt like I've spammed the forum because I had a problem with using RPCs. The solution? There was a script I simply hadn't deactivated for non-owner players. Pretty easy, but did not strike me as the "logical" solution.

    What worked for me was reading that guide a few times (Zero to Hero) and using the examples. Then I spent a few good hours tormenting myself by dissecting the scripts and picking out only the essentials I would need for a chatscript. (Connecting and RPCs). After that it became a bit easier.

    edit: Just realized I replied to a post that was made back when I hadn't even started scripting
     
    Last edited: Oct 12, 2010
  12. appels

    appels

    Joined:
    Jun 25, 2010
    Posts:
    2,687
    There is a very good guide here, it comes with a step by step pdf from basic networking to an authoritative setup. I found this one the easiest to follow.
     
  13. jobemakar

    jobemakar

    Joined:
    Jun 13, 2009
    Posts:
    74
    psx,

    I see jashan suggested a book. I'm not familiar with that book but I think I'm going to order it and check it out. There are two books that I would recommend that aren't Unity-specific, but cover multiplayer concepts well.

    Networked Graphics - http://www.amazon.com/Networked-Gra...=sr_1_1?ie=UTF8&s=books&qid=1286903421&sr=8-1

    and, one I wrote - it is a Flash book but is mostly concepts that apply to any language.
    ActionScript for Multiplayer Games and Virtual Worlds - http://www.amazon.com/ActionScript-...=sr_1_1?ie=UTF8&s=books&qid=1286903398&sr=8-1

    I wish you luck. I know it can be a little tough getting started.