Skip to content

GameMaker

To get started, download the sample project. To avoid weird browser behaviour, right click the link, select Save link as.

Customizing index.html

Installing the SDK

To begin, let's install the SDK by inserting a <script> tag into your game's index.html file. The easiest way to do this is to copy the HTML file that Game Maker outputs, modify it, and then include that copy as a custom HTML file.

  1. In Game Maker Studio 2, Compile your HTML build.
  2. Unzip the zip file that Game Maker creates for you.
  3. In the unzipped files, find index.html. It should be in the root.
  4. Make a copy of the index.html and move the copy to PROJECT_FOLDER/datafiles/ (where PROJECT_FOLDER is the root directory of your project). If your project does not have a /datafiles/ folder create it first.
  5. Open your newly copied /datafiles/index.html in a text editor.
  6. Insert the following somewhere in the <head>...</head> container:
    <!-- CrazyGames -->
    <script src="https://sdk.crazygames.com/crazygames-sdk-v1.js"></script>
    
  7. Save the changes you've made to PROJECT_FOLDER/datafiles/index.html.
  8. In Game Maker Studio 2, from the Asset Browser panel, open Quick Access > Game Options > HTML5. HTML5 Options
  9. Under General > Advanced where it says "Included file as index.html", change the dropdown selection from "Use Default" to "index.html". If "index.html" does not appear in the list, close and reopen the Game Options > HTML5 dialog.
  10. Now your game will be using your custom index.html that contains the modifications.

Setting up banner containers

You can further customize index.html if you wish to display banner ads. You would create a <div> container for each banner ad, describe its size and placement using CSS, then show and hide them through GML code. Here is a basic example of having two banners in your game:

  1. Insert the following just before the closing </body> tag:
    <div class="crazy_banner hidden" id="crazy_banner_1"></div>
    <div class="crazy_banner hidden" id="crazy_banner_2"></div>
    
  2. The crazy_banner class is required. (Later on, we will import a JS extension that depends on this class name for querying all banner containers.)
  3. Insert the following, just before the closing </style> tag:
    .crazy_banner {
      display: block;
      position: absolute;
      background: #00f; /* remove this line when you are done testing size and placement */
    }
    #crazy_banner_1 {
      top: 0;
      left: 0;
      width: 300px;
      height: 250px;
    }
    #crazy_banner_2 {
      top: 0;
      right: 0;
      width: 300px;
      height: 250px;
    }
    .crazy_banner.hidden {
      display: none;
    }
    
  4. To preview their size and placement, remove the hidden class from the <div class="crazy_banner hidden"> containers (remember to add them back after). You can customize their size and placement by modifying the CSS as you wish.
  5. The IDs and their corresponding selectors can be renamed as you wish, but this guide will refer to them as crazy_banner_1 and crazy_banner_2.
  6. When you are done previewing size and placement, remove the background: #00F; declaration from the .crazy_banner selector, and add the hidden class back to your <div class="crazy_banner"> containers.
  7. Now that you've set up your containers, you can fill them with ads during gameplay using GML (covered later on).

Import the JS extension

Next, you'll need to import a JS extension so that you can call JS functions directly in your GML code.

  1. Download this sample project (right click the link, select Save link as) and double-click to open it. It should open automatically in Game Maker Studio 2.
  2. A save dialog will open. Select a temporary location, such as the root folder where you keep your game projects.
  3. In Game Maker Studio, in the Asset Browser panel:
    1. Right-click on any folder or asset.
    2. Click Add Existing. HTML5 Options
    3. Navigate to where you unzipped the sample project and find the /extensions/crazygames/ folder.
    4. Select (open) the yy file.
    5. The extension should now be installed in your game.

GML implementation

Testing

You can test your progress at any time in Game Maker's debug mode.

Implementing a sitelock

A sitelock is a mechanism that deters third parties from stealing and reuploading your game to other websites and monetizing it without your permission. We currently do not have a sitelock for GML games, but what you can do is write some code that prevents your game from loading if it detects that it is hosted on a domain that is not approved.

Include the following code as early as possible in your game.

domain = url_get_domain();
if (
    !debug_mode &&
    string_pos( ".crazygames.", domain ) == 0 &&
    string_pos( ".1001juegos.com", domain ) == 0
){
    game_end();
}

When testing your game, remember to use debug mode to bypass your sitelock.

Note: string_pos() returns the position where a substring is found. It treats the first position as 1 and returns 0 if the string is not found.

Alternatively, instead of simply calling game_end(), if you like, you can display some instructions to the player to help them find your game. But that is up to you.

Initializing the SDK

Initialize the SDK by calling crazy_init() as early as possible in your game code. This also installs what is called event listeners, which allows your game to detect live events like when an ad break has started playing, or if an adblocker was detected upon initialization.

Receiving and handling events

To respond to browser events directly in your game, you can use a callback function. Create a script resource, named, for example functions, to contain the following function template:

function gmcallback_crazy_callback( _event ){
    if ( _event == "crazy.break.started" ) {
    } else if ( _event == "crazy.break.error" ) {
    } else if ( _event == "crazy.break.finished" ) {
    } else if ( _event == "crazy.banner.rendered" ) {
    } else if ( _event == "crazy.banner.error" ) {
    } else if ( _event == "crazy.adblock.detected" ) {
    } else if ( _event == "crazy.sdk.initialized" ) {
    }
}

You would write your code to execute in the case of each event. An example with the template filled in can be found at the end of this guide.

Note: The function name must be exactly gmcallback_crazy_callback for it to work.

Ad breaks

Guidelines for Advertisements

Please be sure to read our advertisement guidelines, since your game will be rejected without any feedback if it doesn't follow them.

Playing an ad break

Ad breaks can be requested using crazy_break(). When this is called, an overlay will be displayed on top of your game, as the ad is being loaded. We support two different types of ad breaks: midgame and rewarded.

Midgame advertisements can happen when a user died, a level has been completed, etc. Rewarded advertisements can be requested by the user in exchange for a reward (An additional life, a retry when the user died, a bonus starting item, extra starting health, etc.). Rewarded ads should be shown only when users explicitly consent to watch an advertisement.

By default crazy_break() shows a midgame advertisement. crazy_break() has an optional argument that indicates the ad type. You can request both types as follows:

crazy_break("midgame");
crazy_break("rewarded");

Info

If it was less than 3 minutes since the last midgame ad, then a midgame ad will not show. This is automatically handled by the SDK and it is not necessary to implement your in-game timer to manage this.

Pausing audio during ads

Ad breaks are displayed as an overlay on top of your game. Your game continues running in the background. To ensure that the game does not interfere with the advertisement, your sound must be muted when the ad starts and turned back on when it has stopped. You can do this by customizing the gmcallback_crazy_callback() function.

The three kinds of events are:

  • "crazy.break.started" is emitted when an advertisement starts playing.
  • "crazy.break.finished" is emitted when an advertisement stops playing.
  • "crazy.break.error" is emitted when an error has occurred, or the ad wasn't filled. This event is also emitted when no advertisement is available.

Ad banners

There are two types of banners: standard banners, and responsive banners.

Standard banners

Standard banners are fixed-size banners that you choose according to your container size. Available sizes are:

  • 728x90
  • 300x250
  • 320x50
  • 468x60
  • 320x100

You can request one or more banners using the crazy_request_banner() function which takes one argument of type string, provided as a JSON string. In the following example, we first create args, an array of structs, where each struct is a single banner request. And then we convert args into a JSON string using json_stringify(); to pass into the function.

In the struct, containerId corresponds to the id attribute of the container you wish to request a banner for and size corresponds to its size. Here is an example of requesting and showing one standard banner:

args = [
    {
        containerId: "crazy_banner_1",
        size: "320x50",
    },
    {
        containerId: "crazy_banner_2",
        size: "300x250",
    },
];

args_json = json_stringify( args );
crazy_request_banner( args_json );

crazy_show_banner("crazy_banner_1");
crazy_show_banner("crazy_banner_2");
  • You can display up to two banners of each size at the same time at once (ex: 728x90 and 300x250, two 300x250, ...), we ask you to make a reasonable usage of banners in order not to deteriorate the player's experience.
  • You can refresh the banner displayed in a container simply by re-executing the banner request. You'll have to wait a minimum of 60 seconds before refreshing a container. You can do a maximum of 60 refreshes per container for a game session.
  • The banner has to be fully inside the game window and not overlap any UI element.
  • If you want to display multiple banners on a screen, you must request them at the same time.

Responsive banners

The responsive banners feature will requests ads that fit into your container, without the need to specify or select a size beforehand. The resulting banners will have one of the following sizes: 970x90, 320x50, 160x600, 336x280, 728x90, 300x600, 468x60, 970x250, 300x250, 250x250 and 120x600.

Only banners that fit into your container will be displayed, if your container cannot fit any of these sizes no ad will be rendered. The rendered banner is automatically vertically and horizontally centered in your container.

You can request one or more banners using the crazy_request_responsive_banner() function which takes one argument of type string, provided as a JSON string. We first create args, an array of strings, where each string corresponds to the id attribute of the container. And then we convert args into a JSON string using json_stringify(); to pass into the function.

args = ["crazy_banner_1", "crazy_banner_2"];
args_json = json_stringify( args );
crazy_request_responsive_banner( args_json );

crazy_show_banner("crazy_banner_1");
crazy_show_banner("crazy_banner_2");
  • You can refresh the banner displayed in a container simply by re-executing the banner request. You'll have to wait a minimum of 60 seconds before refreshing a container. You can do a maximum of 60 refreshes per container for a game session.
  • The container has to be fully inside the game window and not overlap any UI element.
  • If you want to display multiple banners on a screen, you must request them at the same time

Clearing the banners

You can clear all banners with:

crazy_hide_all_banners();

To clear a single banner, use the crazy_hide_banner() function, which takes 1 argument of type string:

crazy_hide_banner( containerId );

For example:

crazy_hide_banner( "crazy_banner_1" );

Game loading

We provide functions that enable us to track when and how long the loading of your game takes.

The crazy_sdk_game_loading_start() function has to be called whenever you start loading your game.

The crazy_sdk_game_loading_stop() function has to be called when the loading is complete and eventually, the gameplay starts.

// Your game starts loading
crazysdk.sdkGameLoadingStart();

// Loading...
crazysdk.sdkGameLoadingStop();

// Next level's assets are loading now
crazysdk.sdkGameLoadingStart();

// Assets are loaded
crazysdk.sdkGameLoadingStop();

Gameplay

We provide functions that enable us to track when and how users are playing your games. These can be used to ensure our site does not perform resource-intensive actions while a user is playing.

The crazy_gameplay_start() function has to be called whenever the player starts playing or resumes playing after a break (menu/loading/achievement screen, game paused, etc.).

The crazy_gameplay_stop() function has to be called on every game break (entering a menu, switching levels, pausing the game, ...) don't forget to call crazy_gameplay_start() when the gameplay resumes.

// Main menu, user clicks start
crazy_gameplay_start();

// Level is over, displaying switching level screen
crazy_gameplay_stop();

// Next level starts
crazy_gameplay_start();

// The player is pausing the game by looking into the menu
crazy_gameplay_stop();

// The player closes the menu and gets back to the game
crazy_gameplay_start();

Happy time

You can call the crazy_happy() function on player achievements, it will possibly adapt the website to celebrate by playing an animation in the browser!

Use this feature sparingly. The celebration should remain a special moment.

// Player beats a boss, reaches a high score, etc.
crazy_happy();

// Player finishes a level, get an item, etc.
// No need to celebrate

This feature lets you share the Crazygames version of your game with the players and invite them to join a multiplayer game. You can call crazy_invite_link() with a map of parameters (as a JSON string) that correspond to your game or game room.

In the following example, we first create struct args which holds various key-value pairs, which you can modify to suit your needs. And then we convert args into a JSON string using json_stringify(); to pass into the function, and store the invite link in the variable invite_link which you can use as needed.

args = {
    roomId: 12345,
    gameMode:"pvp",
    duration: 60,
};
args_json = json_stringify( args );
invite_link = crazy_invite_link( args_json );

You can retrieve any parameter from the invite link with the following code:

room_id = crazy_get_invite_param( "room_id" );

Adblock detection

We detect whether the user has installed an adblock tool. We pass this information to the developer through the SDK. The adblock detection is executed when crazy_init() is called. You will have to implement an event listener on "crazy.adblock.detected" which is fired when the adblock detection finished running. See the example at the end of this guide.

User information

The extension will return a userInfo object via the "crazy.sdk.initialized" event. Game Maker Studio will convert it into a struct, and you can access its variables to customize your game. Here is a sample of its contents:

userInfo: {
    countryCode: "FR", // ISO 3166-1 alpha-2 country code

    // For browser and os, format is the same as https://github.com/faisalman/ua-parser-js
    browser: {
        name: "Chrome",
        version: "87.0.4280.141"
    },
    os: {
        name: "Windows",
        version: "10"
    },
    device: {
        type: "desktop" // possible values: "desktop", "tablet", "mobile"
    }
}

Refer to the gmcallback_crazy_callback() function in the example at the end of this guide, in particular, the code that runs if _event == "crazy.sdk.initialized". In the example, it is stored in a variable global.user_info. So for example, you could access the browser value by referencing global.user_info.browser.

Full example

The sample project shows a full example of displaying ads in Game Maker Studio 2, written in GML. This is a very basic project that uses:

  • one object, mgr_game, that has been placed in the starting room,
  • a script, functions, and
  • a sound resource, bgm_main (to test pausing/resuming of audio). Courtesy of Rafel Krux and used under a Creative Commons license.

To test the SDK:

  • Press enter to trigger a midgame ad break. You should see an overlay for a few seconds.
  • Press space to trigger a rewarded ad. You should see an overlay for a few seconds.
  • Press esc to trigger show/hide banner ads.
  • Press P to see the invite link. Copy the parameters (from "?" until the end) and append them to the end of the URL in your address bar and go to that URL. Once your game loads, you can now press L to test retrieving the value for the key "roomId".
  • Press U to see the userInfo contents.

mgr_game (object)

/// CREATE EVENT

domain = url_get_domain();

if (
    !debug_mode &&
    string_pos( ".crazygames.", domain ) == 0 &&
    string_pos( ".1001juegos.com", domain ) == 0
){
    game_end();
}

crazy_init();

global.ad_is_playing = false;
global.rewarded_requested = false;
global.show_banner_ads = false;
global.ad_blocker_detected = false;

if ( !variable_global_exists("user_info") ) {
    global.user_info = noone;
}

audio_play_sound( bgm_main, 0, true );
/// STEP EVENT

if ( !global.ad_is_playing ) {

    if ( keyboard_check_pressed( vk_enter ) ) {

        crazy_break("midgame");

    } else if ( keyboard_check_pressed( vk_space ) ) {

        global.reward_requested = true;
        crazy_break("rewarded");

    } else if ( keyboard_check_pressed( vk_escape ) ) {

        if ( global.show_banner_ads ) {

            global.show_banner_ads = false;
            crazy_hide_all_banners();

        } else {

            global.show_banner_ads = true;

            args = [
                {
                    containerId: "crazy_banner_1",
                    size: "320x50",
                },
                {
                    containerId: "crazy_banner_2",
                    size: "300x250",
                },

            ];
            args_json = json_stringify( args );
            crazy_request_banner( args_json );

            crazy_show_banner("crazy_banner_1");
            crazy_show_banner("crazy_banner_2");

        }

    } else if ( keyboard_check_pressed( ord("P") ) ) {

        args = {
            room_id: 12345,
            game_mode:"pvp",
            duration: 60,
        };
        args_json = json_stringify( args );
        invite_link = crazy_invite_link( args_json );

        show_message( "Invite link:\n" + string(invite_link) );

    } else if ( keyboard_check_pressed( ord("L") ) ) {

        room_id = crazy_get_invite_param( "room_id" );
        show_message( room_id );

    } else if ( keyboard_check_pressed( ord("U") ) ) {

        show_message( "global.user_info:\n" + string(global.user_info) );

    }
}

functions (script)

function gmcallback_crazy_callback( _event, _output ){

    if ( _event == "crazy.break.started" ) {

        global.ad_is_playing = true;
        audio_pause_all();

    } else if ( _event == "crazy.break.error" ) {

        global.ad_is_playing = false;
        if ( global.reward_requested ) {
            global.rewarded_requested = false;

            // Tell the player there was an error loading the ad, that
            // they should try the action again to request their reward.

        }
        audio_resume_all();

    } else if ( _event == "crazy.break.finished" ) {

        global.ad_is_playing = false;
        if ( global.reward_requested ) {
            global.rewarded_requested = false;

            // Code to grant reward to player would go here.

        }
        audio_resume_all();

    } else if ( _event == "crazy.banner.rendered" ) {

        // The banner rendered successfully.

    } else if ( _event == "crazy.banner.error" ) {

        // The banner request failed, so let's try again.

        args = [
            {
                containerId: "crazy_banner_1",
                size: "320x50",
            },
            {
                containerId: "crazy_banner_2",
                size: "300x250",
            },

        ];
        args_json = json_stringify( args );
        crazy_request_banner( args_json );

        crazy_show_banner("crazy_banner_1");
        crazy_show_banner("crazy_banner_2");

    } else if ( _event == "crazy.adblock.detected" ) {

        // An ad blocker was detected.
        global.ad_blocker_detected = true;

    } else if ( _event == "crazy.adblock.notDetected" ) {

        // An ad blocker was NOT detected.
        global.ad_blocker_detected = false;

    } else if ( _event == "crazy.sdk.initialized" ) {

        // The SDK was initialized. Get the user_info object.
        global.user_info = json_parse(_output);
        show_debug_message( global.user_info );

    }

}