diff --git a/server.js b/server.js index fd37327..3147929 100644 --- a/server.js +++ b/server.js @@ -169,8 +169,10 @@ io.on('connection', function(socket) { if (game) { let player = game.players.find((player) => player.id === id); game.players.find((player) => player.id === id).dead = true; - game.killedPlayer = player; + game.killedPlayer = player.name; + game.lastKilled = player.id; game.killedRole = player.card.role; + game.message = player.name + ", a " + player.card.role + " was killed!" const winCheck = teamWon(game); if (winCheck === "wolf") { game.winningTeam = "wolf"; diff --git a/static/game.js b/static/game.js index 7a349a0..86fc933 100644 --- a/static/game.js +++ b/static/game.js @@ -7,11 +7,13 @@ let clock; let currentGame = null; let cardFlippedOver = false; let cardRendered = false; +let lastKilled = null; // respond to the game state received from the server socket.on('state', function(game) { currentGame = game; - if (game.killedPlayer && game.killedRole) { + if (game.killedPlayer && game.killedRole && game.lastKilled !== lastKilled) { // a new player has been killed + lastKilled = game.lastKilled; playKilledAnimation(); document.getElementById("message-box").innerText = game.message; } @@ -34,8 +36,40 @@ function buildGameBasedOnState() { } } +function hideAfterExit(e) { + e.target.style.display = 'none' + e.target.removeEventListener('animationend', triggerExitAnimation); + e.target.removeEventListener('animationend', hideAfterExit); +} + +function triggerExitAnimation(e) { + e.target.classList.remove(e.target.entranceClass); + e.target.classList.remove(e.target.exitClass); + e.target.offsetWidth; + e.target.classList.add(e.target.exitClass); + window.setTimeout(()=>{ + e.target.addEventListener('animationend', hideAfterExit); + },0); +} + +function triggerEntranceAnimation(selector, entranceClass, exitClass, image) { + let transitionEl = document.querySelector(selector); + transitionEl.style.display = 'block'; + transitionEl.addEventListener('animationend', triggerExitAnimation); + transitionEl.classList.remove(entranceClass); + transitionEl.entranceClass = entranceClass; + transitionEl.exitClass = exitClass; + transitionEl.offsetWidth; + if (image) { + transitionEl.setAttribute("src", "../assets/images/roles/" + currentGame.killedRole + ".png"); + } + transitionEl.classList.add(entranceClass); +} + function playKilledAnimation() { - + triggerEntranceAnimation('#overlay', 'animate-overlay-in', 'animate-overlay-out', false); + triggerEntranceAnimation('#killed-role', 'animate-role-in', 'animate-role-out', true); + triggerEntranceAnimation('#killed-name', 'animate-name-in', 'animate-name-out', false); } function launchGame() { diff --git a/static/styles.css b/static/styles.css index b85c6b5..32fcd4e 100644 --- a/static/styles.css +++ b/static/styles.css @@ -220,55 +220,6 @@ html, body { } } -@keyframes slide-fade-top { - 0% { - opacity: 0; - transform: translateY(-150px) - - } - 50% { - opacity: 1; - transform: translateY(0); - } - - 100% { - opacity: 0; - transform: translateY(-150px) - - } -} - -@keyframes slide-fade-bottom { - 0% { - opacity: 0; - transform: translateY(150px) - - } - 50% { - opacity: 1; - transform: translateY(0); - } - - 100% { - opacity: 0; - transform: translateY(150px) - - } -} - -@keyframes fade-overlay { - 0% { - background-color: rgba(0,0,0,0.0); - } - 50% { - background-color: rgba(0,0,0,0.9); - } - - 100% { - background-color: rgba(0,0,0,0.0); - } -} - #app-content { text-align: center; margin: 0 auto; @@ -1081,8 +1032,10 @@ label { color: #7d0b0b; } -.overlay { +#overlay { position: fixed; + user-select: none; + display: none; width: 100%; height: 100%; top: 0; @@ -1091,42 +1044,139 @@ label { bottom: 0; background-color: rgba(0,0,0,0.9); z-index: 3; - animation: fade-overlay 5s; - animation-timing-function: cubic-bezier(0.39, 0.575, 0.565, 1); } #killed-name { + display: none; color: white; padding-top: 2em; font-size: 2.5em; margin: 0; - animation: slide-fade-top 5s; - animation-timing-function: cubic-bezier(0.39, 0.575, 0.565, 1); } #killed-role { - animation: slide-fade-bottom 5s; - animation-timing-function: cubic-bezier(0.39, 0.575, 0.565, 1); + display: none; + margin: 0 auto; } +@keyframes slide-fade-in-top { + 0% { + opacity: 0; + transform: translateY(-150px) -.killed-card { - width: 50px; - height: 200px; - background-color: white; - position: absolute; - top: 19%; - left: 14%; - background-color: transparent; - cursor: pointer; - justify-content: space-between; - max-width: 17em; - border-radius: 3px; - height: 23em; - width: 72%; - box-shadow: 0 13px 17px rgba(0,0,0,0.6); - perspective: 1000px; - transform-style: preserve-3d; + } + 100% { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slide-fade-out-top { + 0% { + opacity: 1; + transform: translateY(0px) + + } + 100% { + opacity: 0; + transform: translateY(-150px); + } +} + +@keyframes slide-fade-in-bottom { + 0% { + opacity: 0; + transform: translateY(150px) + + } + 100% { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slide-fade-out-bottom { + 0% { + opacity: 1; + transform: translateY(0); + } + 100% { + opacity: 0; + transform: translateY(150px) + + } +} + +@keyframes fade-overlay-in { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} + +@keyframes fade-overlay-out { + 0% { + opacity: 1; + } + 100% { + opacity: 0; + } +} + +.animate-overlay-in { + animation: fade-overlay-in 5s; + animation-timing-function: cubic-bezier(0.19, 1, 0.22, 1); + animation-fill-mode: forwards; + -webkit-animation: fade-overlay-in 5s; + -webkit-animation-timing-function: cubic-bezier(0.19, 1, 0.22, 1); + -webkit-animation-fill-mode: forwards; +} + +.animate-overlay-out { + animation: fade-overlay-out 1s; + animation-timing-function: cubic-bezier(0.95, 0.05, 0.795, 0.035); + animation-fill-mode: forwards; + -webkit-animation: fade-overlay-out 1s; + -webkit-animation-timing-function: cubic-bezier(0.95, 0.05, 0.795, 0.035); + -webkit-animation-fill-mode: forwards; +} + +.animate-name-in { + animation: slide-fade-in-top 5s; + animation-timing-function: cubic-bezier(0.19, 1, 0.22, 1); + animation-fill-mode: forwards; + -webkit-animation: slide-fade-in-top 5s; + -webkit-animation-timing-function: cubic-bezier(0.19, 1, 0.22, 1); + -webkit-animation-fill-mode: forwards; +} + +.animate-name-out { + animation: slide-fade-out-top 1s; + animation-timing-function: cubic-bezier(0.95, 0.05, 0.795, 0.035); + animation-fill-mode: forwards; + -webkit-animation: slide-fade-out-top 1s; + -webkit-animation-timing-function: cubic-bezier(0.95, 0.05, 0.795, 0.035); + -webkit-animation-fill-mode: forwards; +} + +.animate-role-in { + animation: slide-fade-in-bottom 5s; + animation-timing-function: cubic-bezier(0.19, 1, 0.22, 1); + animation-fill-mode: forwards; + -webkit-animation: slide-fade-in-bottom 5s; + -webkit-animation-timing-function: cubic-bezier(0.19, 1, 0.22, 1); + -webkit-animation-fill-mode: forwards; +} + +.animate-role-out { + animation: slide-fade-out-bottom 1s; + animation-timing-function: cubic-bezier(0.95, 0.05, 0.795, 0.035); + animation-fill-mode: forwards; + -webkit-animation: slide-fade-out-bottom 1s; + -webkit-animation-timing-function: cubic-bezier(0.95, 0.05, 0.795, 0.035); + -webkit-animation-fill-mode: forwards; } @keyframes animatetop { diff --git a/views/game.html b/views/game.html index 0c801a2..0bffed2 100644 --- a/views/game.html +++ b/views/game.html @@ -9,11 +9,9 @@