Start typing to search...
Tutorials
Creating games on Koji
4. Updating game behavior
Search

Updating game behavior

In the previous section of the in-game purchases tutorial, you created a payment flow for the game. In this section, you’ll modify the game’s original behavior to reflect the new flow.

By the end of this section, you should feel comfortable:

  • Adding a listener for the resetLives event.

  • Modifying game elements to reflect the new flow.

  • Testing the game to make sure everything works correctly.

Adding a listener for resetLives

The base template for the game uses CustomEvents to communicate between the game instance and the main component. So, it’s a good idea to follow this pattern in the new workflow.

You’ve already added the emitEvent(resetLives) call in the onPurchase() function. Now, you need to add a listener for it.

If you go to frontend/src/Components/Game/index.js, you’ll find that there are already listeners defined in the first useEffect hook. Define your new listener here, as follows.

window.addEventListener('resetLives', resetLives);

Also, make sure to remove the listener in the return function. That way, it gets deleted when the game component unmounts. This step is important for preventing memory leaks.

window.removeEventListener('resetLives', resetLives);

You also need to define the callback function that is passed to the listener.

...
import { spawnFloatingText } from './Effects/FloatingText';
...

const resetLives = () => {
    game.lives = game.startingLives;
    game.gameOver = false;

    spawnFloatingText("EXTRA LIVES", game.width / 2, game.height / 2, {
        duration: 1,
        maxSize: 45
    });
}

This code resets the lives to the starting value and resets the game.gameOver property to false. It also spawns some floating text in the middle of the screen to celebrate this happy event.

If you’ve gone through the remixable game tutorial or are already familiar with the base game template, you could get even more creative and spawn some exploding particles. The player just spent some cash on the game — they should be rewarded!

Modifying Block.js

In the original game, when all lives are lost, the game "camera" returns to the bottom of the stack. This feature is not needed now, so it can be disabled.

In frontend/src/Components/Game/Entities/Block.js, find the handleMiss() function. It looks like this.

handleMiss() {
    this.hasMissed = true;
    playSound(game.sounds.loselife);

    const distanceFromPreviousBlock = Math.abs(this.pos.x - game.blockDesiredX);
    if (distanceFromPreviousBlock < this.size) {
        this.rotDir = Math.sign(this.pos.x - game.blockDesiredX);
        this.isRotating = true;
    }

    setTimeout(game.loseLife, 400);
    setTimeout(() => {
        if (game.gameOver) {
            moveToStart();
        }
    }, 500);
}

Remove the code that moves the camera back to the bottom, as follows.

handleMiss() {
    this.hasMissed = true;
    playSound(game.sounds.loselife);

    const distanceFromPreviousBlock = Math.abs(this.pos.x - game.blockDesiredX);
    if (distanceFromPreviousBlock < this.size) {
        this.rotDir = Math.sign(this.pos.x - game.blockDesiredX);
        this.isRotating = true;
    }

    setTimeout(game.loseLife, 400);
}

In the original game, the Game Over text was displayed in label that would slide down from the top. Since the text is now displayed in your new payment menu, you don’t need the original label.

Disable it by opening frontend/src/Components/Game/setup.js. In the game.loseGame() function, remove these two lines.

game.ui.instructionsAnimTimer = 0;
game.ui.instructionsFadeOutTimer = game.instructionsFadeOutDuration;

The modified function should look like this.

game.loseGame = () => {
    game.lives = 0;
    game.gameOver = true;
    emitEvent('gameOver', { score: game.score });
}

That’s all you need to do accommodate the new flow in your game!

Testing the game

To test the new flow before you publish the game, you can temporarily disable the payment process and just emit the resetLives event directly by modifying frontend/src/Components/View/index.js as follows.

const onPurchase = async () => {
    // Comment this for testing, skip the check
    //const purchase = await Koji.iap.startPurchase('extraLives');

    //if (purchase.receiptId) {
        setShowPaymentDialog(false);
        emitEvent('resumeGame');
        emitEvent('resetLives');

        // Submit the score just to have some backup in case
        // the player closes the game before submitting later
        if (dataManager.name !== "") {
            await dataManager.submitScore(score);
        }
    //}
}
Note
Make sure to uncomment those lines before publishing your game.

After you publish the game, you can use the Koji debugger to test the new in-app purchase feature. You’ll need to have a balance in your Koji wallet.

Note
If you are working locally, you will need to push your changes and pull them into the Koji editor before publishing. For more information, see publish-locally-developed.html.

Wrapping up

In this section, you modified the game’s original behavior to reflect the new payment flow. You’ve now built the main part of the in-game purchase experience.

In the last section, you’ll make the price customizable during remix.