Did you just build your board game for Android? Want to get it online? You are at the right place - let's build it together!!!
Overview
We are going to implement match-making with the Firebase Realtime Database in this article. For that, you need Firebase setup in your Android project here.
Prerequisites
Firebase users - here, we are assuming you were able to login your user into Firebase using any method. This is necessary to identify who to communicate with after the match-making is finished.
Gradle Dependencies - Add these to the
dependencies
block in your app module's grade file.implementation 'com.google.firebase:firebase-core:16.0.6' implementation 'com.google.firebase:firebase-auth:16.1.0' implementation 'com.google.firebase:firebase-database:16.0.6'
You aren't done after implementing match-making . That's cause you've only found two players that will play - but haven't implemented how their moves will propagate over the network. Check out the article on game communication.
Our model
We will use a node in the Firebase database called the game room which will store all the active challenges that users have pushed. Each user will search for existing challenges within the game room and will accept the first one found. Otherwise, the user will upload his own challenge and wait until someone accepts the challenge.
You will be able to add more features in your match-making implementation like matching based on similar performance ratings, friends, regional-bias, etc.
How the heck are we gonna implement that?
I've divided our problem into three objects:
Matcher: Finds any existing matches in the game room.
SelfChallengeManager: Manages the challenge a user uploads if Matcher fails to find any one.
SelfChallengeCanceller: Cancels the match-making process if this user doesn't wanna play anymore.
In addition, we will require a "Challenge" object that has two properties - communication node reference and the challenger's user ID (get why we need to login to Firebase now?). This object will be uploaded into the game-room by SelfChallengeManager
.
Writing our components first
Before writing our three components, we need to understand what a Firebase transaction is. We don't want two users accepting the same challenge at the same time - which would corrupt our database and make our precious users angry. Transactions come to the rescue by prevent concurrent operations on a node in the database (which will be the game room).
How does that relate to our components? - Our components will be modeled as transactions as inner classes in our 'FirebasePlayerMatchMaker' class.
We use two callback interfaces - OnMatchMadeCallback
and internally OnFailCallback
. The factory method takes a OnMatchMadeCallback
which is called whenever a match is made. The OnFailCallback
is invoked whenever MatchMaker fails to find a match.
Here, findMatch
runs on a separate thread and creates an OnFailCallback
if Matcher
doesn't find a match. In that case, we have to create a SelfChallengeManager
and run it as a transaction.
Matcher
Here, the
doTransaction()
method iterates over all the children of the game room node and searches for aChallenge
that is compatible for our user. By default,isChallengeCompat
returnstrue
, but you can change that by adding additional constraints like ratings. The first compatible challenge is then stored and the challenge node is deleted (by setting the value tonull
) in the database. Note that by deleting the node, the other player will be notified of the acceptance.SelfChallengeManager
Here, the
doTransaction
method adds a child node to theGAME_RECORD
node in our database. This is where the game moves will be communicated after the match-making. It then uploads aChallenge
to the game room and adds itself as aValueEventListener
. Whenever another user accepts the request, they will delete this node and this user will get notified as we are listening.SelfChallengeCanceller
Our code just deletes the node created in by
SelfChallengeManager
by iterating over all the game room and finding our challenge. BUT ITS INCOMPLETE!!! You (optionally) should add a feature where the this user automatically resigns from the game if the match was accepted already.
In the OnMatchMadeCallback
you provide to FirebasePlayerMatchMaker.newInstance
, you must initialize the game communication to be done in the node (by path) mGamePath
.
Yo, you've done it. Now read the article on game communication to finish up.