homegames-core
Version:
Play games at home
318 lines (266 loc) • 9.71 kB
JavaScript
const dictionary = require('../../common/util/dictionary');
const { Game, GameNode, Colors, Shapes, ShapeUtils } = require('squish-0767');
const COLORS = Colors.COLORS;
class Clicktionary extends Game {
static metadata() {
return {
aspectRatio: {x: 16, y: 9},
description: 'Take turns drawing and guessing the word',
author: 'Joseph Garcia',
thumbnail: '4b5f169186bc542e14b5d001d25ce6bb',
squishVersion: '0767',
maxPlayers: 2
};
}
constructor() {
super();
this.base = new GameNode.Shape({
shapeType: Shapes.POLYGON,
coordinates2d: ShapeUtils.rectangle(0, 0, 100, 100),
fill: COLORS.CREAM
});
this.players = {};
this.excludedNodeRoot = new GameNode.Shape({
shapeType: Shapes.POLYGON,
coordinates2d: [
[0, 0],
[0, 0]
]
});
this.base.addChild(this.excludedNodeRoot);
this.playerInfoNodes = {};
this.playerColors = {};
this.updateGameState();
}
updateGameState() {
if (Object.keys(this.players).length > 1) {
if (this.notEnoughPlayersText) {
this.excludedNodeRoot.removeChild(this.notEnoughPlayersText.id);
this.notEnoughPlayersText = null;
}
this.newRoundNode = new GameNode.Shape({
shapeType: Shapes.POLYGON,
coordinates2d: ShapeUtils.rectangle(45, 4, 10, 10),
fill: COLORS.HG_RED,
onClick: (player) => {
this.excludedNodeRoot.removeChild(this.newRoundNode.id);
this.newRound();
}
});
const newRoundLabel = new GameNode.Text({
textInfo: {
text: 'Start',
x: 50,
y: 7.5,
align: 'center',
size: 2,
color: COLORS.WHITE
}
});
this.newRoundNode.addChild(newRoundLabel);
this.excludedNodeRoot.addChild(this.newRoundNode);
} else if (!this.notEnoughPlayersText) {
this.notEnoughPlayersText = new GameNode.Text({
textInfo: {
text: 'At least 2 players required',
x: 50,
y: 50,
align: 'center',
size: 1,
color: COLORS.HG_BLACK
}
});
this.excludedNodeRoot.addChild(this.notEnoughPlayersText);
}
}
handleNewPlayer({ playerId, info: playerInfo }) {
this.players[Number(playerId)] = { ...playerInfo, id: playerId };
this.updateGameState();
}
handlePlayerDisconnect(playerId) {
delete this.players[playerId];
}
renderPlayerList() {
this.base.clearChildren([this.excludedNodeRoot.id]);
let yIndex = 0;
for (const playerId in this.players) {
const playerInfoNode = new GameNode.Shape({
shapeType: Shapes.POLYGON,
coordinates2d: ShapeUtils.rectangle(10, 10, yIndex * 8 + 2, 1, 1),
fill: COLORS.CREAM
});
this.playerInfoNodes[playerId] = playerInfoNode;
this.base.addChild(playerInfoNode);
yIndex++;
}
}
playerDidDisconnect(playerId) {
delete this.playerInfoNodes[playerId];
this.renderPlayerList();
}
getCurrentPlayer() {
if (this.currentPlayerIndex === null || this.currentPlayerIndex === undefined) {
this.currentPlayerIndex = 0;
} else {
let newPlayerIndex = this.currentPlayerIndex + 1;
if (newPlayerIndex > Object.values(this.players).length - 1) {
newPlayerIndex = 0;
}
this.currentPlayerIndex = newPlayerIndex;
}
this.currentPlayerId = Object.keys(this.players)[this.currentPlayerIndex];
return Object.values(this.players)[this.currentPlayerIndex];
}
newRound() {
this.newRoundNode.size = {x: 0, y: 0};
this.newRoundNode.text = null;
const currentPlayer = this.getCurrentPlayer();
this.canvas = new GameNode.Shape({
shapeType: Shapes.POLYGON,
coordinates2d: [
[15, 15],
[85, 15],
[85, 85],
[15, 85],
[15, 15]
],
fill: COLORS.WHITE,
onClick: (playerId, x, y) => {
if (!currentPlayer || currentPlayer.id != playerId) {
return;
}
const playerColor = this.playerColors[playerId] || COLORS.BLACK;
const coloredPixel = new GameNode.Shape({
shapeType: Shapes.POLYGON,
coordinates2d: [
x - .25, y - .25,
x + .25, y - .25,
x + .25, y + .25,
x - .25, y + .25,
x - .25, y - .25
],
fill: playerColor
});
this.canvas.addChild(coloredPixel);
}
});
this.base.addChild(this.canvas);
const word = dictionary.random();
this.wordNode = new GameNode.Text({
textInfo: {
text: word,
align: 'center',
x: 50,
y: 5,
size: 2,
color: COLORS.BLACK
},
playerIds: [currentPlayer.id]
});
this.base.addChild(this.wordNode);
const clearButton = new GameNode.Shape({
shapeType: Shapes.POLYGON,
coordinates2d: ShapeUtils.rectangle(2, 70, 10, 10),
fill: COLORS.HG_RED,
playerIds: [currentPlayer.id],
onClick: (player) => {
this.canvas.clearChildren([clearButton.id]);
}
});
const clearText = new GameNode.Text({
textInfo: {
text: 'Clear',
x: 7,
y: 73,
align: 'center',
size: 2,
color: COLORS.WHITE
},
playerIds: [currentPlayer.id]
});
clearButton.addChild(clearText);
let doneCountdown;
const doneButton = new GameNode.Shape({
shapeType: Shapes.POLYGON,
coordinates2d: ShapeUtils.rectangle(88, 4, 10, 10),
fill: COLORS.HG_BLUE,
playerIds: [currentPlayer.id],
onClick: () => {
if (!doneCountdown) {
this.stopInterval = true;
this.wordNode.node.playerIds = [];
doneCountdown = this.setTimeout(() => {
this.stopInterval = false;
doneCountdown = null;
this.base.clearChildren([this.excludedNodeRoot.id]);
this.newRound();
}, 5000);
}
}
});
const doneText = new GameNode.Text({
textInfo: {
text: 'Done',
x: 93.3,
y: 7,
align: 'center',
size: 2,
color: COLORS.WHITE
},
playerIds: [currentPlayer.id]
});
doneButton.addChild(doneText);
clearButton.addChild(doneButton);
this.canvas.addChild(clearButton);
const colorOptions = [COLORS.BLACK, COLORS.RED, COLORS.BLUE, COLORS.GREEN, COLORS.YELLOW, COLORS.WHITE];
let optionX = 25;
for (const colorIndex in colorOptions) {
const color = colorOptions[colorIndex];
const colorButton = new GameNode.Shape({
shapeType: Shapes.POLYGON,
coordinates2d: ShapeUtils.rectangle(optionX, 90, 5, 5),
fill: color,
playerIds: [currentPlayer.id],
onClick: (playerId) => {
this.playerColors[playerId] = color;
}
});
clearButton.addChild(colorButton);
optionX += 10;
}
const answerTime = 60;
let currentTime = answerTime;
const textInfo = {
text: '' + currentTime,
x: 80,
y: 5,
align: 'center',
size: 5,
color: COLORS.WHITE
};
const countdownNode = new GameNode.Text({textInfo: Object.assign({}, textInfo)});
const countdown = this.setInterval(() => {
if (this.stopInterval) {
this.stopInterval = false;
clearInterval(countdown);
}
if (currentTime <= 1) {
clearInterval(countdown);
this.wordNode.node.playerIds = [];
this.setTimeout(() => {
this.base.clearChildren([this.excludedNodeRoot.id]);
this.newRound();
}, 5000);
}
currentTime--;
const newText = Object.assign({}, textInfo);
newText.text = '' + currentTime;
countdownNode.node.text = newText;
}, 1000);
clearButton.addChild(countdownNode);
}
getLayers() {
return [{root: this.base}];
}
}
module.exports = Clicktionary;