A small package that will help making ts/js discord bot mini games way easier! (placeholder for game example)
npm i disgamekit
- Game Class
- Plane Class
- PlaneObject Class
- ComplexPlaneObject
- All classes exmaple
- Turns Class
- Player Class (Turns)
The Game class represents a simple game controller with start, end, and error handling functionality. It manages the overall state of the game and provides methods to start, end, and handle game events.
id
: The unique identifier for the game.
const { Game } = require('disgamekit');
const game = new Game('gameId');
Starts the game and emit's the "start" event.
game.start();
Returns game's current state
console.log(game.isGameOn()); // false
game.start();
console.log(game.isGameOn()); // true
Ends the game and emit's the "end" event.
interaction
:(optional) Interaction associated with the gamecustom
:(optional) Pass a custom string to be sent to the event listener.plane
:(optional) Pass the plane to be reset.
game.start();
console.log(game.isGameOn()); // true
game.end(interaction); // so that when the end event is emitted you can edit an embed or do something to a message.
console.log(game.isGameOn()); // false
Fired when the game starts
const { Game } = require('disgamekit');
let game = new Game('game');
game.on('start', () => {
console.log('Game sucessfully started!');
});
Fired when the game ends
const { Game } = require('disgamekit');
let game = new Game('game');
game.on('end', () => {
console.log('Game ended!');
});
game.end();
// If you have a component to end the game, you can edit the reply one last time.
game.on('end', (i) => {
i.update('Game has ended.');
});
game.end(interaction);
// And lastly if you used a custom message
game.on('end', (i, c) => {
i.update(c);
});
game.end(interaction, 'Game has ended.');
Fired when an error occurs.
const { Game } = require('disgamekit');
let game = new Game('game');
game.on('error', (error) => {
console.log('Error occured!' + error);
});
const gameId = 'game`';
const game = new Game(gameId);
game.on('start', () => {
console.log('Game started!');
});
game.on('end', () => {
console.log('Game ended!');
});
game.on('error', (error) => {
console.error('An error occurred with the game!:', error);
});
game.start();
In the example above, a new Game
instance is created with a game client and a unique ID. Event listeners are added for the start
, end
, and error
events. Lastly the game is started using game.start()
.
The Plane
class represents a grid-based 2d plane and provides methods to manage and manipulate objects on the plane. All objects refrenced can be found here
game
: The game instance associated with the plane.rows
: The number of rows in the plane.columns
: The number of columns in the plane.blank
:(optional) The default value for empty cells in the plane. Defaults tonull
const { Game, Plane } = require('disgamekit');
const game = new Game('gameId');
const plane = new Plane(game, 5, 5, 'blank');
Looks up an object's coordinates based on its ID.
inputValue
: The ID of the object to be looked up on the plane.
// If an object with the ID: qwert was at x:2 y: 6
plane.lookupObj('qwert'); // { x: 2, y: 6 }
Looks up the value at the specified x and y coordinates on the plane
x
:(optional) The x-coordinate.y
:(optional) The y-coordinate
plane.lookupCoords(2, 6); // "qwert"
Clears the entire plane, removing all objects while preserving their coordinates.
plane.clear();
Adds/Updates/Removes Objects on the plane. If provided : It will update/add to the plane If not provided : It will clear the plane of any objects.
...arr
:(optional) Numerous objects to be updated on the plane.
plane.update(object1, object2, object3, object4);
Reutrns a string representation of the plane, with optional row and column separators.
row
:(optional) The separator for rows. Defaults to an empty string.column
:(optional) The separator for columns. Defaults to a line break
// For example, the plane has 5 rows and 5 columns
plane.return('', '\n');
/*
blank blank blank blank blank
blank blank blank blank blank
blank blank blank blank blank
blank blank blank blank blank
blank blank blank blank blank
*/
The PlaneObject class represents an object that can be placed on the Plane. It emits events for collision detection and can be used to create interactive game elements.
plane
: Plane instance.x
: The object's origin on the x-axisy
: The object's origin on the y-axisid
: A unique identifier for the object.value
:(optional) The emoji or value to display on the plane for said object. Defaults to the object's ID.detectCollision
:(optional) Whether to detect collisions with other objects. Defaults totrue
ai
: (optional) Enable Auto-Movement
const { Plane, PlaneObject } = require('disgamekit');
let plane = new Plane(...)
let hat = new PlaneObject(plane, 0, 0, 'hat', '🧢');
Check if current PlaneObject is an AI
const { Plane, PlaneObject } = require('disgamekit');
let plane = new Plane(...)
let hat = new PlaneObject(plane, 0, 0, 'hat', '🧢', false, true);
hat.isAi() // true
Start tracking specified target
target
: another PlaneObject to target
let apple = new PlaneObject(plane, 5, 5, 'apple', 'a');
hat.start(apple);
Step 1 grid space closer to the target
target
: (optional) Override current target with new target
hat.step(); // since it's tracking apple at (5, 5), hat will go to (1, 1)
Stop running the AI
hat.stop();
hat.step(); // AI has not been started!
Fired when foo
collides with a wall or another PlaneObject
instance
const { Game, PlaneObject, Plane } = require('disgamekit');
let game = new Game('game');
let plane = new Plane(game, 4, 4);
let object = new PlaneObject(plane, 2, 0, 'object');
object.on('colllision', (i) => {
console.log(`Object collided with ${i.id}!`);
});
const { Plane, PlaneObject } = require('disgamekit');
// Create a game instance
const game = new Game('gameId');
// Create a plane with 5 rows and 5 columns
const plane = new Plane(game, 5, 5);
// Create plane objects
const object1 = new PlaneObject(plane, 2, 2, 'obj1', 'A');
const object2 = new PlaneObject(plane, 3, 3, 'obj2', 'B');
// Update the plane with the objects
plane.update(object1, object2);
// Check for collision (This is called when collided with a wall, even if detectCollison = false.)
object1.on('collision', (i) => {
console.log(`${i} collided with object1!`);
});
// Lookup object coordinates
const coordinates1 = plane.lookupObj('obj1');
console.log('Object 1 coordinates:', coordinates1); // Output: Object 1 coordinates: { x: 2, y: 2 }
// Lookup value at coordinates
const value = plane.lookupCoords(3, 3);
console.log('Value at coordinates (3, 3):', value); // Output: Value at coordinates (3, 3): B
// Clear the plane
plane.clear();
// Update the plane with a single object
const object3 = new PlaneObject(plane, 1, 1, 'obj3', 'C');
plane.update(object3);
// Return the plane as a string
const planeString = plane.return(' ', '\n');
console.log(planeString);
/* Output:
null null null null null
null null null null null
null null C null null
null null null null null
null null null null null
*/
In the example above, we create a game instance and then create a Plane
instance with 5 rows and 5 columns. We create PlaneObject
instances (object1
and object2
) with origin coordinates and values. The plane is then updated with these objects using the update()
method.
We perform lookups on the plane using the lookupObj()
method to retrieve the coordinates of object1
, and the lookupCoords()
method to retrieve the value at coordinates (3, 3)
.
The plane is cleared using the clear()
method and then updated with a new object (object3
). Finally, we return the plane as a string representation using the return()
method and print it to the console.
Example Discord.js
// This works the same with interactions. But so that the code is not 6k lines long, I've used messages.
// Discord.js and disgamekit imports
const {
Client,
IntentsBitField,
EmbedBuilder,
ButtonBuilder,
ButtonStyle,
ActionRowBuilder,
} = require('discord.js');
const { Game, Plane, PlaneObject } = require('disgamekit');
const client = new Client({
intents: [
IntentsBitField.Flags.Guilds,
IntentsBitField.Flags.GuildMessages,
IntentsBitField.Flags.MessageContent,
],
});
client.on('ready', () => {
console.log(`${client.user.tag} is online`);
});
// var setup
const game = new Game(client, 'game');
game.var.score = 0;
const plane = new Plane(game, 10, 10, ':green_square:');
const moveable = new PlaneObject(
plane,
3,
3,
'moveable',
':blue_square:',
true
);
const nonmove = new PlaneObject(plane, 2, 2, 'nonmove', ':apple:');
// game controls
const row = new ActionRowBuilder().addComponents(
new ButtonBuilder()
.setCustomId('up')
.setLabel('up')
.setStyle(ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId('down')
.setLabel('down')
.setStyle(ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId('left')
.setLabel('left')
.setStyle(ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId('right')
.setLabel('right')
.setStyle(ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId('end')
.setLabel('end')
.setStyle(ButtonStyle.Danger)
);
client.on('messageCreate', async (m) => {
if (m.author.bot) return;
const message = m.content;
if (!message.includes('mjb?')) return;
let cmd = message.split('?');
switch (cmd[1]) {
case 'help':
m.reply('No.');
break;
case 'button':
game.start();
plane.update(moveable, nonmove); // show the initial state by updating the object to the grid before hand
await m.reply({
embeds: [
new EmbedBuilder()
.setTitle('g a m e')
.setDescription(plane.return()),
],
components: [row],
});
break;
}
});
// game events
game.on('start', () => {
console.log('Game started!');
});
game.on('end', async (i) => {
await i.update({
content: `game has ended! Your final score = ${game.var.score}`,
components: [],
embeds: [],
}); // clear buttons so no errors occur.
console.log('Game ended!');
});
moveable.on('collision', (obj) => {
// when the moveable collides with nonemoveable update the score, if wall, log it to the console.
if (obj.id == nonmove.id) {
game.var.score++;
} else if (obj.id == 'wall') {
// You can just use an if since it's 2 objects but i used an else if for documentation sake
console.log('Collision with wall!');
}
});
// game controls
client.on(`interactionCreate`, async (i) => {
switch (i.customId) {
case 'up':
moveable.y++;
await update(i, plane, moveable, nonmove);
break;
case 'down':
moveable.y--;
await update(i, plane, moveable, nonmove);
break;
case 'left':
moveable.x--;
await update(i, plane, moveable, nonmove);
break;
case 'right':
moveable.x++;
await update(i, plane, moveable, nonmove);
break;
case 'end':
game.end(i);
}
});
// helper function to make this 50 less lines.
async function update(i, plane, ...item) {
/*
you don't need to make a function like this
but due to my controls doing the same thing
over and, over again, I made it a function.
*/
await plane.update(...item);
await i.update({
embeds: [
new EmbedBuilder()
.setTitle(`g a m e`)
.setDescription(plane.return())
.setFooter({ text: `Score = ${game.var.score}` }),
],
components: [row],
});
}
// Login the Discord client with your token
client.login('your-token-here-bro');
This code sets up a Discord bot using the Discord.js library and integrates it with a game using the disgamekit library. Here's a breakdown of the major components:
- Discord.js: It's used to create the Discord client, handle events, and interact with the Discord API.
- disgamekit: This library.
The code initializes a game with a client, a plane, and plane objects. It also sets up game controls as buttons using an ActionRowBuilder
.
When a user sends a message with the command "mjb?button", the game starts, the plane is updated with the objects, and the game state is sent as a reply with the buttons.
The game responds to interactions with the buttons, updating the position of the moveable object and updating the game state accordingly.
The game emits events for "start", "end", and "collision", which can be handled to perform actions when these events occur. (Currently) the moveable
listens for the "collision" event and checks whether it collided with an object or the wall. If it's the wall it logs to the console. If it's the nonmove
object, it updates the game variables stored in game.var
.
The update
function is a helper function that updates the game state and updates the message with the new state and buttons.
NOTE - The code above is set up in a way that every user plays the same game . To avoid this either initialize the variables in the message create or use a map.
Like the PlaneObject (without collision or AI), but can span multiple pixels on the plane. Currently can create a line from point A to B.
plane
: Pass the plane associated with this object, like the PlaneObject
const { ComplexPlaneObject, Plane } = require('disgamekit');
const plane = new Plane(/** Plane stuff**/);
const obj1 = new ComplexPlaneObject(plane);
Draw a line or multiples with one object.
...input
: Numerous Objects to be added. (Rest parameter)
obj1.draw(
{
value: /* Emoji to display for the line*/,
path: /* Path the line should take.*/
},
{
value: ":apple:",
path: "0, 0 -> 7, 8" // (x1, y1 -> y1, y2)
}
)
Return an array of PlaneObjects that represent the line.
const plane = new Plane(/** plane stuff */);
const obj1 = new ComplexPlaneObject(plane);
plane.update(...obj1.return()); // used a rest parameter because array.
The Turns class manages a turn-based system for games with multiple players. It allows adding, removing, and advancing turns for players.
...players
: Numerous players to be added
const { Turns, Player } = require('disgamekit');
const player1 = new Player('1', 'Alice');
const player2 = new Player('2', 'Bob');
const player3 = new Player('3', 'Charlie');
const turns = new Turns(player1, player2, player3);
Adds a new player to the game.
player
: The player represented by the player class
const { Turns, Player } = require('disgamekit');
const player1 = new Player('1', 'Alice');
const player2 = new Player('2', 'Bob');
const turns = new Turns(player1);
const player3 = new Player('3', 'Charlie');
turns.addPlayer(player3);
Removes a player from the game.
player
: The player represented by the player class
const { Turns, Player } = require('disgamekit');
const player1 = new Player('1', 'Alice');
const player2 = new Player('2', 'Bob');
const player3 = new Player('3', 'Charlie');
const turns = new Turns(player1, player2, player3);
turns.removePlayer(player2);
Starts the turn-based game.
const { Turns, Player } = require('disgamekit');
const player1 = new Player('1', 'Alice');
const player2 = new Player('2', 'Bob');
const turns = new Turns(player1, player2);
turns.startTurns();
Advances to the next turn.
overridePlayer
:(optional) Override with an additional player, making them have an extra turn
const { Turns, Player } = require('disgamekit');
const player1 = new Player('1', 'Alice');
const player2 = new Player('2', 'Bob');
const turns = new Turns(player1, player2);
turns.startTurns();
turns.nextTurn();
Reverses the order of turns.
const { Turns, Player } = require('disgamekit');
const player1 = new Player('1', 'Alice');
const player2 = new Player('2', 'Bob');
const player3 = new Player('3', 'Charlie');
const turns = new Turns(player1, player2, player3);
turns.reverseOrder();
The Player class represents a player in the game (specifically for the Turns class). It holds a unique identifier (id) and the player's name (name).
id
: The player's unique identifier.name
: The player's name.
const { Player } = require('disgamekit');
const player1 = new Player('1', 'Alice');
const player2 = new Player('2', 'Bob');