In this tutorial, you will learn how to create a simple 2-player network game, where two sprites move around a layout and try to collect the most objects.
Before we start, please note that this tutorial is only meant to demonstrate the basic features of the Multiplayer object, and does not include features such as interpolation, lag compensation, logging messages, or efficient data transmission (for example, encoding input data by setting individual bits of a variable). All of these topics are discussed in Ashley's excellent multiplayer tutorials, starting with http://www.scirra.com/tutorials/892/multiplayer-tutorial-1-concepts , so please be sure to read his tutorials as well when you are ready to move beyond the basics.
The core idea:
Every multiplayer game has a Host, whose version of the running program handles the majority of the game logic: sprite movement, collisions, etc. The other players are Peers, which transmit input data (such as keypresses) at regular intervals to the Host, who will then move the Peer's sprite accordingly (for example, by simulating actions in the 8-Direction behavior) on the Host computer, and then synchronize these objects with each of the peers.
On the start of the layout, you will need to establish the following:
* What data is being sent from the Peer to the Host? (At the least, this should include keypress data.) We do this with the Multiplayer's Add Client Input Value action. You will need to choose a name for each variable, determine the type of precision (to send true/false data such as key presses, "Very low" (1byte) precision is sufficient), and choose whether or not values should be interpolated (for keypress data, you want to select "None").
* What data is being sent from the Host to the Peer? Typically, this will include any sprites which move or are controlled by the players, or any sprites which may be created/destroyed (such as items which will be collected). This is accomplished with the Multiplayer's Sync Object action. This action also allows you to choose if you need position or angle (or both) to be synchronized; generally, the less data you synchronize, the less lag the players will experience. Additionally, if objects have instance variables that need to be synchronized, this may be specified with the Multiplayer's Sync Instance Variable action. Finally, note that objects such as backgrounds or GUI elements typically don't need to be synced in this manner.
Later on in the event sheet, there will be two separate Groups of code, one containing events that should be processed by the host computer (such as moving sprites), the other containing events to be processed by the peer computer (such as send key input data). At the start of the layout, both groups should be deactivated, and the appropriate group can be activated later (when each computer determines if it is the Host or a Peer).
Finally, you will need to run the Multiplayer action: Connect to Signalling Server.
After the "connect to signalling server" action completes, a series of event triggers will occur, after each of which you will need to take the appropriate next step in the setup process.
* Condition: Multiplayer, On Signalling Connected. At this point, the program is ready to log in to the server. In this simple multiplayer game, we will not allow users to choose their alias name, and instead we can just use the same text (such as "Player") for everyone; if more than one user has the same alias, the server will append a number to the alias (e.g. "Player2", "Player3") to be able to tell them apart.
* Condition: Multiplayer, On Signalling Logged In. At this point, we are ready to join a room, which enables the program to find other players. The easiest way to do this is to use the Multiplayer Auto-Join Room action. In this action you can specify the name of your game, instance, and room, as well as how many people can play this game at a time (we'll just use 2 for this simple example). It is very important to give your program a unique game name, to avoid very different programs trying to connect to each other. To increase the probability of uniqueness, for example you could use some combination of your name, the name of your project, and a random number.
* Condition: Multiplayer, On Signalling Joined Room. At this point, the program has determined if it is the Host (first to join the room) or if it is a Peer (everyone else). Here you can use a subevent with the condition Multiplayer: Is Host (at which point you would activate the Host Group of events). This should be followed by an Else condition, which will be true for non-Hosts, a.k.a. Peers (at which point you would activate the Peer Group of events). Also at this point, Peers should destroy all instances of objects which are being synchronized by the Host, as the Host will broadcast its own copies of these objects to all the Peers. (Failure to destroy these instances will result in inert local copies of objects in the Peers' running programs.)
* Condition: On Peer Connected. At this point, the Host needs to store the ID of the Peer(s), which will be important when the host queries the values of the client input values, which were created in the On Start of Layout event. Since there is only one peer to keep track of in this game, this is most easily accomplished by storing the value of Multiplayer.PeerID in a global variable.
Peer Group events
In this group of events, on every tick you will want to run the actions that set the default for each of the client input state variables to 0 (which we will use to indicate that a key is not being pressed). Then you should create an event whose condition is Multiplayer: On Client Update, followed by a series of events for each key that might currently be held down. In each of these events, you can use the Multiplayer action Set Client Input State, then list the name of the variable (which were declared in the On Start of Layout event) and its new value of 1 (which we will use to indicate that a key is being pressed).
Additionally, since this game contains sprites moving around a layout that is larger than the window size, each player has a Scroll To behavior that is disabled by default; in this set of events, the Scroll To behavior is enabled for the Peer-controlled sprite.
Host Group events
In this group of events, we need to determine the values of the Peer's client variables and move the Peer sprite accordingly. (In this example, the Host sprite is controlled by the 8-direction behavior.) To check the values of the Peer variables, you can use the System action Compare Two Values, and use the Multiplayer.PeerState function, which takes two inputs: the ID of the peer (this is why we needed the host to store this information into a variable earlier), and the name of the variable.
Also in this group of events, you would handle events such as collisions. In this sample game, each player is trying to collect the greatest number of items. When a player/item collision occurs, the Host updates the corresponding instance variable in the player's sprite, and this data is then sent to each Peer (as we established this in the On Start of Layout event).
"Both" Group events
We also want to synchronize the GUI elements, which keep track of the scores of each player. This cannot be accomplished by synchronizing the text object, because that just tracks the position (and angle) of these objects, not the text they contain. Instead, each player's score is stored (and synchronized) within the corresponding sprite, and both the players update their GUI Text objects via the event in what I've called the "Both" Group (which remains active for both the Host and the Peers).
Testing Multiplayer projects from a single computer
To test multiplayer projects from a single computer, here's what has worked for me: after saving your project, click the Run Layout icon and your project should open in a web browser with a "local" address such as localhost:50000. Then open another instance of Construct 2, open your project in this program as well, and click the Run Layout icon; your project should open in a web browser with a different local address, such as localhost:50001. Then you could adjust the sizes of the two browser windows so that they are side by side; whichever window has focus will be controlled by the keyboard, and you should see the changes happening simultaneously in the inactive window as well.