I'm trying to display a blackjack table using NodeJS and Canvas. I'm drawing the images of all players and all the cards. The problem is that the image of the last card is not rendered, but the code does execute at that point and the coordinates of the card are correct.
The code does:
- Sets all the constants needed for it to position images.
- For loop on the array which contains all the players.
- Draw their image and their respective cards.
I can't seem to find the problem. The code is:
await int.deferReply();
interface Player {
pic: string;
hand: string[];
pos?: { x: number; y: number };
}
const joinTable = (user: User): Player => ({
pic: user.displayAvatarURL({ extension: "png" }),
hand: []
});
const joined = [
joinTable(int.user),
joinTable(int.user),
joinTable(int.user),
joinTable(int.user),
joinTable(int.user)
];
const [W, H] = [1920, 1080];
const [DEALER_Y, PLAYER_Y] = [H * 0.1, H * 0.75];
const PLAYER_Y_ODD = PLAYER_Y - 300;
const [HALF_W, OFFSET_X] = [W * 0.5, 64];
const [CARD_DIMS, CARD_OFFSET_X] = [[52, 82] as [number, number], 32];
const PORTIONS = W / (joined.length + 1);
const canvas = createCanvas(W, H);
const ctx = canvas.getContext("2d");
const { img, cards } = PATHS;
const drawCard = async (
p: Player,
deck: string[],
x: number,
y: number,
n: number = 1
) => {
for (let i = 0; i < n; i++) {
let c = client.draw(deck, p.hand);
p.hand.push(c);
let cSprite = await loadImage(cards + c + ".png");
ctx.drawImage(cSprite, x, y, ...CARD_DIMS);
//console.log(`${c}: (${x}, ${y})`);
}
};
let deck = client.deck();
let bg = await loadImage(img + "green.jpg");
let dProPic = await loadImage(
client.user.displayAvatarURL({ extension: "png" })
);
ctx.drawImage(bg, 0, 0);
ctx.drawImage(dProPic, HALF_W - OFFSET_X, DEALER_Y);
for (let i = 0; i < joined.length; i++) {
let plPic = await loadImage(joined[i].pic);
let [x, y] = [
PORTIONS * (i + 1) - OFFSET_X,
i % 2 === 0 && joined.length > 2 ? PLAYER_Y_ODD : PLAYER_Y
];
joined[i].pos = { x, y };
ctx.drawImage(plPic, x, y);
drawCard(
joined[i],
deck,
Math.floor(x - OFFSET_X - 32 * joined[i].hand.length),
y - 96
);
}
let atc = new AttachmentBuilder(canvas.createPNGStream());
await int.editReply({ files: [atc] });
example output:
If I decrease / increase the amount of players the problem persists. If I set 1 player the card is not rendered.
EDIT
Here's some additional infos:
The PATHS
:
const BASE_PATH = __dirname + "/../";
export const PATHS = {
img: join(BASE_PATH, "../assets/img/"),
cards: join(BASE_PATH, "../assets/cards/"),
};
The client is a discord.js client, and int
is a a discord.js command interaction, which is sent after a user sends a slash command in a discord channel where the bot is present. The int.user
is the user assigned to an interaction that they fired, example: if I use a slash command, the int.user is an object that has all the properties of my discord user, like the id, the profile pic, the username etc.
I added a few methods on the client
such as deck()
:
public deck() {
let n = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K"];
let s = ["C", "H", "D", "S"];
let [ln, ls] = [n.length, s.length];
let deck: string[] = [];
for (let i = 0; i < ls; i++) {
for (let j = 0; j < ln; j++) {
deck.push(n[j] + s[i]);
}
}
return deck;
}
Which creates a 52 card deck.
That aside, I tried to move the code which was indise the drawCard
function directly inside the for-loop, and that works! But i don't know why and I am left with hard to read and repetitive code.