simple intro to multiplayer?

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

64561–2381–$airhockey_149.zip (474 KB)

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

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 :wink:

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 :wink: ).

Hope this helps,
Jashan

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. :slight_smile:

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

Well, have you tried:

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

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

(“more advanced stuff”)

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” :wink: … 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 :wink:

Jashan

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

PSX, did you ever post this little nugget?

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)

I just found this. Hope it helps

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

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.

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-Graphics-Building-Virtual-Environments/dp/0123744237/ref=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-Multiplayer-Games-Virtual-Worlds/dp/0321643364/ref=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.