zig-js
v1.6.15
Published
Embedding the ZIG client into your game is easy.
Downloads
1,799
Keywords
Readme
zig-js
Embedding the ZIG client into your game is easy.
The library is available as an npm package.
Install it and add it to your package.json
using npm install --save zig-js
.
You can then import the library and access the zig functionality.
The examples in this document make heavy use of async
/await
to handle promises.
await x(); y()
is similar to x().then(() => y())
. More information on
async function on MDN.
Changelog
You can find an overview about recent changes here.
Embedding ZIG into your game
For a quick start on how to include the zig-js
library in a game project using webpack,
see our example project
on github. The project also includes information on how to test your game integration
locally.
Loading your game
Once the game has finished loading all assets and is ready to start, you can signal
this by sending a gameLoaded
message to the parent frame. To simplify things the
ZIG client exposes a Messages
object (of type GameMessageInterface
). Only use the
Zig.Client
instance if the Zig.ready()
promise resolves.
There are two game flow modes.
Single round game In this mode the game is controlled completely from the outside. You dont need to implement any game controls. This mode does not support things like re-buy or variable stake selection.
In-game purchase flow In this mode all controls are handled by the game itself. The game is responsible to show a play button and, if required, a variable stake selector. To enable this mode, you need to add
purchaseInGame: true
to the game settings defined in yourouter.html
file.
The supported game mode can be passed as a parameter to the gameLoaded
call.
import {Zig} from "zig-js/zig/zig";
window.onload = async () => {
// wait for your game to load
await YourGame.loadAssets();
// wait for Zig.Client to initialize. Only use Client after this
await Zig.ready();
// tell parent frame that the game finished loading
const purchaseInGame = false;
Zig.Client.Messages.gameLoaded(purchaseInGame);
};
Single round games
The flow for a single round game is described in this diagram.
Once the customer decides between a real game for money or a free demo game
the parent frame sends a playGame
or playDemoGame
message back to the game.
To listen for those events the Messages
object exposes a registerGeneric
method.
Simply pass an object containing event handlers with the message types as keys.
Zig.Client.Messages.registerGeneric({
playGame() {
// the player would like to start a new game round.
// call into your game code to begin a new round.
YourGame.runGame();
},
playDemoGame() {
// the player requested a demo ticket.
// YourGame.runDemoGame()
},
});
To buy a ticket, use the Zig.Client.buyTicket
method. The method returns a
Promise
instance resolving to the ticket that was supplied by the backend system. This ticket
includes all the information about the game you need to show to the customer.
interface Ticket {
// Local id of the ticket
// This id needs to be send back with a `settle` call.
id: string;
// Some identifying alphanumeric string that does not need to be
// unique but should identify the ticket given other information like an
// approximate time or customer number
ticketNumber: string;
// The amount of money the customer payed for this ticket.
price: MoneyAmount;
// The bet factor that was used when purchasing this ticket.
betFactor: number;
// The winning class of the ticket. Use this to extract the winnings
// of this ticket. If the winnings are zero this was a loosing bet.
winningClass: {
winnings: MoneyAmount
};
// the decoded scenario object or undefined if the scenario
// field could not be decoded. Basically `JSON.parse(atob(ticket.scenario))`
decodedScenario?: any;
// this field contains optional data from the integrating platform.
// this can be used to add additional fields to the ticket payload, e.g. a
// ticket id or ticket number which is valid in the integrating platform.
customContent?: any;
}
interface MoneyAmount {
amountInMinor: number;
amountInMajor: number;
currency: string;
}
After the customer plays the game, you might want to show a dialog containing the
winnings for the purchased ticket. Once that dialog is closed by the user, you signal
the end of the game round using gameFinished()
.
const YourGame = {
async runGame() {
// get the ticket
const ticket = await Zig.Client.buyTicket();
// show the progression + outcome to the customer
await YourGame.play(ticket);
// settle the ticket and add he winnings to the customers account
await Zig.Client.settleTicket(ticket.id);
// Show a dialog to the customers displaying the winnings
await YourGame.showTicketWinnings(ticket);
// tell the parent that the game has finish
Zig.Client.Messages.gameFinished();
},
};
In case of errors, you can use the error
method on the Messages
instance, to forward any
value as an error object to the parent frame. The Zig.Client
object will already handle errors
for you, but you might want to wrap the call to your play
method in a try/catch
block like this. If you are using promises without await
, you need to call .catch(...)
.
try {
await YourGame.play(ticket);
} catch(err) {
Zig.Client.interfaces.error(err);
// YourGame.reset();
return;
}
After sending an error to the parent frame you should always reset your game frontend. For more information see error handling section.
In-game start-button and variable stakes
If the game supports variable stakes and an in-game start-button, the order of operations slightly differs. You can see the complete game flow in this diagram.
First you need to tell the parent page that your game handles
this so called in game purchase flow. You do this by passing true
to the
gameLoaded()
call as described above.
// tell parent frame, that the game finished loading,
// and that we are running in 'in game purchase' mode.
const purchaseInGame = true;
Zig.Client.Messages.gameLoaded(purchaseInGame);
Once the player wishes to enter the game, the parent frame will send a prepareGame
message
containing a parameter that tells your game, if the player wishes to play a demo games
or a series of real game. At this point, you'll show the play button and the
stake selection, if you implement a variable stake game.
Zig.Client.Messages.registerGeneric({
// [...]
prepareGame(event) {
// call your game to show/enable the stake selector.
YourGame.showStakeSelector(event.demo);
},
});
Once the player has selected the stake and you want the game to begin, the game needs
to send a buy
message containing the selected stake.
const YourGame = {
selectedStake: 2,
onStartGameClicked() {
// request the parent to start the game with the given stake.
Zig.Client.Messages.buy(YourGame.selectedStake);
},
}
The integrating frame will validate the request, check the players balance, etc and
call your game back with a normal playGame
or playDemoGame
message like in
the single game round example above. You will not get the selected stake back in the message,
so you need to hang onto the selected stake in your game while you are waiting
for the game to start. In you playGame
handler, you call the Zig.Client.buyTicket
method with a second parameter containing the stake. The same is true for your playDemoGame
handler:
await Zig.Client.buyTicket(null, {betFactor: YourGame.selectedStake})
After settling the ticket using settleTicket
, you jump back to the stake selection
screen without sending a gameFinished
message. You only send a gameFinished
message you want to leave your game using a special homescreen button.
Resume unplayed game In case that the user has an unplayed ticket, the integration will
not call prepareGame
but call playGame
directly. In that case you can go ahead
with requesting a ticket by calling Zig.Client.buyTicket
without any extra paramters.
Cancel buy request After sending a buy
message to the parent, the customer might choose
to cancel the game or may not have enought money to play the game with the selected stake.
In that case a cancelRequestStartGame
will be send to the game. You can then show the
stake selection screen again.
Zig.Client.Messages.registerGeneric({
// [...]
cancelRequestStartGame() {
// call your game to show/enable the stake selector.
YourGame.showStakeSelector();
},
});
Error handling
In case of errors, you should delegate the error handling to the parent frame.
The library will try to make sense of the error object and handle it appropriately.
You should reset your game into the initial state after an error and expect a normal
prepareGame
or playGame
message to start a new game round.
try {
// ...
} catch(err) {
Zig.Client.Messages.error(yourErrorObject);
YourGame.reset();
}
Build and release this library
This part of the documentation is only relevant for developers of the zig client.
You can build the library using npm
run shortcuts.
npm run release
Will build a new stable release. This will be automatically used by all game frontends that include the library.npm run beta
Will release a beta build and push that asdev
version to npm. While you are on a beta release, you can upload new versions without doing a real release.npm run build-upload
Uploads a new version into the dev channel, but only if you are currently on a beta release.