Sign In Register

How can we help you today?

Start a new topic

Join challenge with code

Looking for a similar mechanism mechanism to Kahoot. 


Where when a player starts a new challenge is generates a 6 digit code which players can use to join the challenge.


Essentially match making on a code?



1 Comment

Hey Josh,


I have an approach for you:


What you need:


1-Create a runtime collection to save references to the generated codes, which challenges they are linked to and the time we created them(in miliseconds).

2-To customise the the Create Challenge Response Cloud code script.

3-Create an event that uses the code to search for games and join them if a game exists.

4-A way to remove used codes so future games can use them.


1 - The runtime collection.


This step is easy, simply create a runtime collection. I've named mine 'challengeCodeCollection' and you will see me make references to it in Cloud code.


Guide: https://docs.gamesparks.com/tutorials/database-access-and-cloud-storage/creating-game-collection-indexes.html


2- Customising createChallengeResponse script 


Go to Cloud Code -> Responses -> createChallengeResponse 


Add the following code:


  

//We check if the response has a valid challengeInstanceId to carry on the sequence
if(Spark.getData().challengeInstanceId !== null){
    
    //Load runtime collection where we save the code and reference to challenges
    var challengeCollection = Spark.runtimeCollection("challengeCodeCollection");
    
    //Get the challenge instance id generated
    var challengeID = Spark.getData().challengeInstanceId;
    
    //Generate random code of 000-000 format
    var code = randomCode();
    
    //If we did not get a valid code after 1000 attempts then force an error
    if(code === null){
        Spark.setScriptError("error", "NO VALID CODE CAN BE GENERATED")
    } else{
        var date = new Date();
        //Create new entry in collection for players to search and join
        challengeCollection.insert({"_id":{"$oid":challengeID},"code": code,"creationTime":date.getTime()})
        //Return the code to the player
        Spark.setScriptData("code", code);
    }
    
}

//Function to create number
function randomCode(){
	//Create a code, if this code is not valid (used already) keep trying for 1000 times, if none are valid, return null to be used to create an error message back
    for(var i = 0; i < 1000; i++){
        //Generate two 3 character long ints
        var firstThree = ("00" + Math.floor(Math.random() * 1000).toString()).slice(-3);
        var secondThree = ("00" + Math.floor(Math.random() * 1000).toString()).slice(-3);
        
        //Combine ints to form game search code
        var codeGen = firstThree + "-" + secondThree;
        
        //Is there any other game using this code right now?
        var potentialMatch = challengeCollection.findOne({"code": codeGen});
        
        //If not, break while loop by returning code
        if(potentialMatch === null){
            return codeGen;
        }
        if(i >= 999){
            return null;
        }
    }
}

  

The reason we have this code in the challenge creation response is because when the player has successfully created a challenge, they receive a valid challenge instance id. This is a good place to verify that the player has a valid challenge.  We can then save the id, the code and the timestamp in our challenge and code runtime collection.


3- Our join event


Because our players dont know the challenge instance id the joinChallengeRequest is pointless to use, so we need to create a custom event that uses the code to:

-Find our game through searching the challenge and code runtime collection 

-Retrieve the challenge instance id

-Invoke a joinChallenge request for us through Cloud code


The event will have one string attribute and for our example we name this attribute : 'code'


Here's the event's Cloud code:


  

//Get code from input
var code = Spark.getData().code

//Find game
var challengeOBJ = Spark.runtimeCollection("challengeCodeCollection").findOne({"code": code},{_id : 1});
var challengeID = challengeOBJ._id.$oid;

//If game does not exist, return error
if(challengeID === null){
    Spark.setScriptError("error", "NO GAME CAN BE FOUND")
} 
//If game exists, join it and return response as scriptData
else{
    //Create a join challenge request via code
    var joinRequest = new SparkRequests.JoinChallengeRequest();
    
    //Set the id``  ` of the challenge we wish to join
    joinRequest.challengeInstanceId = challengeID;
    
    //The sending happen here at .send()
    var joinResponse = joinRequest.Send()
    
    //If error is null or unidentified return the result of the request otherwise return the error
    if(joinResponse.error == null){
        Spark.setScriptData("joined", joinResponse.joined);    
    } else{
        Spark.setScriptError("error", joinResponse.error)
    }
    
}

  

4- Removing old entries to allow new games to re-use the code


This can be done in a few ways:


A) Having a daily script remove any entry older than 24 hours (Can be anytime, 24 hours is an example).

     - one con to this is that your code can no longer be used to join that game after set time.

B) When a game is concluded the entry is removed.

     - One con to this is that if the game is never concluded, the code is never re-used.


FOR BOTH METHODS YOU'RE GOING TO HAVE TO ADD THE CODE IN METHOD B FOR THE GLOBAL MESSAGES SCRIPTS OF:

challengeExpiredMessage

challengeLapsedMessage

challengeWithdrawnMessage


For method A, have the following code in your daily script found in Cloud Code -> system -> every day:


 

//Load our challenge and code collection
var challengeCollection = Spark.runtimeCollection("challengeCodeCollection");
//Create a date stamp
var date = new Date();
//Time stamp 24 hours ago by substracting the miliseconds equal to 24 hours
var timestamp = date.getTime() - 86400000;

//Remove any entry that has a creation timestamp of less than the timestamp we set above
//$lt is the 'less than' operator
challengeCollection.remove({"creationTime": { $lt: timeStamp }})

 

For method B you will have to place the following code in the Global Messages (Cloud Code -> Global Messages) versions of:


-challengeWon (Or challengeLost, not both at the same time because we want the logic to only run once)

-challengeDrawn (Ensure its the Global messages version to avoid duplication)


 

//Get challenge instance id
var challengeID = Spark.getData().challenge.challengeId;
//Load collection
var challengeCollection = Spark.runtimeCollection("challengeCodeCollection");

//Remove code entry for this challenge to be re-used
challengeCollection.remove({"_id":{"$oid":challengeID}})

 

^^^^^^^^^^^^^

ADD THE ABOVE CODE FOR THE GLOBAL MESSAGE VERSION OF:


challengeExpiredMessage

challengeLapsedMessage

challengeWithdrawnMessage


This will ensure that if the challenge is expired, lapsed or withdrawn we make the code available for re-use. It is important to leave the code in the Global version of the message because we only want to run it once. The global version is the server version of the call that only executes once.


I hope that is is comprehensive and easy enough to follow for your need, as always we are around to help so let us know your feedback. I will make this a tutorial in the doc site for other devs to benefit from it, Thank you for your question and bringing it to our attention!


Cheers,

Omar




Login to post a comment