We’ve updated our SDKs, and this code is now deprecated.
Good news is we’ve written a comprehensive guide to building a multiplayer game. Check it out!
Let’s chat about multiplayer matchmaking algorithms. In this blog post, we’ll cover how to enable multiplayer users to challenge other players. In our last two blog posts on multiplayer matchmaking, we showed you how to build random matchmaking and skill-based matchmaking.
We’ve now covered both building a multiplayer game lobby with a chatroom and the different ways we can use matchmaking to connect two different users. Here’s what we’ve covered so far:
- Part One: Series Overview and Building a Multiplayer Game Lobby
- Part Two: Adding Users and Usernames
- Part Three: Getting a List of Online Users
- Part Four: Random Matchmaking of Users
- Part Five: Skill-based Matchmaking of Users
- Part Six: Matchmaking Algorithm: Enabling Users to Challenge Other Players
- Part Seven: Create Chatrooms and Multiple Channels On Demand Tutorial
- Part Eight: Preparing for Private Chatrooms and Refactoring via Private Channels
- Part Nine: Creating Private Chat Requests with Popup Alerts
- Part Ten: JavaScript Private Chat API with Access Control
This blog post is Part Six of PubNub Developer Evangelist Ian Jennings‘s series on creating a multiplayer game with JavaScript.
You’ll first need to sign up for a PubNub account. Once you sign up, you can get your unique PubNub keys in the PubNub Developer Portal. Once you have, clone the GitHub repository, and enter your unique PubNub keys on the PubNub initialization, for example:
One User Calls Another
Matchmaking is great, but what if you want to play against a specific opponent? Let’s add the ability to challenge another online user.
This “challenge” pattern will bring us the same synchronization functionality found in many applications. There are several uses for a matchmaking algorithm: pairing two parties on a phone call, pairing a driver and passenger, or pairing users to make edits to a document in a collaborative environment. For example, the same code we’ll write today could arrange a video call for Skype or Google Hangouts or hail a cab through Lyft or Sidecar.
How to Make Users Clickable
The first thing we’re going to do is add the ability to select a user from the list of#online-users
. We’ll add a basic click handler to the user elements.
We’ll also add some additional CSS to show that the users are now clickable.
Handshake to Establish Communication
Great, now instead of just firing an alert()
on click, we’ll pubnub.publish()
our challenge. This will begin the handshake process.
Handshaking is an automated process of negotiation that dynamically sets parameters of a communications channel established between two entities before normal communication over the channel begins.
Message Types
Notice how the message
object has changed yet again. It is now one level deeper.
In the previous chapters we only had one type of message, a chat message. Every chat message would be seen by every user so we didn’t need to do much filter.
Now we have multiple types of messages being broadcast over the same channel. There are chat messages, challenge requests, and challenge responses.
This is why we standardize the message object by adding a type
property. This let’s us know how to act upon receiving different types of messages.
Message Payload
The next thing we do is add a payload
property which will act as a bucket for the rest of our message information.
Making this change to the message packet means that we need to update our old chat code triggered when a message is received. Now instead of accessing for data.username
we check if(data.type =='chat')
and then access data.payload.username
instead.
Targeting Specific Users
Now that we’ve filtered our type: 'chat'
messages, let’s handle our type: 'challenge'
messages.
Notice the target
and uuid
properties in the message object from the $new_user.click()
function above.
Since all of our messages are sent over the same channel, how do we know who is challenging who? uuid
will tell us who is sending the message, and target
will tell us who is intended to receive the message.
In addition to filtering our message based on type: 'challenge'
, we only act on messages intended for us by ensuring payload.target == me
.
Completing the Handshake
Once we receive a challenge, we’ve completed the first part of the handshake process. One user challenges another, and the other user receives the challenge.
However, it wouldn’t be fair to act upon the challenge so soon. We need to give the user who is receiving the challenge the ability to accept or deny it.
We filter upon the payload.action
to divide the types of messages again. Now, messages with type: 'challenge'
are also filtered between action: 'request'
oraction: 'response'
.
The action: 'request'
message is the first message broadcast. It is sent from uuid
totarget
.
When the target
user receives type: 'request'
, they are shown a prompt. The payload is then broadcast with type: 'response'
and “action“` equal to the result of the prompt (boolean);
Handshake Code
Check out the request and response code below.
It’s also important to note that the values of uuid
and target
in the response are the reverse of values when the request is made. It could be represented simply as:
Because challenges are public we could log all challenges to the chat room if we wanted. In this case we simply choose to ignore any challenge that is not sent to us.
If we wanted challenges to remain private, we could create private channels for each user and send challenges through them. We’ll cover private user channels later in the guide.
Matchmaking Algorithm Demo
Check out the full matchmaking algorithm demo here or embedded below. We’ll begin organizing our code in the next chapter.
See the Pen Memewarz – Challenge by Ian Jennings (@ianjennings) on CodePen.0