GX.games: How To Create Challenges For Your Games


GX.games: How To Create Challenges For Your Games

GX.games allows you to set up “challenges” for a game where players can compete to win the challenge. Each challenge has a leaderboard where players are ranked based on their score for that particular challenge.

leaderboard_main.png

The usual flow of doing a GX.games challenge goes like this:

  1. You select a challenge and hit "play"
  2. You are taken into the game, and the game is told which challenge is currently active
  3. Based on the active challenge, the game lets you do something specific and then submits your score to the challenge leaderboard
  4. You are then ranked in that leaderboard along with other players

This tutorial covers how a challenge can be created, and how you can detect which challenge is active in-game (through GML code) and submit scores accordingly.

In this guide, we’ll be creating two challenges using our Fire Jump example:

  1. Ultimate Lifesaver”: Get the highest “rescue” score. Here, the highest score will win.

  2. Hasty Jumper”: Lowest time to getting three rescues. Here, the lowest time will win.

Before continuing, make sure you have read the GX.games publishing tutorial and have uploaded your game to GX.games.

Creating Challenges on GX.games DevCloud

To create a challenge, you need to go to GX.games DevCloud, select your game and go into the “Challenges” section. Here, you can click on “Create new challenge” to get started:

select_challenges.png

Clicking on that button will open a new window where you can set the details of your first challenge. You can enter the following information:

creating_challenge.png

  1. Title: This is the title of your challenge which will be visible on the GX.games website.

  2. Data type: This controls how the score for this challenge will appear. There are two options:

    1. Integer (Points): This is a simple integer value that will be suitable for most kinds of points (e.g.: coins, kills, captures, etc.).

    2. Duration: This is a time value submitted in milliseconds (ms).

  3. Sorting: This controls how the leaderboard for this challenge will be sorted, and whether the lowest or the highest score is considered the best. There are two options:

    1. Higher is better: This means that the largest score value will win the challenge and is suitable for most kinds of points (e.g.: coins, kills, captures, etc.)

    2. Lower is better: This means that the smallest score value will win the challenge and is suitable for timed challenges, which require a certain objective to be finished in the lowest amount of time.

NOTE: The Data Type and Sorting options cannot be changed after a challenge has been created, so make sure you enter the correct details before hitting "Confirm".


For this example, we'll create a challenge called “Ultimate Lifesaver” with the data type set to “Integer (Points)” and the sorting set to “Higher is better”.

On creating the challenge, you will be taken to the details page for your new challenge where you can enter the short description and long description, and upload a “cover art” image to be used for your challenge.

ultimate_lifesaver_details_1.png

Below this you have the option to set up a "Timed challenge", meaning that your challenge will only be playable between the specified dates. This way you can set up a challenge that is only active for, say, a week, and is disabled after that.

To set up a timed challenge, you simply need to activate the "Enabled" toggle to the right and then enter the start date and end date for your challenge. (Note that this is entirely optional and can be skipped if you don't want a timed challenge.)

You will also see the Data Type and Sorting options here, however they can't be changed.

ultimate_lifesaver_details_2.png

At the top of the page, you will see options to enable or disable the challenge on your private and public game pages, and you will also see a “Challenge identifier” which will be used to identify the challenge in your game code.

challenge_publishing_details.png

Enabling the “Private challenge page” will allow you to test the challenge by opening the given URL, and enabling the “Public challenge page” will allow anyone on GXC to find and play your challenge and share it with others. You will be given a URL for the public version as well so you can test it by opening the link directly.

You can now go ahead and create the second challenge, “Hasty Jumper”, with the data type set to “Duration” and the sorting set to “Lower is better”.

create_challenge_2.png

If you go back to the Challenges section of your game now, you should see both of your challenges:

challenges_list.png

Setting Up The GX.games Library

The GX.games API Library is available on the GameMaker Marketplace, and contains the necessary functions required for interacting with challenges and user profiles on GXC. Click here to add the library asset to your account and then download it through GameMaker.

Getting The Asset

Once you have opened the asset link given above, you need to log into your YoYo Games account and get the asset:

undefined

The asset will now be added to your account and can be downloaded through GameMaker.

Installing The Asset

Open your project in GameMaker, and in the menu bar at the top, select “Marketplace” and then “My Library”.

my_library.png

This will open your asset library where you need to (1) search for “GX” and (2) download the GX.games API Library asset:

undefined

After the asset has been downloaded, you need to (3) click on the “Import” button as shown above, which will open the Import window:

Note: If you have downloaded a .yymps file directly from the Marketplace, you can drag it into the GameMaker IDE to import it.

import_window.png

Here you need to click on “Add All” and then “Import” to add all library assets to your project. You are now ready to start using the GXC library functions!

The asset also contains demo assets which serve as an example for the library. You can skip importing those assets by manually selecting the required folders in the list on the left and pressing "Add". Here is a breakdown of the asset structure so you can choose which folders to import:

  1. "GXC API": This contains assets that are required for the library to function.
  2. "Included Files": This contains the documentation file, and while it is not required for the asset to function, it is recommended to import it as it contains important information regarding the library functions.
  3. "Demo": This contains demo assets and is optional.

Please note that the asset comes with its own documentation: you need to click on the menu.png menu above the Asset Browser, select “Included Files”, click on “Open In Explorer” (or “Finder”) and open the included PDF file.

Challenge Identifiers

We need to be able to identify which challenge is currently active, and so we need to store the unique identifiers (or IDs) of our challenges in our project as variables.

For this, you can create a script (let’s call it scr_challenges) -- make sure to remove the function block -- and simply create two global variables storing the IDs of your challenges as strings:

challenges_script.png

You can get these IDs from GXC DevCloud by opening a challenge and copying the “Challenge identifier”:

get_challenge_id.png

Retrieving Challenge Information

You can now use the gxc_get_query_param() function to check which challenge is active. For this you can create a new object (or use an existing one), place it in the first room of your game, and then add the following code in its Create event:

var _current_challenge = gxc_get_query_param("challenge");

if (_current_challenge == global.ch_ultimate_lifesaver)
{
    show_message("The Ultimate Lifesaver challenge has been activated!");
}

This will retrieve the currently active challenge ID from the URL parameters and check whether it’s equal to the Ultimate Lifesaver challenge’s ID. If it is, it uses show_message() to show us a pop-up message letting us know the challenge has been activated. (Please note that this function is for debug use only and should not be used in your final game.)

If you run the game through the Opera GX target, you won’t see any messages as there is no challenge active. To test a challenge you would need to upload your game to GXC, enable a challenge and then test it through the challenge’s URL, which is not ideal for testing small changes in quick succession; so to work around this, GXC DevCloud provides you with the required URL parameters that you can use to activate a challenge locally!

Testing Challenges Locally

To test your challenges locally, you’re going to need the “query parameters” (or URL parameters) that are passed into your game’s URL when a challenge is activated. You only ever need to do this for testing challenges locally, and GXC DevCloud provides you with these parameters to make testing easier. 

Short answer: On GXC DevCloud, activate your private challenge page and copy the given query parameters; then paste them at the end of your local game link and you are good to go!

For a detailed answer, keep reading.

On GXC DevCloud, go into your challenge’s details and activate your “private challenge page”. This will show “query parameters” with a copy_icon.png copy button next to it, where you can click to copy the challenge parameters to your clipboard.

copy_parameters.png

The copied text will be similar to this:

?game=a47df7fc-4df2-45c1-90bd-76903645b094&track=13813ccd-0dda-41b6-900c-e8e2691e6430&challenge=c92f5e78-a380-49b4-8e22-d98997f558b7

These are simple URL parameters that include your game, track and challenge IDs and can be retrieved in-game using the gxc_get_query_param() function.

Activating A Challenge Locally

Now, go back into GameMaker and run your game again. When your game opens in Opera GX, in the address bar you will see “localhost:XXXX/runner.html” where “XXXX” is the game’s port. You simply need to paste your copied query parameters at the end of this link, making sure that the parameters start with a question mark (?), and then open the resulting URL.

Your final URL will look something like this:

localhost:51264/runner.html?game=a47df7fc-4df2-45c1-90bd-76903645b094&track=13813ccd-0dda-41b6-900c-e8e2691e6430&challenge=c92f5e78-a380-49b4-8e22-d98997f558b7

You can now save this link somewhere (perhaps in a Note asset in your GameMaker project) so you can simply copy and paste it into your browser whenever you want to test this challenge! (Of course, you need to have run your game from the IDE first.)

When the game starts, it will now detect the challenge ID given in the URL and show the message we programmed:

challenge_detected.png

Woohoo!

You can now repeat this process to test any challenge locally: simply go into your challenge’s details, copy the query parameters and paste them at the end of your local game link!

Submitting Challenge Score

Short answer: Upload your score at the end of your game loop using gxc_challenge_submit_score() and then check your leaderboard on your private challenge page.

For a detailed answer, keep reading. 

You can now program your game to submit a particular score value when a round ends and the appropriate challenge is active; for example:

if (gxc_get_query_param("challenge") == global.ch_ultimate_lifesaver)
{
    gxc_challenge_submit_score(global.highscore_rescue);

    // Debug only
    show_message("Score submitted for the Ultimate Lifesaver challenge!");
}

Make sure that this code runs only once when your game loop ends and is not constantly being executed in a Step event!

Note that because the gxc_challenge_submit_score() function doesn’t require you to specify a particular challenge and simply uploads the given score to whichever challenge is currently active, you can check for multiple challenges in a condition and upload the same score value if any one of those is active; for example:

var _challenge = gxc_get_query_param("challenge");

switch (_challenge)
{
    case global.ch_ultimate_lifesaver:
    case global.ch_another_similar_challenge:
    case global.ch_yet_another_similar_challenge:
        gxc_challenge_submit_score(global.highscore_rescue);
    break;

    case global.ch_coin_based_challenge:
        gxc_challenge_submit_score(global.coins);
    break;
}

The above code submits the rescue highscore for the first three challenges, and the coins value for the fourth one. You can add as many cases as you wish, to upload different values to different challenges.

Now the code examples given above would simply upload every score made to the challenge, whether it's the highest or the lowest. This is not efficient, because if the player hasn’t actually beat their own highscore then their score should not be uploaded. As a solution it is recommended to create a local highscore variable and check against it whenever your game loop ends; then only upload the player’s score if they have beat their own highscore first:

if (global.score_rescue > global.highscore_rescue)
{
    if (gxc_get_query_param("challenge") == global.ch_ultimate_lifesaver)
    {
        gxc_challenge_submit_score(global.highscore_rescue);
        show_message("Score submitted for the Ultimate Lifesaver challenge!");
    }

    // Update highscore
    global.highscore_rescue = global.score_rescue;
}

Regardless of the way you choose to upload your score, it will be entered into the challenge’s leaderboard; so go ahead and test your game locally (make sure to add the query parameters!) and submit your challenge score.

NOTE: You need to be logged into either GX.games or GX.games DevCloud through Opera GX to be able to upload a challenge score while playing the game locally.

score_submitted_message.png

You can now open your private challenge page and see the leaderboard at the bottom, which will include the scores you submitted while testing locally. You can also upload your game to GXC and share this private link with others to challenge them to beat your score!

private_leaderboard.png

There is much more that the GXC Library can do: it allows you to retrieve the user’s profile information and also accepts callbacks so you know whether your requests have been successful or whether there were any errors. To know all about this, please read the GXC documentation, which is also provided with the GXC API asset. You can find it in the Included Files of your project (or the datafiles folder in the project directory).

Second Challenge

To complete this example, we’re now going to set up our second challenge: Hasty Jumper. This will require a special set of variables and conditions as we want to upload the amount of time it took the player to get three rescues.

We’ll create a variable that stores the amount of time (in seconds) it took to reach three rescues, meaning that it will stop counting once the player has reached that score.

// Create
three_rescue_time = 0;

// Step
if (global.score_rescue < 3)
{
    three_rescue_time += delta_time / 1000; // Converted from microseconds to milliseconds
}

When the game is over, it will check whether the Hasty Jumper challenge is active, and make sure that the player has reached at least three rescues. In that case it will upload the time value to the challenge:

if (gxc_get_query_param("challenge") == global.ch_hasty_jumper)
{
    if (global.score_rescue >= 3)
    {
        gxc_challenge_submit_score(three_rescue_time);
    }
}

To test this, open the challenge’s details on GXC DevCloud, enable its private page and copy its query parameters; then test the game locally using these parameters and upload your score.

Remember, throughout the game you can always check which challenge is active, which means you can display different content based on the active challenge -- for example, when the Hasty Jumper challenge is active and the user reaches three rescues, you can display some text showing them how much time they took to get here. This way you can program feedback for GXC challenges into your game so the player immediately knows how well they did!

Clearing Scores

During development you may want to wipe all scores for a certain challenge so you can test it from scratch again, or you may want to do that before releasing the game to the public so that they have an empty leaderboard to start with. For this, DevCloud allows you to clear the scores for any of your challenges.

At the bottom of your Challenge Details page, you can click on "Clear scores" to clear the leaderboard(s) for your selected challenge.

clear_scores_button.png

This will open a menu where you can select whether you want to clear the scores for the private version, live version, or both:

clear_scores_menu.png

Summary

Once you have set up your GX.games DevCloud account, setting up challenges becomes very easy, and with the GXC Library submitting scores is also a breeze. You can now share your challenge links with your friends and compete with them to get the best scores!

Read this tutorial to create in-game leaderboards for your challenges, to display your scores the way you want.