From bb17dc47ba64aad9e684ab5f2b7faae2bad94e58 Mon Sep 17 00:00:00 2001 From: MaciejkaG Date: Sun, 3 Mar 2024 16:55:38 +0100 Subject: [PATCH] Major changes - Fully working ship placement system - Validating ship positions works too - Client side ship data display works as well - Changes to field colors to dark grey instead of light. This improves comfort of use and ensures proper contrast on lower quality displays and ease of use. --- index.js | 12 +++++--- public/assets/css/board.css | 14 ++++++--- public/assets/js/battleships-lib.js | 42 +++++++++++++++++++++++---- public/assets/js/main.js | 43 ++++++++++++++++------------ public/assets/js/socket-game.js | 9 ++++-- utils/battleships.js | 44 +++++++++++++++++++---------- views/board.handlebars | 2 +- 7 files changed, 116 insertions(+), 50 deletions(-) diff --git a/index.js b/index.js index 63f9d11..3ef75af 100644 --- a/index.js +++ b/index.js @@ -238,11 +238,15 @@ io.on('connection', async (socket) => { if (playerGame.data.state === 'preparation') { const playerShips = await GInfo.getPlayerShips(socket); let canPlace = bships.validateShipPosition(playerShips, type, posX, posY, rot); + let shipAvailable = bships.getShipsAvailable(playerShips)[type] > 0; - if (canPlace) { - console.log("placed"); + if (!canPlace) { + socket.emit("toast", "Nie możesz postawić tak statku"); + } else if (!shipAvailable) { + socket.emit("toast", "Nie masz już statków tego typu"); } else { - socket.emit("toast", "Nie możesz postawić tak statku") + await GInfo.placeShip(socket, { type: type, posX: posX, posY: posY, rot: rot }); + socket.emit("placed ship", { type: type, posX: posY, posY: posX, rot: rot }); } } }); @@ -252,7 +256,7 @@ io.on('connection', async (socket) => { if (playerGame.data.state === 'action') { if (bships.checkTurn(playerGame, socket.id)) { - + } } }); diff --git a/public/assets/css/board.css b/public/assets/css/board.css index 53791a3..8e72269 100644 --- a/public/assets/css/board.css +++ b/public/assets/css/board.css @@ -2,9 +2,9 @@ font-size: 20px; - --field: rgb(201, 201, 201); - --mark-line: rgb(136, 136, 136); - --mark-spot: rgb(68, 68, 68); + --field: rgb(36, 36, 36); + --mark-line: rgb(59, 59, 59); + --mark-spot: rgb(90, 90, 90); --mark-ship-valid: hsl(120, 100%, 80%); --mark-ship-invalid: hsl(0, 100%, 80%); --ship-valid: hsl(120, 70%, 55%); @@ -77,13 +77,19 @@ h1,h2,h3,h4,h5,h6 { background: var(--ship-valid); pointer-events: none; opacity: 0; - transition: opacity 0.15s; + transform: scale(0); + transition: opacity 0.25s, transform 0.25s 0.05s; } #secondaryBoard .field .shipField { background: var(--ship-invalid); } +.field .shipField.active { + transform: scale(1); + opacity: 1; +} + .field svg { opacity: 0; width: 100%; diff --git a/public/assets/js/battleships-lib.js b/public/assets/js/battleships-lib.js index 361dfbe..cbc9b27 100644 --- a/public/assets/js/battleships-lib.js +++ b/public/assets/js/battleships-lib.js @@ -3,7 +3,7 @@ class Battleships { if (boardSize>0) { this.boardSize = boardSize; } else { - throw new Error("Wrong boardSize for the 'Battleships' class"); + throw new Error("Incorrect boardSize for the 'Battleships' class"); } } @@ -22,7 +22,9 @@ class Battleships { } getField(x, y) { - if (0 < x && x <= this.boardSize && 0 < y && y <= this.boardSize) { + if (0 <= x && x < this.boardSize && 0 <= y && y < this.boardSize) { + x++; + y++; return $(`#board .row:nth-child(${y}) .field:nth-child(${x})`); } else { throw new RangeError("getField position out of range."); @@ -30,20 +32,50 @@ class Battleships { } getRow(row) { - row = parseInt(row)+1 + row++; if (row<=this.boardSize) { return $(`#board .row:nth-child(${row}) .field`); } else { - throw new RangeError("getColumn position out of range."); + throw new RangeError("getRow position out of range."); } } getColumn(column) { - column = parseInt(column)+1 + column++; if (column<=this.boardSize) { return $(`#board .row .field:nth-child(${column})`); } else { throw new RangeError("getColumn position out of range."); } } + + placeShip(data) { + let fields = []; + switch (data.rot) { + case 0: + for (let i = 0; i <= data.type; i++) { + fields.push([data.posX + i, data.posY]); + } + break; + case 1: + for (let i = 0; i <= data.type; i++) { + fields.push([data.posX, data.posY + i]); + } + break; + case 2: + for (let i = 0; i <= data.type; i++) { + fields.push([data.posX - i, data.posY]); + } + break; + case 3: + for (let i = 0; i <= data.type; i++) { + fields.push([data.posX, data.posY - i]); + } + break; + } + + fields.forEach(field => { + this.getField(field[0], field[1]).children(".shipField").addClass("active"); + }); + } } \ No newline at end of file diff --git a/public/assets/js/main.js b/public/assets/js/main.js index c21b6ec..60d1dc7 100644 --- a/public/assets/js/main.js +++ b/public/assets/js/main.js @@ -10,10 +10,13 @@ var previousRow = $(":not(*)"); var previousColumn = $(":not(*)"); var selectedShip = 0; var shipRotation = 0; +var shipsLeft = [4, 3, 2, 1]; var changedFields = []; var hoveredField = null; +refreshBoardView(); + $("#board .field").hover(function () { hoveredField = this; // Pokaż "miarki" @@ -24,17 +27,15 @@ $("#board .field").hover(function () { changedFields.push(row, column, $(this)); - row.css("background", "rgb(136, 136, 136)"); - column.css("background", "rgb(136, 136, 136)"); + row.css("background", "var(--mark-line)"); + column.css("background", "var(--mark-line)"); - $(this).css("background", "rgb(68, 68, 68)"); + $(this).css("background", "var(--mark-spot)"); previousRow = row; previousColumn = column; // Pokaż podgląd statku - posX++; - posY++; var fields = []; switch (shipRotation) { case 0: @@ -61,7 +62,7 @@ $("#board .field").hover(function () { var fieldElem; let failed = false; - for (let i = 0; i < selectedShip+1; i++) { + for (let i = 0; i <= selectedShip; i++) { const field = fields[i]; try { @@ -74,9 +75,9 @@ $("#board .field").hover(function () { } if (failed) { - fieldElem.css("background", "rgb(255, 163, 163)"); + fieldElem.css("background", "var(--mark-ship-invalid)"); } else { - fieldElem.css("background", "rgb(163, 255, 163)"); + fieldElem.css("background", "var(--mark-ship-valid)"); } changedFields.push(fieldElem); } @@ -84,7 +85,7 @@ $("#board .field").hover(function () { hoveredField = null; // Wyłącz "miarki" po wyjściu kursora z pola (aby się nie duplikowały w przyszłości) changedFields.forEach(field => { - field.css("background", "rgb(201, 201, 201)"); + field.css("background", "var(--field)"); }); changedFields.length = 0; }); @@ -153,9 +154,17 @@ function switchRotation() { } function refreshBoardView() { + let shipsOfType = shipsLeft[selectedShip]; + $("#shipsLeft").html(shipsOfType); + if (!shipsOfType) { + $("#shipsLeft").addClass("danger"); + } else { + $("#shipsLeft").removeClass("danger"); + } + if (hoveredField) { changedFields.forEach(field => { - field.css("background", "rgb(201, 201, 201)"); + field.css("background", "var(--field)"); }); changedFields.length = 0; @@ -166,16 +175,14 @@ function refreshBoardView() { changedFields.push(row, column, $(hoveredField)); - row.css("background", "rgb(136, 136, 136)"); - column.css("background", "rgb(136, 136, 136)"); + row.css("background", "var(--mark-line)"); + column.css("background", "var(--mark-line)"); - $(hoveredField).css("background", "rgb(68, 68, 68)"); + $(hoveredField).css("background", "var(--mark-field)"); previousRow = row; previousColumn = column; - posX++; - posY++; var fields = []; switch (shipRotation) { case 0: @@ -202,7 +209,7 @@ function refreshBoardView() { var fieldElem; let failed = false; - for (let i = 0; i < selectedShip + 1; i++) { + for (let i = 0; i <= selectedShip; i++) { const field = fields[i]; try { @@ -215,9 +222,9 @@ function refreshBoardView() { } if (failed) { - fieldElem.css("background", "rgb(255, 163, 163)"); + fieldElem.css("background", "var(--mark-ship-invalid)"); } else { - fieldElem.css("background", "rgb(163, 255, 163)"); + fieldElem.css("background", "var(--mark-ship-valid)"); } changedFields.push(fieldElem); } diff --git a/public/assets/js/socket-game.js b/public/assets/js/socket-game.js index 16de1f8..456cd75 100644 --- a/public/assets/js/socket-game.js +++ b/public/assets/js/socket-game.js @@ -5,7 +5,6 @@ var timerDestination = null; var gamePhase = 'pregame'; $('.field').on('click', function () { - console.log("Clicked"); socket.emit("place ship", selectedShip, $(this).data('pos-x'), $(this).data('pos-y'), shipRotation); }); @@ -21,6 +20,12 @@ socket.on('toast', (msg) => { }).showToast(); }); +socket.on("placed ship", (data) => { + bsc.placeShip(data); + shipsLeft[data.type]--; + refreshBoardView(); +}); + socket.on('connect', () => { $(".cover h1").html("Oczekiwanie na serwer..."); }); @@ -30,9 +35,7 @@ socket.on("players ready", () => { }); socket.on("player idx", (idx) => { - console.log(idx); playerIdx = idx; - console.log(playerIdx); }); socket.on('turn update', (turnData) => { diff --git a/utils/battleships.js b/utils/battleships.js index 92b3400..6a7d49e 100644 --- a/utils/battleships.js +++ b/utils/battleships.js @@ -35,14 +35,23 @@ export class GameInfo { const gameId = socket.session.activeGame; const key = `game:${gameId}`; - await this.redis.json.set(key, '$.state', 'action'); - let nextPlayer = await this.redis.json.get(key, '$.nextPlayer'); + await this.redis.json.set(key, '.state', 'action'); + let nextPlayer = await this.redis.json.get(key, '.nextPlayer'); nextPlayer = nextPlayer === 0 ? 1 : 0; - await this.redis.json.set(key, '$.nextPlayer', nextPlayer); + await this.redis.json.set(key, '.nextPlayer', nextPlayer); const UTCTs = Math.floor((new Date()).getTime() / 1000 + 30); this.io.to(gameId).emit('turn update', { turn: 0, phase: "action", timerToUTC: UTCTs }); } + + async placeShip(socket, shipData) { + const gameId = socket.session.activeGame; + const key = `game:${gameId}`; + const hostId = (await this.redis.json.get(key, {path: '$.hostId'}))[0]; + + const playerIdx = socket.request.session.id === hostId ? 0 : 1; + let res = await this.redis.json.arrAppend(key, `.boards[${playerIdx}].ships`, shipData); + } } export function isPlayerInRoom(socket) { @@ -95,12 +104,10 @@ export function resetTimers() { // }); // } -export function getShipsAvailable(data, playerIdx) { +export function getShipsAvailable(ships) { let shipsLeft = [4, 3, 2, 1]; - const playerShips = shipsLeft.boards[playerIdx].ships; - - playerShips.forEach(ship => { + ships.forEach(ship => { shipsLeft[ship.type]--; }); @@ -152,8 +159,6 @@ export function checkHit(data, playerIdx, posX, posY) { } export function validateShipPosition(ships, type, posX, posY, rot) { - let multips; - let boardRender = []; for (let i = 0; i < 10; i++) { @@ -165,6 +170,7 @@ export function validateShipPosition(ships, type, posX, posY, rot) { } ships.forEach(ship => { + let multips; switch (ship.rot) { @@ -181,7 +187,7 @@ export function validateShipPosition(ships, type, posX, posY, rot) { break; case 3: - multips = [1, 0]; + multips = [-1, 0]; break; } @@ -190,6 +196,8 @@ export function validateShipPosition(ships, type, posX, posY, rot) { } }); + let multips; + switch (rot) { case 0: multips = [0, 1]; @@ -204,16 +212,22 @@ export function validateShipPosition(ships, type, posX, posY, rot) { break; case 3: - multips = [1, 0]; + multips = [-1, 0]; break; } - for (let i = 0; i < type + 1; i++) { - if (posY + multips[1] * i > 9 || posY + multips[1] * i < 0 || posX + multips[0] * i > 9 || posX + multips[0] * i < 0) { + for (let x = 0; x <= type; x++) { + if (posY + multips[1] * x > 9 || posY + multips[1] * x < 0 || posX + multips[0] * x > 9 || posX + multips[0] * x < 0) { return false; } - if (boardRender[posY + multips[1] * i][posX + multips[0] * i]) { - return false; + + let subtrahents = [[0, 0], [0, 1], [1, 0], [0, -1], [-1, 0], [1, 1], [-1, -1], [1, -1], [-1, 1]]; // Usuń cztery ostatnie elementy jeżeli chcesz by statki mogły się stykać rogami + for (let y = 0; y < subtrahents.length; y++) { + const idxY = posY - subtrahents[y][0] + multips[1] * x; + const idxX = posX - subtrahents[y][1] + multips[0] * x; + if (!(idxY < 0 || idxY > 9 || idxX < 0 || idxX > 9) && boardRender[idxY][idxX]) { + return false; + } } } diff --git a/views/board.handlebars b/views/board.handlebars index a86c3f6..f71da48 100644 --- a/views/board.handlebars +++ b/views/board.handlebars @@ -10,7 +10,7 @@

Wybrany statek

Jednomasztowiec

-

Dostępne: 1

+

Dostępne: 1

Sterowanie