From 89a902c390e363182b86943ca9162b2066193bc1 Mon Sep 17 00:00:00 2001 From: Ayush Deb Date: Tue, 23 Jul 2024 18:55:29 +0530 Subject: [PATCH] added live draggable scoreboard --- js/game.js | 460 ++++++++++++++++++++++++++++-------------------- pages/game.html | 71 +++++++- 2 files changed, 335 insertions(+), 196 deletions(-) diff --git a/js/game.js b/js/game.js index 1c1171a..1fad610 100644 --- a/js/game.js +++ b/js/game.js @@ -1,174 +1,246 @@ class Game { - static instance; // Singleton instance of Game class - - constructor(rows, columns, playersCount) { - if (Game.instance == null) Game.instance = this; - - this.playersUI = document.querySelector(".players"); - this.playerNameUI = document.querySelector(".player-turn .name"); - this.playerTurnBgUI = document.querySelector(".player-turn .bg"); - - this.events = { - edgeFill: [], - boxFill: [], - playerSwitch: [], - playerWin: [], - }; - - this.players = [ - { name: "Player 1", color: "pink", filledBoxes: 0 }, - { name: "Player 2", color: "skyblue", filledBoxes: 0 }, - { name: "Player 3", color: "lightgreen", filledBoxes: 0 }, - { name: "Player 4", color: "magenta", filledBoxes: 0 }, - { name: "Player 5", color: "yellow", filledBoxes: 0 }, - { name: "Player 6", color: "orange", filledBoxes: 0 }, - ]; - - let p = this.players.length - playersCount; - for (let i = 0; i < p; i++) this.players.pop(); - - this.currentPlayerIndex = 0; - this.currentPlayer = this.players[this.currentPlayerIndex]; - - this.board = new Board(rows, columns); - - this.isGameover = false; - - this.addPlayersUI(); - this.updatePlayerNameUI(); - - // Adding event listeners for filling box, switching player, and winning - this.addEventListener("boxFill", () => this.onBoxFill()); - this.addEventListener("playerSwitch", () => this.onPlayerSwitch()); - this.addEventListener("playerWin", () => this.onPlayerWin()); - } - - // End Game - onPlayerWin() { - this.isGameover = true; - this.removeEventListener("boxFill"); - - let winSound = new Audio("../assets/sounds/win.mp3"); - winSound.play(); - - // Determine winner or draw - const winner = this.determineWinner(this.players); - - // Display the result - if (winner === "DRAW") { - this.playerNameUI.parentElement.textContent = "DRAW"; - this.playerTurnBgUI.classList.add("win"); - this.playerTurnBgUI.style.background = "#eaeaea"; - } else { - this.playerNameUI.parentElement.textContent = `${winner.name} wins`; - this.playerTurnBgUI.classList.add("win"); - this.playerTurnBgUI.style.background = winner.color; - } - - // Open the win overlay - document.getElementById("win-overlay").style.height = "100%"; - } - - determineWinner(players) { - // Find the maximum number of filled boxes - const maxBoxes = Math.max(...players.map((player) => player.filledBoxes)); - - // Find how many players have the maximum number of filled boxes - const result = players.filter((player) => player.filledBoxes === maxBoxes); - - if (result.length > 1) { - return "DRAW"; - } else { - return result[0]; - } - } - - onPlayerSwitch() { - this.updatePlayerNameUI(); - } - - // If a box is filled, increment players' score with the number of boxes filled by him/her and update UI - onBoxFill() { - this.currentPlayer.filledBoxes++; - this.updatePlayerScoreUI(); - } - - // Add players to UI - addPlayersUI() { - this.players.forEach((player, index) => { - const div = document.createElement("div"); - div.classList.add("player"); - - // Maintain filled boxes. - const b = document.createElement("b"); - b.classList.add("filled-boxes"); - b.textContent = player.filledBoxes; - b.style.background = player.color; - this.players[index]["filledBoxesUI"] = b; - - // Maintain player name. - const span = document.createElement("span"); - span.textContent = player.name; - - div.appendChild(b); - div.appendChild(span); - - // Adding score and name to the element - this.playersUI.appendChild(div); - }); - } - - // Update player score UI used while switching player - updatePlayerScoreUI() { - this.currentPlayer.filledBoxesUI.innerText = this.currentPlayer.filledBoxes; - } - - // Update player name UI used while switching player - updatePlayerNameUI() { - this.playerNameUI.innerText = this.currentPlayer.name; - this.playerTurnBgUI.style.background = this.currentPlayer.color; - } - - eventExist(event) { - return this.events.hasOwnProperty(event); - } - - // Add event listeners - addEventListener(event, callback) { - if (!this.eventExist(event)) { - console.error(`${event} event is not defined`); - return; - } - - this.events[event].push(callback); - } - - // Remove event listeners - removeEventListener(event, callback) { - if (!this.eventExist(event)) { - console.error(`${event} event is not defined`); - return; - } - this.events[event].splice(this.events[event].indexOf(callback), 1); - } - - // Invoke event listeners - invokeEvent(event, args) { - if (!this.eventExist(event)) { - console.error(`${event} event is not defined`); - return; - } - this.events[event].forEach((callback) => callback(args)); - } - - // Switch player - switchPlayer() { - if (!this.isGameover) { - this.currentPlayerIndex = ++this.currentPlayerIndex % this.players.length; - this.currentPlayer = this.players[this.currentPlayerIndex]; - this.invokeEvent("playerSwitch"); - } - } + static instance; // Singleton instance of Game class + + constructor(rows, columns, playersCount) { + if (Game.instance == null) Game.instance = this; + + this.playersUI = document.querySelector(".players"); + this.playerNameUI = document.querySelector(".player-turn .name"); + this.playerTurnBgUI = document.querySelector(".player-turn .bg"); + + this.events = { + edgeFill: [], + boxFill: [], + playerSwitch: [], + playerWin: [], + }; + + this.players = [ + { name: "Player 1", color: "pink", filledBoxes: 0 }, + { name: "Player 2", color: "skyblue", filledBoxes: 0 }, + { name: "Player 3", color: "lightgreen", filledBoxes: 0 }, + { name: "Player 4", color: "magenta", filledBoxes: 0 }, + { name: "Player 5", color: "yellow", filledBoxes: 0 }, + { name: "Player 6", color: "orange", filledBoxes: 0 }, + ]; + + let p = this.players.length - playersCount; + for (let i = 0; i < p; i++) this.players.pop(); + + this.currentPlayerIndex = 0; + this.currentPlayer = this.players[this.currentPlayerIndex]; + + this.board = new Board(rows, columns); + + this.isGameover = false; + + this.addPlayersUI(); + this.updateScoreboard(); + this.updatePlayerNameUI(); + this.makeScoreboardDraggable(); + + // Adding event listeners for filling box, switching player, and winning + this.addEventListener("boxFill", () => this.onBoxFill()); + this.addEventListener("playerSwitch", () => this.onPlayerSwitch()); + this.addEventListener("playerWin", () => this.onPlayerWin()); + } + + // End Game + onPlayerWin() { + this.isGameover = true; + this.removeEventListener("boxFill"); + + let winSound = new Audio("../assets/sounds/win.mp3"); + winSound.play(); + + // Determine winner or draw + const winner = this.determineWinner(this.players); + + // Display the result + if (winner === "DRAW") { + this.playerNameUI.parentElement.textContent = "DRAW"; + this.playerTurnBgUI.classList.add("win"); + this.playerTurnBgUI.style.background = "#eaeaea"; + } else { + this.playerNameUI.parentElement.textContent = `${winner.name} wins`; + this.playerTurnBgUI.classList.add("win"); + this.playerTurnBgUI.style.background = winner.color; + } + + // Open the win overlay + document.getElementById("win-overlay").style.height = "100%"; + } + + determineWinner(players) { + // Find the maximum number of filled boxes + const maxBoxes = Math.max(...players.map((player) => player.filledBoxes)); + + // Find how many players have the maximum number of filled boxes + const result = players.filter((player) => player.filledBoxes === maxBoxes); + + if (result.length > 1) { + return "DRAW"; + } else { + return result[0]; + } + } + + onPlayerSwitch() { + this.updatePlayerNameUI(); + } + + // If a box is filled, increment players' score with the number of boxes filled by him/her and update UI + onBoxFill() { + this.currentPlayer.filledBoxes++; + this.updatePlayerScoreUI(); + this.updateScoreboard(); + } + + // Add players to UI + addPlayersUI() { + const scoreboard = document.querySelector('.scoreboard'); + scoreboard.innerHTML = ''; // Clear existing content + + this.players.forEach((player, index) => { + const div = document.createElement("div"); + div.classList.add("player"); + + // Maintain filled boxes. + const b = document.createElement("b"); + b.classList.add("filled-boxes"); + b.textContent = player.filledBoxes; + b.style.background = player.color; + this.players[index]["filledBoxesUI"] = b; + + // Maintain player name. + const span = document.createElement("span"); + span.textContent = player.name; + + div.appendChild(b); + div.appendChild(span); + + // Adding score and name to the element + this.playersUI.appendChild(div); + + // Create scoreboard element + const scoreDiv = document.createElement('div'); + scoreDiv.classList.add('score', `player${index + 1}-score`); + scoreDiv.innerHTML = ` + ${player.name} + 0 + `; + scoreboard.appendChild(scoreDiv); + }); + } + + // Update player score UI used while switching player + updatePlayerScoreUI() { + this.currentPlayer.filledBoxesUI.innerText = this.currentPlayer.filledBoxes; + } + + // Update player name UI used while switching player + updatePlayerNameUI() { + this.playerNameUI.innerText = this.currentPlayer.name; + this.playerTurnBgUI.style.background = this.currentPlayer.color; + } + + updateScoreboard() { + this.players.forEach((player, index) => { + const scoreElement = document.getElementById(`player${index + 1}-score`); + if (scoreElement) { + scoreElement.textContent = player.filledBoxes; + } + }); + } + + makeScoreboardDraggable() { + const scoreboardContainer = document.querySelector('.scoreboard-container'); + let isDragging = false; + let currentX; + let currentY; + let initialX; + let initialY; + let xOffset = 0; + let yOffset = 0; + + scoreboardContainer.addEventListener("mousedown", dragStart); + document.addEventListener("mousemove", drag); + document.addEventListener("mouseup", dragEnd); + + function dragStart(e) { + initialX = e.clientX - xOffset; + initialY = e.clientY - yOffset; + + if (e.target === scoreboardContainer) { + isDragging = true; + } + } + + function drag(e) { + if (isDragging) { + e.preventDefault(); + currentX = e.clientX - initialX; + currentY = e.clientY - initialY; + + xOffset = currentX; + yOffset = currentY; + + setTranslate(currentX, currentY, scoreboardContainer); + } + } + + function dragEnd(e) { + initialX = currentX; + initialY = currentY; + + isDragging = false; + } + + function setTranslate(xPos, yPos, el) { + el.style.transform = `translate3d(${xPos}px, ${yPos}px, 0)`; + } + } + + eventExist(event) { + return this.events.hasOwnProperty(event); + } + + // Add event listeners + addEventListener(event, callback) { + if (!this.eventExist(event)) { + console.error(`${event} event is not defined`); + return; + } + + this.events[event].push(callback); + } + + // Remove event listeners + removeEventListener(event, callback) { + if (!this.eventExist(event)) { + console.error(`${event} event is not defined`); + return; + } + this.events[event].splice(this.events[event].indexOf(callback), 1); + } + + // Invoke event listeners + invokeEvent(event, args) { + if (!this.eventExist(event)) { + console.error(`${event} event is not defined`); + return; + } + this.events[event].forEach((callback) => callback(args)); + } + + // Switch player + switchPlayer() { + if (!this.isGameover) { + this.currentPlayerIndex = ++this.currentPlayerIndex % this.players.length; + this.currentPlayer = this.players[this.currentPlayerIndex]; + this.invokeEvent("playerSwitch"); + } + } } // Declaring Global Variables @@ -180,30 +252,30 @@ const bgMusic = new Audio("../assets/sounds/bgMusic.mp3"); var game = null; document.addEventListener("DOMContentLoaded", () => { - bgMusic.volume = 0.1; - bgMusic.play(); - - const rows = calculate(rowsInput, 5, 30); - const columns = calculate(columnsInput, 5, 30); - const playersCount = calculate(playersInput, 2, 6); - - game = new Game(rows, columns, playersCount); - const storedTheme = localStorage.getItem("selectedTheme"); - const video = document.getElementById("myVideo"); - video.src = `/assets/videos/${storedTheme}.mp4`; - - const musicToggleBtn = document.getElementById("music-toggle"); - musicToggleBtn.addEventListener("click", () => { - if (bgMusic.paused) { - bgMusic.play(); - musicToggleBtn.innerText = "Music On"; - } else { - bgMusic.pause(); - musicToggleBtn.innerText = "Music Off"; - } - }); + bgMusic.volume = 0.1; + bgMusic.play(); + + const rows = calculate(rowsInput, 5, 30); + const columns = calculate(columnsInput, 5, 30); + const playersCount = calculate(playersInput, 2, 6); + + game = new Game(rows, columns, playersCount); + const storedTheme = localStorage.getItem("selectedTheme"); + const video = document.getElementById("myVideo"); + video.src = `/assets/videos/${storedTheme}.mp4`; + + const musicToggleBtn = document.getElementById("music-toggle"); + musicToggleBtn.addEventListener("click", () => { + if (bgMusic.paused) { + bgMusic.play(); + musicToggleBtn.innerText = "Music On"; + } else { + bgMusic.pause(); + musicToggleBtn.innerText = "Music Off"; + } + }); }); function calculate(value, min, max) { - return Math.min(Math.max(value, min), max); -} + return Math.min(Math.max(value, min), max); +} \ No newline at end of file diff --git a/pages/game.html b/pages/game.html index 8e90dd7..c6f67d8 100644 --- a/pages/game.html +++ b/pages/game.html @@ -96,7 +96,64 @@ pointer-events: none; z-index: 99999; } - + /* Score board */ + .game-wrapper { + position: relative; + display: flex; + justify-content: center; + align-items: flex-start; + padding: 20px; +} + +.game-container { + display: flex; + justify-content: center; + align-items: center; + width: 100%; +} + +.scoreboard-container { + position: absolute; + left: 20px; + top: 20px; + background-color: rgba(255, 255, 255, 0.9); + border-radius: 15px; + padding: 20px; + box-shadow: 0 0 15px rgba(0, 0, 0, 0.1); + width: 250px; + cursor: move; + z-index: 1000; +} + +.scoreboard-container h2 { + text-align: center; + margin-bottom: 20px; + color: #333; +} + +.scoreboard { + display: flex; + flex-direction: column; + gap: 15px; +} + +.score { + font-size: 22px; + font-weight: bold; + padding: 15px; + border-radius: 10px; + text-align: center; + display: flex; + justify-content: space-between; + align-items: center; +} + +.player1-score { background-color: rgba(255, 192, 203, 0.7); } +.player2-score { background-color: rgba(173, 216, 230, 0.7); } +.player3-score { background-color: rgba(144, 238, 144, 0.7); } +.player4-score { background-color: rgba(255, 0, 255, 0.7); } +.player5-score { background-color: rgba(255, 255, 0, 0.7); } +.player6-score { background-color: rgba(255, 165, 0, 0.7); } /* Tour */ #tour-overlay { @@ -424,7 +481,17 @@ -
+
+
+

Scoreboard

+
+ +
+
+
+
+
+