Thursday, April 19, 2012

How to create online multiplayer HTML5 games in Contruct2

 

Construct2 can use websockets to send and receive messages between games. By using socket-io, we can use a Node.js script as the server and my modification to the socket-io plugin for Construct2 to allow the games to synchronize data between them in real-time. There are two parts to this design: the Node.js server and the Construct2 clients (the games playing).

The main part of building an online multiplayer HTML5 game is to plan:

  1. how the clients will communicate
  2. how often and what to communicate
  3. how much of the logic will go into the server and how much to the client.

In my sample game, I chose to have each client own a player and have the server just relay messages:

  1. Use string messages in the form TypeOfMessage, Parameter1, Paremeter2, Parater3, etc to communicate.
  2. Have the clients send their player position about 16 times a second. Whenever their player shoots, the client needs to send a message immediately.
  3. Almost all of the game logic will reside in the client

The Server Script

The server runs in Node.js and functions as basically a relay of messages between Construct2 clients. The server needs to run outside of Construct2 because a construct2 game cannot run as a server, i.e. it cannot use your computer to “listen” to messages. It can only connect to a websocket server (in this case Node.js) and sent/receive messages to/from it.

If you look at the source code of the example_server.js file included in my plugin, you will see that the first thing we do is to listen in port 8099:

var io = require("socket.io").listen(8099);

The next thing we do is to staet listing for connections, and if we get one, we send the connecting client an initialization message:

socket.send('I,' + mySelf[0] + ',' + mySelf[1] + ',' + mySelf[2]);

The initialization message simply tells the connecting client (the C2 game) the id of his player and the initial x and y coordinates for his player. Note that the message is just a string. I chose to make my messages sent from the server formatted in the following way:

TypeOfMessage, Parameter1, Paremeter2, Parater3, etc

The parts of the message are separated by commas. Next in the server script, we use a loop to send the connecting client the positions of each of the clients (players) already connected:

socket.send('C,' + entity[0] + ',' + entity[1] + ',' + entity[2]);

This message type is C, which means that the client has to Create a player (in this case the other clients have to create the new player that just connected). We will see later how the Constrcut2 clients interpret those messages. After the positions of the players are sent to the connecting client, we broadcast the to the clients already connected that a new client has arrived and its id and initial position (which was set by this script):

socket.broadcast.emit("message",'C,' + mySelf[0] + ',' + mySelf[1] + ',' + mySelf[2]);

Please note that the initial position is set by the server to the same position always for simplicity, however, in your game, there is no reason why you have to do this. You could have multiple random spots and just let the server assign any of those random spots.

The next part of the server script uses socket.on("message", function (data) to start listening to any messages sent by this newly connected client. This line is different from the previous io.sockets.on("connection", function (socket) in that the later line listens to connections only not messages.

Each message sent by the client can be a UM (update position) or a S message (shoot). The server splits by comma any message sent by the client, detects what kind of message is and then relays the message to all the other clients (players). Note that if th message is a UM (update position), the server will save the position so that it can send the correct position to any new client.

The Client

Each client is a Construct2 game that use the modified websocket plugin to send messages to the server (not to the other clients).

On the start of the playing layout, we connect to the Node.js server using its IP address:

image

Note that the IP address could be public or a LAN address. If public, the server (node.js) must be running in a LAN whose router redirects the 8099 to the computer running the Node.js server script.

Once connected, the client listens to messages from the server. The first message it will receive is an Initialization message:

image 

When this message arrives, C2 will create a player in the coordinates given by the server and assign the owned player the id sent by the server. Note that plugin has a special action “Split Data Received” that splits the message into its parts (element 0 is the type of message, element 1 is the ID of the player, element 2 and 3 are the X and Y positions).

The client will also receive C messages to create the other players:

image

Finally, the client will receive messages to update the position of the other players or to have the other players shoot:

image

To update the position of the own player and to notify the shooting of the own player, the Construct2 game will send messages to the Node.js server when the conditions occur:

image 

Note that it sends its player position every 0.07 seconds. Whenever their player shoots, the client also sends a message immediately.

Summary

Document_2012-04-19_11-10-04

The above picture give you a quick overview of how the parts discussed interact with each other. Please remember that you can make your message represent anything you want, e.g.: player picks up an item, player dies, etc. However keep in mind that you should limit the amount of information flowing. Choose the most basic messages that would allow your game to run parallel. For example in my sample game, I do not have a “Died” message because I am trusting that the clients are synchronized enough that if a bullet hits a player in one client, the same bullet will hit it in the other client because the bullet was created with the same position and velocity in all the clients.

There are some tips here on how to install Node.js and socket-io in your machine.

Online multiplayer takes a lot of discipline and knowledge. I strongly recommend that you start with something basic (like a pong game where you just update positions) and then move from there.

9 comments:

Taurian said...

Is there a way to handle multiple rooms? Using this method? It seems it sends the message to everyone connected to the server. This sounds like it could be a problem in the future.

Thanks,

-Ed

Juan Pablo said...

The message is sent to every player because the scope of the server is one hosted game. In other words if someone wants to host a game, he would run the server.

You could use rooms, bu that would mean that multiple games are hosted from one server. Depending on the type of game, this could put a lot of pressure in that one server.

David said...

Hey,

I got everything working and it works quite well.
But I have one problem. When a player leaves the game, their character is still there. I have tried multiple things to no avail.

Any suggestions?

Anonymous said...

Hi,

Thanks for the great guide on construct 2 multiplayer, but I seem to have hit a bit of a wall that confuses me.

When I run your example files everything works fine. When I follow your example files closely it won't work for my own game even if the cmd is following all the same steps. Was wondering if you knew of any issues with construct 2 receiving the server data via the Socket.LastDataElement(index) command as it seems to work with just the Socket.LastData command.

Sorry for troubling you but I have absolutely no idea why my own code won't connect with the game when it's extremely similar to yours for the examples purpose.

Thanks!

itza said...

hi. I did what you told me, create another game that would control the main game but not I'm doing wrong, if I'm not sending or receiving data bad bad server or if I'm doing something wrong there, that in fact I think it is. can you help me

itza said...

hi. I did what you told me, create another game that would control the main game but not I'm doing wrong, if I'm not sending or receiving data bad bad server or if I'm doing something wrong there, that in fact I think it is. can you help me

Juan Pablo Tarquino said...

Hi guys, please ask the questions in the C2 forum at http://www.scirra.com/forum/topic49587_page17.html . There are other people there that can help you if I am not available. Thank you!

Anonymous said...

When I run the server report me this error:
ReferenceError: Socket is not defined
     at Object. (C: \ Program Files \ nodejs \ example_server.js: 2:1)
     at Module._compile (module.js: 456:26)
     at Object.Module._extensions .. js (module.js: 474:10)
     at Module.load (module.js: 356:32)
     at Function.Module._load (module.js: 312:12)
     at Function.Module.runMain (module.js: 497:10)
     at startup (node.js: 119:16)
     at node.js: 901:3
Excuse for my bad English. This article translated by google translator.
Please tell me where I made ​​a mistake.
Thank you.

waqar ali said...

great tutorial.
any idea how i can link construct 2 socket.io with google app engine?