From 3d5eb360a27c02a73c2519a79497bf268e67376e Mon Sep 17 00:00:00 2001 From: Alec Maier Date: Sat, 31 Aug 2019 18:22:39 -0400 Subject: [PATCH] Deal and display cards to players, click a button to say you are dead and relay this message to everyone, small code improvements --- game.html | 4 +- server.js | 15 ++++++- static/game.js | 100 +++++++++++++++++++++++++++++++++++++++++----- static/join.js | 15 +------ static/setup.js | 50 +++++++++++------------ static/styles.css | 94 ++++++++++++++++++++++++++++++++++++++++++- static/util.js | 15 +++++++ 7 files changed, 241 insertions(+), 52 deletions(-) create mode 100644 static/util.js diff --git a/game.html b/game.html index 3cda2fd..af133bd 100644 --- a/game.html +++ b/game.html @@ -9,8 +9,10 @@
+
-
+
+
diff --git a/server.js b/server.js index 753d5a3..146954d 100644 --- a/server.js +++ b/server.js @@ -39,7 +39,7 @@ io.on('connection', function(socket) { onSucess(); }); socket.on('joinGame', function(playerInfo) { - activeGames[Object.keys(activeGames).find((key) => key === playerInfo.code)].players[socket.id] = {name: playerInfo.name, id: playerInfo.id}; + activeGames[Object.keys(activeGames).find((key) => key === playerInfo.code)].players.push({name: playerInfo.name, id: playerInfo.id}); }); socket.on('requestState', function(data) { if(Object.keys(socket.rooms).includes(data.code) === false) { @@ -53,5 +53,18 @@ io.on('connection', function(socket) { io.to(data.code).emit('state', activeGames[Object.keys(activeGames).find((key) => key === data.code)]); } }); + socket.on('startGame', function(gameData) { + let game = activeGames[Object.keys(activeGames).find((key) => key === gameData.code)]; + game.state = "started"; + game.players = gameData.players; + io.to(gameData.code).emit('state', game); + }); + socket.on('killPlayer', function(id, code) { + let game = activeGames[Object.keys(activeGames).find((key) => key === code)]; + let player = game.players.find((player) => player.id === id); + game.players.find((player) => player.id === id).dead = true; + game.message = player.name + ", a " + player.card.role + ", has been killed!"; + io.to(code).emit('state', game); + }); }); diff --git a/static/game.js b/static/game.js index 7952dd4..11d9572 100644 --- a/static/game.js +++ b/static/game.js @@ -1,10 +1,17 @@ +import {utility} from './util.js' + const socket = io(); var currentGame = null; +document.getElementById("launch").addEventListener("click", launchGame); + // respond to the game state received from the server socket.on('state', function(game) { currentGame = game; - console.log(game); + if (game.message) { + document.getElementById("message-box").innerText = game.message; + } + console.log(currentGame); buildGameBasedOnState(); }); @@ -12,10 +19,80 @@ function buildGameBasedOnState() { switch(currentGame.state) { case "lobby": renderLobby(); + break; + case "started": + renderGame(); + break; + default: + break; } } +function launchGame() { + randomlyDealCardsToPlayers(); + socket.emit('startGame', { players: currentGame.players , code: currentGame.accessCode}); +} + +function randomlyDealCardsToPlayers() { + for (let player of currentGame.players) { + player.card = drawRandomCard(); + } +} + +function drawRandomCard() { + return currentGame.deck.splice(utility.getRandomInt(currentGame.deck.length) - 1, 1)[0]; +} + +function getLiveCount() { + let liveCount = 0; + for (let player of currentGame.players) { + if (!player.dead) { + liveCount ++; + } + } + return liveCount; +} + +function renderGame() { + const player = currentGame.players.find((player) => player.id === sessionStorage.getItem("id")); + const card = player.card; + + // render the players card + document.getElementById("lobby-container").setAttribute("class", "hidden"); + document.getElementById("launch").setAttribute("class", "hidden"); + document.getElementById("game-container").setAttribute("class", "game-container"); + document.getElementById("game-container").innerHTML = + "
" + getLiveCount() + "/" + currentGame.size + " Players alive
" + + "
" + + "
" + + "

" + card.role + "

" + + "

" + card.description + "

" + + "
" + + "
" + + "
" + + ""; + let killedBtn = document.createElement("button"); + killedBtn.setAttribute("id", "dead-btn"); + + // render the "I'm dead" button based on the player's state + if (player.dead) { + killedBtn.setAttribute("class", "app-btn-secondary killed-btn disabled"); + killedBtn.innerText = "Killed" + } else { + killedBtn.setAttribute("class", "app-btn-secondary killed-btn"); + killedBtn.innerText = "I'm dead"; + } + document.getElementById("game-container").appendChild(killedBtn); + document.getElementById("dead-btn").addEventListener("click", killPlayer); +} + +function killPlayer() { + socket.emit("killPlayer", currentGame.players.find((player) => player.id === sessionStorage.getItem("id")).id, currentGame.accessCode); +} + function renderLobby() { + // Render lobby header if (document.getElementsByClassName("lobby-player").length === 0) { let header = document.createElement("h2"); header.setAttribute("class", "app-header"); @@ -24,36 +101,39 @@ function renderLobby() { let subHeader = document.createElement("div"); subHeader.setAttribute("id", "lobby-subheader"); subHeader.innerHTML = "
" + - "" + Object.keys(currentGame.players).length + "" + + "" + currentGame.players.length + "" + "/" + currentGame.size + " Players" + "
" + "
" + "
Access Code: " + currentGame.accessCode + "
"; document.getElementById("lobby-container").appendChild(subHeader); } + // Render all players that are new let i = 1; - for (let key in currentGame.players) { + for (let player of currentGame.players) { if(!document.getElementById("player-" + i)) { const playerContainer = document.createElement("div"); - currentGame.players[key].id === sessionStorage.getItem("id") ? + player.id === sessionStorage.getItem("id") ? playerContainer.setAttribute("class", "lobby-player highlighted") : playerContainer.setAttribute("class", "lobby-player"); playerContainer.setAttribute("id", "player-" + i); - playerContainer.innerHTML = "

" + currentGame.players[key].name + "

"; + playerContainer.innerHTML = "

" + player.name + "

"; document.getElementById("lobby-container").appendChild(playerContainer); - document.getElementById("join-count").innerText = Object.keys(currentGame.players).length.toString(); + document.getElementById("join-count").innerText = currentGame.players.length.toString(); } i ++; } // display the launch button if the player is the host if (sessionStorage.getItem("host")) { - Object.keys(currentGame.players).length === currentGame.size ? - document.getElementById("launch-btn").innerHTML = "" - : document.getElementById("launch-btn").innerHTML = "" + currentGame.players.length === currentGame.size ? + document.getElementById("launch").innerHTML = "" + : document.getElementById("launch").innerHTML = "" + } else { + document.getElementById("launch").innerHTML = "

The host will start the game.

" } } // request the current state of the game from the server window.onload = function() { socket.emit('requestState', {code: sessionStorage.getItem("code")}); -} +}; diff --git a/static/join.js b/static/join.js index 4e0c970..f2a2635 100644 --- a/static/join.js +++ b/static/join.js @@ -1,23 +1,12 @@ const socket = io(); +import { utility } from './util.js' document.getElementById("join-btn").addEventListener("click", function() { sessionStorage.setItem("code", document.getElementById("code").value); - let playerId = generateID(); + let playerId = utility.generateID(); sessionStorage.setItem("id", playerId); const playerInfo = {name: document.getElementById("name").value, id: playerId, code: document.getElementById("code").value}; socket.emit('joinGame', playerInfo); window.location.replace('/' + document.getElementById("code").value); }); -function generateID() { - let code = ""; - let charPool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - for (let i = 0; i < 10; i++) { - code += charPool[getRandomInt(61)] - } - return code; -} - -function getRandomInt(max) { - return Math.floor(Math.random() * Math.floor(max)); -} diff --git a/static/setup.js b/static/setup.js index 7199843..94ae5e3 100644 --- a/static/setup.js +++ b/static/setup.js @@ -1,4 +1,5 @@ import {cards} from './cards.js' +import {utility} from './util.js' const socket = io(); var games = []; @@ -6,6 +7,7 @@ var games = []; // important declarations class Card { constructor(role, team, description, powerRole) { + this.id = null; this.role = role; this.team = team; this.description = description; @@ -15,17 +17,17 @@ class Card { } class Game { - constructor(accessCode, size, deck, time, players) { + constructor(accessCode, size, deck, time) { this.accessCode = accessCode; this.size = size; this.deck = deck; this.time = time; - this.players = players; + this.players = []; this.state = "lobby"; } } -var deck = []; +var fullDeck = []; var gameSize = 0; var time = null; @@ -40,7 +42,7 @@ window.onload = function() { const newCard = new Card(card.role, card.team, card.description, card.powerRole); const cardContainer = document.createElement("div"); - deck.push(newCard); + fullDeck.push(newCard); cardContainer.setAttribute("class", "card"); cardContainer.innerHTML = "

" + newCard.role + "


" + newCard.quantity + "

"; @@ -60,14 +62,14 @@ window.onload = function() { function updateGameSize() { gameSize = 0; - for (let card of deck) { + for (let card of fullDeck) { gameSize += card.quantity; } document.getElementById("game-size").innerText = gameSize + " Players"; } function resetCardQuantities() { - for (let card of deck) { + for (let card of fullDeck) { card.quantity = 0; } updateGameSize(); @@ -76,17 +78,28 @@ function resetCardQuantities() { }); } +function buildDeckFromQuantities() { + let playerDeck = []; + for (const card of fullDeck) { + for (let i = 0; i < card.quantity; i++) { + let newCard = new Card(card.role, card.team, card.description, card.powerRole); + newCard.id = utility.generateID(); + playerDeck.push(newCard); + } + } + return playerDeck; +} + function createGame() { // generate 6 digit access code let code = ""; let charPool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; for (let i = 0; i < 6; i++) { - code += charPool[getRandomInt(61)] + code += charPool[utility.getRandomInt(61)] } - console.log(code); // generate unique player Id for session - let id = generateID(); + let id = utility.generateID(); sessionStorage.setItem("id", id); // player who creates the game is the host @@ -97,9 +110,8 @@ function createGame() { const game = new Game( code, gameSize, - deck, - document.getElementById("time").value, - { [socket.id]: playerInfo} + buildDeckFromQuantities(), + document.getElementById("time").value ); socket.emit('newGame', game, function(data) { console.log(data); @@ -108,17 +120,3 @@ function createGame() { window.location.replace('/' + code); }); } - -function generateID() { - let code = ""; - let charPool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - for (let i = 0; i < 10; i++) { - code += charPool[getRandomInt(61)] - } - return code; -} - - -function getRandomInt(max) { - return Math.floor(Math.random() * Math.floor(max)); -} diff --git a/static/styles.css b/static/styles.css index 8b31cc8..018efa3 100644 --- a/static/styles.css +++ b/static/styles.css @@ -39,7 +39,6 @@ html, body { margin: 0 auto; width: 100%; - margin-bottom: 2em; font-family: sans-serif; } @@ -197,6 +196,12 @@ label { flex-direction: column; } +#message-box { + margin: 1em 1em; + border-bottom: 1px solid #7d0b0b; + padding: 0.5em; +} + /* lobby */ @@ -230,6 +235,10 @@ label { } +.hidden { + display: none; +} + #lobby-subheader { text-align: left; margin-bottom: 2em; @@ -246,3 +255,86 @@ label { #launch-btn { margin-top: 2em; } + +/* GAME */ + +@keyframes flip { + 0% { + transform: rotateY(0deg); + } + 100% { + transform: rotateY(-180deg); + } +} + +.game-card { + border: 1px solid #7d0b0b; + background-color: #f0f0f0; + display: flex; + flex-direction: column; + justify-content: space-between; + max-width: 17em; + border-radius: 3px; + height: 25em; + margin: 0 auto 2em auto; + width: 82%; + box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3); + perspective: 1000px; + animation: flip 0.7s; + animation-fill-mode: forwards; + animation-direction: reverse; + transform-style: preserve-3d; +} + +.game-card h2 { + font-size: 2em; + color: #7d0b0b; +} + +.game-card p { + padding: 1em; +} + +.game-container { + margin-top: 1em; +} + +/* This container is needed to position the front and back side */ +.game-card-inner { + position: relative; + width: 95%; + height: 97%; + margin: auto auto; + border-radius: 3px; + text-align: center; + border: 1px solid gray; +} + +.game-card:hover { +} + +/* Position the front and back side */ +.game-card-front, .game-card-back { + background-color: #f0f0f0; + position: absolute; + width: 100%; + height: 100%; + backface-visibility: hidden; +} + +.game-card-back { + transform: rotateY(180deg); +} + +.killed-btn { + border-radius: 5px; + width: 13em; + font-size: 1.2em; + margin: 0 +} + +#players-remaining { + font-size: 1.7em; + color: gray; + margin-bottom: 0.5em; +} diff --git a/static/util.js b/static/util.js new file mode 100644 index 0000000..525b9cd --- /dev/null +++ b/static/util.js @@ -0,0 +1,15 @@ +export const utility = +{ + generateID() { + let code = ""; + let charPool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + for (let i = 0; i < 10; i++) { + code += charPool[this.getRandomInt(61)] + } + return code; + }, + + getRandomInt(max) { + return Math.floor(Math.random() * Math.floor(max)); + } +};