An API to help creators building their game for our Axis machine.
This API will allow you to use our custom controllers with a very few lines of code, and emulate them easily with your keyboard and a gamepad.
You will also be able to play around with the all the LEDS that are inside the machine.
If you want to create a multiplayer game, Axis API already has some features ready to go for you.
To increase competitivity in your game, you can also use our leaderboard system.
It's all quite simple to use and very flexible.
In order to use our API better, you need to have a good overview of what the Axis machine looks like and how it works :
All the controllers are ordered in 2 groups, each group has 1 Joystick and 5 buttons.
A button is identified by its key (A, X, I, S, W) and its group id (1 or 2).
A Joystick is identified by its group id (1 or 2).
Figure 1: Controllers
A joystick gives an analog signal between -1 and 1 on the x and y axis.
Figure 2: Joystick
npm i github:gobelins-axis/axis-api
The Axis object is a singleton that contains every method and properties you need to build your game. You should take a look at the API References for more details.
import Axis from "axis-api";
This first thing you will need to do when starting the development of your game is emulate properly the Axis machine inputs.
You can emulate button inputs easily by mapping your keyboard keys to all the buttons available on the Axis machine, using the registerKeys method :
// Map Keyboard Keys to Axis Machine Buttons from group 1
Axis.registerKeys("q", "a", 1); // keyboard key "q" to button "a" from group 1
Axis.registerKeys("d", "x", 1); // keyboard key "d" to button "x" from group 1
Axis.registerKeys("z", "i", 1); // keyboard key "z" to button "i" from group 1
Axis.registerKeys("s", "s", 1); // keyboard key "s" to button "s" from group 1
Axis.registerKeys(" ", "w", 1); // keyboard key Space to button "w" from group 1
// Map Keyboard Keys to Axis Machine Buttons from group 2
Axis.registerKeys("ArrowLeft", "a", 2); // keyboard key "ArrowLeft" to button "a" from group 2
Axis.registerKeys("ArrowRight", "x", 2); // keyboard key "ArrowRight" to button "x" from group 2
Axis.registerKeys("ArrowUp", "i", 2); // keyboard key "ArrowUp" to button "i" from group 2
Axis.registerKeys("ArrowDown", "s", 2); // keyboard key "ArrowDown" to button "s" from group 2
Axis.registerKeys("Enter", "w", 2); // keyboard key "Enter" to button "w" from group 2
// Node: It's also possible to map multiple keyboard keys for a single machine button like so :
// Axis.registerKeys(['q', 'ArrowLeft'], 'd', 1);
Of course for joystick events, it's a little bit less convenient. You will need to use a Gamepad with analog joysticks connected with USB or bluetooth.
Once you've found one you will need to create a joystick emulator instance and update it every frame to keep track of the gamepad inputs :
const gamepadEmulator = Axis.createGamepadEmulator(0); // 0 is gamepad index, often represents the first gamepad connected to your computer
function update() {
gamepadEmulator.update();
requestAnimationFrame(update);
}
update();
Then, just assign thie emulator to the joystick you want to emulate
Axis.joystick1.setGamepadEmulatorJoystick(gamepadEmulator, 0); // 0 is the joystick index of the gamepad, often the one on the left side
Axis.joystick2.setGamepadEmulatorJoystick(gamepadEmulator, 1); // 1 is the joystick index of the gamepad, often the one on the right side
You can also connect two gamepads to make it more convenient if you're creating a multiplayer game.
const gamepadEmulator1 = Axis.createGamepadEmulator(0);
const gamepadEmulator2 = Axis.createGamepadEmulator(1);
Axis.joystick1.setGamepadEmulatorJoystick(gamepadEmulator1, 0);
Axis.joystick2.setGamepadEmulatorJoystick(gamepadEmulator2, 0);
function update() {
gamepadEmulator1.update();
gamepadEmulator2.update();
requestAnimationFrame(update);
}
update();
Since we're now using gamepads, why not use gamepad buttons too... Let's do it :
const gamepadEmulator = Axis.createGamepadEmulator(0);
Axis.registerGamepadEmulatorKeys(gamepadEmulator, 0, "a", 1); // Gamepad button index 0 (PS4 X) to button "a" from group 1
Axis.registerGamepadEmulatorKeys(gamepadEmulator, 1, "x", 1); // Gamepad button index 1 (PS4 Square) to button "x" from group 1
Axis.registerGamepadEmulatorKeys(gamepadEmulator, 2, "i", 1); // Gamepad button index 2 (PS4 Circle) to button "i" from group 1
Axis.registerGamepadEmulatorKeys(gamepadEmulator, 3, "s", 1); // Gamepad button index 3 (PS4 Triangle) to button "s" from group 1
Once your properly emulated the keyboard keys with your keyboard or gamepad, you can use our button event system directly on the Axis singleton. The event payload will give you back the button key and id.
// Setup event listeners directly on the Axis singleton
Axis.addEventListener("keydown", keydownHandler);
Axis.addEventListener("keyup", keyupHandler);
const position = { x: 0, y: 0 };
function keydownHandler(e) {
const speed = 50;
// Get the current button key pressed in the event payload object
if (e.key === "a") {
const direction = -1;
position.x += speed * direction;
}
if (e.key === "b") {
const direction = 1;
position.x += speed * direction;
}
}
function keyupHandler(e) {
// Do stuffs...
}
// If needed, you can of course remove the event listeners
function destroy() {
Axis.removeEventListener("keydown", keydownHandler);
Axis.removeEventListener("keyup", keyupHandler);
}
You can also listen to button events on the button instance itself, there are two ways of accessing a button instance :
- Using the buttonManager :
const buttonA1 = Axis.buttonManager.getButton('a', 1);
buttonA1.addEventListener('keydown', () {
// Do stuffs...
});
- Using the registerKeys method that returns the instance :
const buttonA1 = Axis.registerKeys("q", "a", 1);
buttonA1.addEventListener('keydown', () {
// Do stuffs...
});
Each button has a RGB LED inside of it, you can easily set its color with our API :
const buttonA1 = Axis.buttonManager.getButton("a", 1);
buttonA1.setLedColor("red");
// You can also use RGB or hexadecimal strings
// buttonA1.setLedColor("rgb(255, 0, 0)");
// buttonA1.setLedColor("#FF0000");
This is quite useful if you want to let your user know which button he needs to use. Or if you are creating a multiplayer game, you can split the buttons between players with different colors!
Just like the buttons, you can listen to joystick events directly on the Axis singleton. The event payload will give you back the joystick id :
Axis.addEventListener("joystick:move", joystickMoveHandler);
const position1 = { x: 0, y: 0 };
const position2 = { x: 0, y: 0 };
function joystickMoveHandler(e) {
// Get the joystick id in the event payload object
if (e.id === 1) {
const speed = 50;
position1.x += speed * e.position.x;
position1.y += speed * e.position.y;
}
if (e.id === 2) {
const speed = 50;
position2.x += speed * e.position.x;
position2.y += speed * e.position.y;
}
}
Again, just like the buttons, you can also listen to events on the joystick instance itself. Joystick instances are available on the Axis singleton.
// Joystick move event on the joystick instance
Axis.joystick1.addEventListener("joystick:move", joystick1MoveHandler);
Axis.joystick2.addEventListener("joystick:move", joystick2MoveHandler);
const position1 = { x: 0, y: 0 };
const position2 = { x: 0, y: 0 };
function joystick1MoveHandler() {
const speed = 50;
position1.x += speed * e.position.x;
position1.y += speed * e.position.y;
}
function joystick2MoveHandler() {
const speed = 50;
position2.x += speed * e.position.x;
position2.y += speed * e.position.y;
}
The joystick instances are dispatching two different event types :
"joystick:move" :
It fires every frame and gives a position x,y between -1 and 1.
"joystick:quickmove" :
It fires when the x or y value reaches the minimum or maximum value. Giving back one single direction string ("left", "right", "up", "down"). This is typically useful when you want to achieve UI Navigation with the joystick.
Axis.joystick1.addEventListener("joystick:quickmove", joystickQuickmoveHandler);
function joystickQuickmoveHandler(e) {
const speed = 50;
if (e.direction === "left") position.x += speed * -1;
if (e.direction === "right") position.x += speed;
if (e.direction === "up") position.y += speed * -1;
if (e.direction === "down") position.y += speed;
}
If your building a multiplayer game, you might want to create player instances and assign them a set of joysticks and buttons, you can do that through the Axis singleton.
const player1 = Axis.createPlayer({
id: 1,
joysticks: Axis.joystick1,
// Can also be an array of both joysticks...
// joysticks: [Axis.joystick1, Axis.joystick2],
buttons: Axis.buttonManager.getButtonsById(1), // Give player 1 all buttons from group 1
});
const player2 = Axis.createPlayer({
id: 2,
joysticks: Axis.joystick2,
buttons: Axis.buttonManager.getButtonsById(2), // Give player 1 all buttons from group 2
});
Now you can use the player instances to listen to the buttons and joystick inputs :
// Use buttons from player 1
player1.addEventListener("joystick:move", player1JoystickMoveHandler);
player2.addEventListener("joystick:move", player2JoystickMoveHandler);
player1.addEventListener("keydown", player1KeydownHandler);
player2.addEventListener("keydown", player2KeydownHandler);
const positionPlayer1 = { x: 0, y: 0 };
const positionPlayer2 = { x: 0, y: 0 };
function player1JoystickMoveHandler(e) {
const speed = 50;
positionPlayer1.x += speed * e.position.x;
}
function player2JoystickMoveHandler(e) {
const speed = 50;
positionPlayer2.x += speed * e.position.x;
}
function player1KeydownHandler(e) {
// Player 1 Shooting
}
function player2KeydownHandler(e) {
// Player 2 Shooting
}
To increase competitivity you can create a leaderboard where your users will be able to save their best scores.
You can create the leaderboard instance like so :
const leaderboard = Axis.createLeaderboard({
id: "my-game",
});
Here make sure to use exactly the same id that the one you received when uploading your game to the Axis Machine, otherwise it won't work. If you haven't uploaded your game yet and want to try out the leaderboard, just use a random string, scores will be stored locally and you'll be able to use the leaderboard API just like it was in the machine.
Then you can post scores and fetch all the existing scores, they will be automatically ordered using the value key in descending order.
// Post a score
// Every score data should at least have username and value keys
leaderboard
.postScore({
username: "sergiuonthetrack",
value: 100,
})
.then(() => {
// Get all scores
leaderboard.getScores().then((response) => {
console.log(response);
});
});
If you need to show a string instead of a numerical value in the leaderboard, you can use a the key valueString
.
// Post a score
// Every score data should at least have username and value keys, valueString is an optional key
leaderboard
.postScore({
username: "sergiuonthetrack",
value: 100,
valueString: '100s', // specify that the score is in seconds
})
.then(() => {
// Get all scores
leaderboard.getScores().then((response) => {
console.log(response);
});
});
NB It's important to note that you will not be able to push any data to the database when running the game on your own machine, only the axis machine has the rights to push scores data. But on your machine we simply use localStorage api to store scores. You don't have to do anything different.
So you can now store your users scores but how will they type their usernames?
You can use our virtual keyboard :
const input = document.querySelector("input");
Axis.virtualKeyboard.open();
Axis.virtualKeyboard.addEventListener("input", (username) => {
input.value = username;
});
Axis.virtualKeyboard.addEventListener("validate", (username) => {
virtualKeyboard.close();
leaderboard.postScore({
username,
value: 100098796,
});
});
At anytime, the player can leave the game with the machine home button, when this button is pressed the player will be asked to confirm or cancel, you can handle these situations with the following events :
// Exit game events
Axis.addEventListener("exit:attempted", exitAttemptHandler);
function exitAttemptedHandler() {
pause();
}
function exitCanceledHandler() {
unpause();
}
function exitCompletedHandler() {
console.log("๐ Bye bye");
}
The Axis Machine has many LEDS connected to it, you can interact with each of them very easily:
Axis.ledManager.leds[0].setColor("rgb(255, 0, 0)");
Axis.ledManager.leds[0].setColor("red");
Axis.ledManager.leds[0].setColor("#ff0000");
All the leds instances will be ordered by groups later on.
Axis.ipcRenderer.send('led:animation', 1); // Animation index from 0 to 3
ipcRenderer
: Object
joystickManager
: instance of JoystickManager class
joystick1
: instance of Joystick class
joystick2
: instance of Joystick class
buttonManager
: instance of ButtonManager class
playerManager
: instance of PlayerManager class
players
: Array of instances of Player class
leaderboard
: Instance of Leaderboard class
virtualKeyboard
: Instance of VirtualKeyboard class
ledManager
: Instance of LedManager class
Axis.registerKeys(keyboardKeys, key, id)
: Instance of Button class
Param | Type | Description |
---|---|---|
keyboardKeys | String or Array(String) |
Keyboard keys to map to the machine button |
key | String |
The machine button key ("a", "x", "i", "s", "w") |
id | Int |
The machine button id (1 or 2) |
Axis.createPlayer(options)
: instance of Player class
Axis.createLeaderboard(options)
: instance of Leaderboard class
Axis.createGamepadEmulator(index)
: instance of GamepadEmulator class
Param | Type | Description |
---|---|---|
index | Int |
The gamepad index |
Axis.registerGamepadEmulatorKeys(gamepadEmulator, gamepadButtonIndexes, key, id)
: Instance of Button class
Param | Type | Description |
---|---|---|
gamepadEmulator | GamepadEmulator instance |
Instance of GamepadEmulator class |
gamepadButtonIndexes | Int or Array(Int) |
The gamepad buttons indexes |
key | String |
The machine button key ("a", "x", "i", "s", "w") |
id | String |
The machine button id (1 or 2) |
Axis.addEventListener(event, eventHandler)
: null
Param | Type | Description |
---|---|---|
event | String |
Event name |
eventHandler | function |
The callback function |
Axis.removeEventListener(event, eventHandler)
: null
Param | Type | Description |
---|---|---|
event | String |
Event name |
eventHandler | function |
The callback function |
keydown
keyup
joystick:move
joystick:quickmove
exit:attempted
exit:canceled
exit:completed
Coming soon
Coming soon
Coming soon
Coming soon
Coming soon
Coming soon
Coming soon
Coming soon
Coming soon
Coming soon
# install dependencies
npm install
# serve with hot reload at localhost:3003
npm run dev
No need to build manually, pushing to main triggers a build via Github Action to create the bundle file.
In main Make sure context isolation is set to false :
// main.js
const win = new BrowserWindow({
width: 1200,
height: 900,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
contextIsolation: false,
enableRemoteModule: true,
},
});
In preload.js on DOMContentLoaded event you can access the Game Axis Instance in the window and set the ipc renderer like this :
// preload.js
const { ipcRenderer } = require("electron");
window.addEventListener("DOMContentLoaded", () => {
window.__axis__.set_ipc_renderer(ipcRenderer);
});