Multiplayer tutorial 4: real-time game

Favourite 75 favourites
Tutorial written by AshleyOriginally published on 19th, March 2014 - 4 revisions

Peer group

As with the pong example, the Peer event group is a little simpler than that of the host. Remember that Sync object creates, moves and destroys objects automatically for peers depending on what happens on the host, so we don't need to worry about that here. The Host group however will have to deal with the logic of how the objects move and interact.

There is one thing we need to do when creating objects as a peer, though. Sync object will automatically create and destroy objects, but when they are created we need to set their peerid instance variable so we can later know which peer the object represents. When Sync object creates an object, the object's On created event triggers and the Multiplayer.PeerID expression is set to the ID of the peer for whom the object is being created. This allows us to remember who the peer is. Also, as with all objects representing peers, we use the Associate object with peer action to indicate this object represents a connected peer. (This must always be done on both the host and peer sides.)

https://www.scirra.com/images/articles/mp3-ev21.png


You'll notice that event 22 is a sub-event that checks if the object being created represents the local player. If Sync object creates the object representing ourself, by default it is locked to data coming from the host and any changes will be overridden. This would mean our inputs would be laggy as they have to be sent to the host and then new data received back indicating our new position. So when our own object is created, we use the Enable local input prediction action on it. This frees it up, allowing it to move around. However it will constantly still be remembering the past few second's of movement, and checking the data from the host for the object. If it starts to deviate from the host's position - taking in to account the time delay - it will start to apply some correction. Therefore it is important that the peer is using exactly the same movement logic as the host, with the same speed, acceleration and so on.

The next event updates our client input values. Whenever the On client update trigger fires, the peer is about to send its client input values to the host, so it's time to update them. Note we pick the Peer object representing the local player in this event, so references to Peer relate to the object representing us.

https://www.scirra.com/images/articles/mp3-ev23.png


The first thing this event does is set the lookx and looky input values to the mouse position. This means the host will know where we are aiming. This updates the client input values we added in On start of layout.

Each subevent then tests if each of the five controls is being pressed, and updates the corresponding bit in the inputs instance variable. Since the inputs client input value is an 8-bit integer, it looks like this sequence of bits:

0 0 0 0 0 0 0 0 (= 0 in decimal)

The Construct 2 setbit system expression is useful for setting each bit individually. The bits are zero-based and the first bit is on the right for the purposes of this example. Therefore setting bit 4 to 1 will result in this number:

0 0 0 1 0 0 0 0 (= 16 in decimal)

We use bit 0 for left, 1 for up, 2 for right, 3 for down and 4 for shooting (holding the left mouse button). So if the player is holding up and right and shooting all at the same time, the number will end up looking like this:

0 0 0 1 0 1 1 0 (= 22 in decimal)

The host can then use the getbit expression to check which of our controls are pressed. This uses bandwidth very efficiently, since with a separate value for each control we'd need at least five bytes, requiring five times as much bandwidth for this data.

Note we're updating the inputs instance variable of the Peer object, so the last event (number 34) copies the instance variable to the client input value. We'll also need the instance variable in the next event. After the trigger event ends, the multiplayer engine will transmit the updated client input values to the host.

Finally, we've enabled local input prediction for ourselves, so we can move our own player ahead of when we move on the host. The last event in the Peer group moves us depending on our own controls. Note an important detail of this event: we check the bits set in the instance variable that we updated in On client update. As the comment describes, this is because we don't want to start moving before we have sent the message to the host saying we're holding that control. 'On client update' triggers 30 times a second by default, or every other frame in a 60 FPS game. If we started moving but sent the client update the next frame, we would make ourselves go one frame out of sync with the host, and force local input prediction to make a correction. So if the player presses a control, we actually wait until the next client update before they start to move. This input latency is hard to notice in practice, and helps ensure the movement occurs as closely as possible in sync with the host.

https://www.scirra.com/images/articles/mp3-ev35.png


Note that the Peer object's 8 direction behavior has Default controls set to No. This means none of the objects will be controllable, except where we use Simulate control. This is necessary to avoid the behavior trying to control all the peers in the game, where it would conflict with what Sync object is trying to do.

That concludes the logic specific to peers. There's still the Host and Common groups to go!

Share and Copy this Tutorial

You are free to copy, distribute, transmit and adapt this work with correct attribution. Click for more info.

Comments

5
Tedg 9,849 rep

Awesome tutorial and awesome tool :)

Wednesday, March 19, 2014 at 5:21:07 PM
0
Jayjay 19.2k rep

Thanks for this tutorial! :D

Wednesday, March 19, 2014 at 5:51:25 PM
4
superwifibattler 3,327 rep

How do you make this with a drag&drop game or a board game or something?

Wednesday, March 19, 2014 at 7:02:12 PM
6
exertia 2,625 rep

@ashley - is there a way to restrict # of players to say 2 or a predetermined number, and force additional players into a new room / game.

Wednesday, March 19, 2014 at 8:33:47 PM
1
SergioRM 6,879 rep

really interesting! thank you!

Wednesday, March 19, 2014 at 9:59:39 PM
1
rexrainbow 145.7k rep

Like @superwifibattler said, the prediction might not be useful in some cases like turned based game (board game, poker game) , could Ashley provide some hint about that?

Wednesday, March 19, 2014 at 11:15:51 PM
2
Joskin 6,089 rep

Thanks for this tutorial ! It's not easy !

@rexrainbow, what about using the messages system for cards game ?
I can try to make a simple example.

Thursday, March 20, 2014 at 9:06:27 AM
3
rexrainbow 145.7k rep

@Joskin

Yes, I know it's possible.
My idea is -
1. [peer] request a command
2. [peer] validate this command (could I run this command?)
3. [peer] if validated pass, execute this command and send this request to host

4. [host] receive command , then validate it
5. [host] if validated pass, execute this command and send this request to other peers
- if validated failed , something with that peer

6. [other peer] get validated command, execute it.

The validation function and execution function will be the same at host and peer. (peer and host will use the same function to validate command)

Thursday, March 20, 2014 at 9:34:26 AM
1
potpie1010 2,836 rep

Awesome tutorial; great feature.

There's no other game engine that's fun to use, yet is still able to produce actual games.

Multiplayer should be interesting!

Thursday, March 20, 2014 at 1:18:01 PM
1
bilgekaan 23.7k rep

Great feature and tutorial thank you!

Friday, March 21, 2014 at 11:48:30 PM
2
dynamiczny 438 rep

Is there any chance of obtaining the code for the signaling server? After all I would not like to infinitely rely on the server which I don't even have access to..

Could you provide the code so that we could set up our own signalling servers?

Tuesday, March 25, 2014 at 2:30:26 PM
1
qu0y 3,151 rep

Thank you Ashley!

Saturday, March 29, 2014 at 2:09:01 PM
1
drappdev 2,164 rep

I think i missed the section around the room size.
If i change the "Max Peers" value to 2, and then open 4 separate browser windows to the localhost:50000 address. the first 2 i login are entered into the room, whilst the 3rd & 4th are given the error "signalling error: room full".
If anyone knows how to push the extra players above the max peers into 'new' rooms. I would really appreciate the knowledge share.
Thanks

Tuesday, April 01, 2014 at 10:08:55 PM
1
AbelaNET 14.7k rep

Ashley, thanks. Great info.

Wednesday, April 02, 2014 at 8:20:19 AM
2
Wsoukkachang 1,433 rep

@drappdev The new auto-join feature should help you with your problem.

Thursday, April 10, 2014 at 3:26:15 AM

Leave a comment

Everyone is welcome to leave their thoughts! Register a new account or login.