mirror of
https://github.com/MaciejkaG/statki.git
synced 2024-11-30 01:42:54 +01:00
Major changes
- Hit registration works perfectly now - Multiple color tweaks - Enhanced timer animation To-do: - Detecting game end - Multiple fixes - Revamp round timers (they are global now, so resetting a timer resets it for all games)
This commit is contained in:
parent
8f3538417a
commit
6021305f4a
33
index.js
33
index.js
@ -29,7 +29,7 @@ const io = new Server(server);
|
||||
const redis = createClient();
|
||||
redis.on('error', err => console.log('Redis Client Error', err));
|
||||
await redis.connect();
|
||||
redis.flushDb();
|
||||
// redis.flushDb();
|
||||
|
||||
const GInfo = new bships.GameInfo(redis, io);
|
||||
|
||||
@ -224,7 +224,16 @@ io.on('connection', async (socket) => {
|
||||
|
||||
let UTCTs = Math.floor((new Date()).getTime() / 1000 + 90);
|
||||
io.to(playerGame.id).emit('turn update', { turn: 0, phase: "preparation", timerToUTC: UTCTs });
|
||||
bships.timer(90, () => {
|
||||
bships.timer(20, async () => {
|
||||
const playerGame = await GInfo.getPlayerGameData(socket);
|
||||
for (let i = 0; i < playerGame.data.boards.length; i++) {
|
||||
const ships = playerGame.data.boards[i].ships;
|
||||
if (!ships.length) {
|
||||
AFKEnd(playerGame.id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GInfo.endPrepPhase(socket);
|
||||
bships.timer(30, () => {
|
||||
AFKEnd(playerGame.id);
|
||||
@ -250,7 +259,7 @@ io.on('connection', async (socket) => {
|
||||
} else if (!shipAvailable) {
|
||||
socket.emit("toast", "Nie masz już statków tego typu");
|
||||
} else {
|
||||
await GInfo.placeShip(socket, { type: type, posX: posX, posY: posY, rot: rot });
|
||||
await GInfo.placeShip(socket, { type: type, posX: posX, posY: posY, rot: rot, hits: Array.from(new Array(type+1), () => false) });
|
||||
socket.emit("placed ship", { type: type, posX: posX, posY: posY, rot: rot });
|
||||
}
|
||||
}
|
||||
@ -265,12 +274,24 @@ io.on('connection', async (socket) => {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('shoot', async () => {
|
||||
socket.on('shoot', async (posX, posY) => {
|
||||
const playerGame = await GInfo.getPlayerGameData(socket);
|
||||
|
||||
if (playerGame.data.state === 'action') {
|
||||
if (bships.checkTurn(playerGame, socket.request.session.id)) {
|
||||
|
||||
if (bships.checkTurn(playerGame.data, socket.request.session.id)) {
|
||||
const enemyIdx = socket.request.session.id === playerGame.data.hostId ? 1 : 0;
|
||||
|
||||
if (await GInfo.shootShip(socket, posX, posY)) {
|
||||
io.to(playerGame.id).emit("shot hit", enemyIdx, posX, posY);
|
||||
} else {
|
||||
io.to(playerGame.id).emit("shot missed", enemyIdx, posX, posY);
|
||||
}
|
||||
|
||||
await GInfo.passTurn(socket);
|
||||
bships.resetTimers();
|
||||
bships.timer(30, () => {
|
||||
AFKEnd(playerGame.id);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,18 +1,23 @@
|
||||
:root {
|
||||
font-size: 20px;
|
||||
|
||||
|
||||
--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%);
|
||||
|
||||
--mark-hit: #ffffff;
|
||||
|
||||
--ship-valid: hsl(120, 70%, 55%);
|
||||
--ship-invalid: hsl(0, 70%, 55%);
|
||||
--ship-miss: hsl(0, 0%, 18%);
|
||||
|
||||
--dynamic: rgb(83, 83, 245);
|
||||
--danger: rgb(243, 56, 56);
|
||||
--important: rgb(203, 50, 241);
|
||||
|
||||
color: rgb(136, 136, 136)
|
||||
}
|
||||
|
||||
@ -21,7 +26,7 @@
|
||||
}
|
||||
|
||||
body {
|
||||
background: black;
|
||||
background-color: black;
|
||||
color: white;
|
||||
font-family: 'Lato', sans-serif;
|
||||
transition: opacity 0.3s ease;
|
||||
@ -67,14 +72,14 @@ h1,h2,h3,h4,h5,h6 {
|
||||
aspect-ratio: 1;
|
||||
border-radius: 20%;
|
||||
cursor: pointer;
|
||||
transition: background 0.1s;
|
||||
transition: background-color 0.1s;
|
||||
}
|
||||
|
||||
.field .shipField {
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
border-radius: 20%;
|
||||
background: var(--ship-valid);
|
||||
background-color: var(--ship-valid);
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
@ -82,7 +87,7 @@ h1,h2,h3,h4,h5,h6 {
|
||||
}
|
||||
|
||||
#secondaryBoard .field .shipField {
|
||||
background: var(--ship-invalid);
|
||||
background-color: var(--ship-invalid);
|
||||
}
|
||||
|
||||
.field.active .shipField {
|
||||
@ -208,9 +213,9 @@ h1,h2,h3,h4,h5,h6 {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
background: rgb(0, 0, 0, 0.6);
|
||||
background-color: rgb(0, 0, 0, 0.6);
|
||||
backdrop-filter: blur(20px);
|
||||
transition: opacity 0.5s;
|
||||
transition: opacity 0.5s, transform 0.5s;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
@ -219,9 +224,9 @@ h1,h2,h3,h4,h5,h6 {
|
||||
}
|
||||
|
||||
@keyframes timerDanger {
|
||||
0% { color: var(--important) }
|
||||
50% { color: var(--danger) }
|
||||
100% { color: var(--important) }
|
||||
0% { color: var(--important); transform: scale(1); }
|
||||
50% { color: var(--danger); transform: scale(1.1); }
|
||||
100% { color: var(--important); transform: scale(1); }
|
||||
}
|
||||
|
||||
#timer.active {
|
||||
|
@ -12,7 +12,7 @@ class Battleships {
|
||||
for (var i = 0; i < size; i++) {
|
||||
let row = "<div class=\"row\">";
|
||||
for (var n = 0; n < size; n++) {
|
||||
row += `<div class="field" data-pos-x="${n}" data-pos-y="${i}"><div class="shipField"><svg xmlns='http://www.w3.org/2000/svg' version='1.1' preserveAspectRatio='none' viewBox='0 0 100 100'><path d='M100 0 L0 100 ' stroke='#f33838' stroke-width='10'/><path d='M0 0 L100 100 ' stroke='#f33838' stroke-width='10'/></svg></div></div>`;
|
||||
row += `<div class="field" data-pos-x="${n}" data-pos-y="${i}"><div class="shipField"><svg xmlns='http://www.w3.org/2000/svg' version='1.1' preserveAspectRatio='none' viewBox='0 0 100 100'><path d='M100 0 L0 100 ' stroke='#ffffff' stroke-width='10'/><path d='M0 0 L100 100 ' stroke='#ffffff' stroke-width='10'/></svg></div></div>`;
|
||||
}
|
||||
row += "</div>";
|
||||
board += row;
|
||||
@ -31,6 +31,16 @@ class Battleships {
|
||||
}
|
||||
}
|
||||
|
||||
getFieldSecondary(x, y) {
|
||||
if (0 <= x && x < this.boardSize && 0 <= y && y < this.boardSize) {
|
||||
x++;
|
||||
y++;
|
||||
return $(`#secondaryBoard .row:nth-child(${y}) .field:nth-child(${x})`);
|
||||
} else {
|
||||
throw new RangeError("getField position out of range.");
|
||||
}
|
||||
}
|
||||
|
||||
getRow(row) {
|
||||
row++;
|
||||
if (row<=this.boardSize) {
|
||||
@ -49,6 +59,32 @@ class Battleships {
|
||||
}
|
||||
}
|
||||
|
||||
setField(x, y, state, primary = false) {
|
||||
if (state==="hit") {
|
||||
this.getField(x, y).children().children("svg").html("<path d='M100 0 L0 100 ' stroke='#ffffff' stroke-width='10'/><path d='M0 0 L100 100 ' stroke='#ffffff' stroke-width='10'/>");
|
||||
this.getField(x, y).addClass("hit");
|
||||
} else if (state==="miss") {
|
||||
this.getField(x, y).children(".shipField").css("background-color", "var(--ship-miss)");
|
||||
this.getField(x, y).addClass("active hit");
|
||||
this.getField(x, y).children().children("svg").html("<circle fill='#ffffff' cx='50' cy='50' r='20' />");
|
||||
}
|
||||
|
||||
this.getFieldSecondary(x, y).addClass("hit");
|
||||
}
|
||||
|
||||
setFieldEnemy(x, y, state, primary = false) {
|
||||
if (state === "hit") {
|
||||
this.getFieldSecondary(x, y).children().children("svg").html("<path d='M100 0 L0 100 ' stroke='#ffffff' stroke-width='10'/><path d='M0 0 L100 100 ' stroke='#ffffff' stroke-width='10'/>");
|
||||
this.getFieldSecondary(x, y).addClass("active hit");
|
||||
} else if (state === "miss") {
|
||||
this.getFieldSecondary(x, y).children(".shipField").css("background-color", "var(--ship-miss)");
|
||||
this.getFieldSecondary(x, y).addClass("active hit");
|
||||
this.getFieldSecondary(x, y).children().children("svg").html("<circle fill='#ffffff' cx='50' cy='50' r='20' />");
|
||||
}
|
||||
|
||||
this.getFieldSecondary(x, y).addClass("hit");
|
||||
}
|
||||
|
||||
placeShip(data) {
|
||||
let fields = [];
|
||||
switch (data.rot) {
|
||||
|
@ -30,20 +30,20 @@ $(".board .field").hover(function () {
|
||||
|
||||
changedFields.push(row, column, $(this));
|
||||
|
||||
row.css("background", "var(--mark-line)");
|
||||
column.css("background", "var(--mark-line)");
|
||||
row.css("background-color", "var(--mark-line)");
|
||||
column.css("background-color", "var(--mark-line)");
|
||||
|
||||
previousRow = row;
|
||||
previousColumn = column;
|
||||
|
||||
if (postPrep) {
|
||||
if (myTurn) {
|
||||
$(this).css("background", "var(--mark-ship-invalid)");
|
||||
$(this).css("background-color", "var(--mark-ship-invalid)");
|
||||
} else {
|
||||
(this).css("background", "var(--mark-spot)");
|
||||
$(this).css("background-color", "var(--mark-spot)");
|
||||
}
|
||||
} else {
|
||||
$(this).css("background", "var(--mark-spot)");
|
||||
$(this).css("background-color", "var(--mark-spot)");
|
||||
|
||||
// Pokaż podgląd statku
|
||||
|
||||
@ -87,9 +87,9 @@ $(".board .field").hover(function () {
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
fieldElem.css("background", "var(--mark-ship-invalid)");
|
||||
fieldElem.css("background-color", "var(--mark-ship-invalid)");
|
||||
} else {
|
||||
fieldElem.css("background", "var(--mark-ship-valid)");
|
||||
fieldElem.css("background-color", "var(--mark-ship-valid)");
|
||||
}
|
||||
changedFields.push(fieldElem);
|
||||
}
|
||||
@ -98,7 +98,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", "var(--field)");
|
||||
field.css("background-color", "var(--field)");
|
||||
});
|
||||
changedFields.length = 0;
|
||||
});
|
||||
@ -185,7 +185,7 @@ function refreshBoardView() {
|
||||
|
||||
if (hoveredField) {
|
||||
changedFields.forEach(field => {
|
||||
field.css("background", "var(--field)");
|
||||
field.css("background-color", "var(--field)");
|
||||
});
|
||||
changedFields.length = 0;
|
||||
|
||||
@ -196,10 +196,10 @@ function refreshBoardView() {
|
||||
|
||||
changedFields.push(row, column, $(hoveredField));
|
||||
|
||||
row.css("background", "var(--mark-line)");
|
||||
column.css("background", "var(--mark-line)");
|
||||
row.css("background-color", "var(--mark-line)");
|
||||
column.css("background-color", "var(--mark-line)");
|
||||
|
||||
$(hoveredField).css("background", "var(--mark-field)");
|
||||
$(hoveredField).css("background-color", "var(--mark-field)");
|
||||
|
||||
previousRow = row;
|
||||
previousColumn = column;
|
||||
@ -243,9 +243,9 @@ function refreshBoardView() {
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
fieldElem.css("background", "var(--mark-ship-invalid)");
|
||||
fieldElem.css("background-color", "var(--mark-ship-invalid)");
|
||||
} else {
|
||||
fieldElem.css("background", "var(--mark-ship-valid)");
|
||||
fieldElem.css("background-color", "var(--mark-ship-valid)");
|
||||
}
|
||||
changedFields.push(fieldElem);
|
||||
}
|
||||
|
@ -5,10 +5,15 @@ var timerDestination = null;
|
||||
var gamePhase = 'pregame';
|
||||
var occupiedFields = [];
|
||||
|
||||
$('.field').on('click', function () {
|
||||
$('#board .field').on('click', function () {
|
||||
socket.emit("place ship", selectedShip, $(this).data('pos-x'), $(this).data('pos-y'), shipRotation);
|
||||
});
|
||||
|
||||
$('#secondaryBoard .field').on('click', function () {
|
||||
socket.emit("shoot", $(this).data('pos-x'), $(this).data('pos-y'));
|
||||
});
|
||||
|
||||
|
||||
$('.field').on('contextmenu', function () {
|
||||
if ($(this).hasClass('active')) {
|
||||
let originPos = occupiedFields.find((elem) => elem.pos[0] == $(this).data('pos-x') && elem.pos[1] == $(this).data('pos-y')).origin;
|
||||
@ -54,6 +59,24 @@ socket.on("removed ship", (data) => {
|
||||
refreshBoardView();
|
||||
});
|
||||
|
||||
socket.on("shot hit", (victimIdx, posX, posY) => {
|
||||
console.log("hit");
|
||||
if (victimIdx === playerIdx) {
|
||||
bsc.setField(posX, posY, "hit");
|
||||
} else {
|
||||
bsc.setFieldEnemy(posX, posY, "hit");
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("shot missed", (victimIdx, posX, posY) => {
|
||||
console.log("missed");
|
||||
if (victimIdx === playerIdx) {
|
||||
bsc.setField(posX, posY, "miss");
|
||||
} else {
|
||||
bsc.setFieldEnemy(posX, posY, "miss");
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('connect', () => {
|
||||
$(".cover h1").html("Oczekiwanie na serwer...");
|
||||
});
|
||||
|
@ -36,12 +36,12 @@ export class GameInfo {
|
||||
const key = `game:${gameId}`;
|
||||
|
||||
await this.redis.json.set(key, '.state', 'action');
|
||||
let nextPlayer = await this.redis.json.get(key, '.nextPlayer');
|
||||
let nextPlayer = await this.redis.json.get(key, { path:'.nextPlayer' });
|
||||
nextPlayer = nextPlayer === 0 ? 1 : 0;
|
||||
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 });
|
||||
this.io.to(gameId).emit('turn update', { turn: nextPlayer, phase: "action", timerToUTC: UTCTs });
|
||||
}
|
||||
|
||||
async placeShip(socket, shipData) {
|
||||
@ -73,6 +73,37 @@ export class GameInfo {
|
||||
await this.redis.json.set(key, `.boards[${playerIdx}].ships`, playerShips);
|
||||
return deletedShip;
|
||||
}
|
||||
|
||||
async shootShip(socket, posX, posY) {
|
||||
const gameId = socket.session.activeGame;
|
||||
const key = `game:${gameId}`;
|
||||
const hostId = (await this.redis.json.get(key, { path: '.hostId' }));
|
||||
|
||||
const enemyIdx = socket.request.session.id === hostId ? 1 : 0;
|
||||
const playerIdx = enemyIdx ? 0 : 1;
|
||||
|
||||
let playerShips = await this.redis.json.get(key, { path: `.boards[${enemyIdx}].ships` });
|
||||
|
||||
var check = checkHit(playerShips, posX, posY);
|
||||
|
||||
if (!check) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var shotShip;
|
||||
for (let i = 0; i < playerShips.length; i++) {
|
||||
const ship = playerShips[i];
|
||||
|
||||
if (ship.posX === check.originPosX & ship.posY === check.originPosY) {
|
||||
shotShip = ship;
|
||||
playerShips[i].hits[check.fieldIdx] = true;
|
||||
}
|
||||
}
|
||||
|
||||
await this.redis.json.set(key, `.boards[${enemyIdx}].ships`, playerShips);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export function isPlayerInRoom(socket) {
|
||||
@ -135,11 +166,7 @@ export function getShipsAvailable(ships) {
|
||||
return shipsLeft;
|
||||
}
|
||||
|
||||
export function checkHit(data, playerIdx, posX, posY) {
|
||||
playerIdx = playerIdx === 0 ? 1 : 0;
|
||||
|
||||
let enemyBoard = data.boards[playerIdx];
|
||||
|
||||
export function checkHit(ships, posX, posY) {
|
||||
let boardRender = [];
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
@ -150,7 +177,7 @@ export function checkHit(data, playerIdx, posX, posY) {
|
||||
boardRender.push(array);
|
||||
}
|
||||
|
||||
enemyBoard.ships.forEach(ship => {
|
||||
ships.forEach(ship => {
|
||||
let multips;
|
||||
|
||||
switch (ship.rot) {
|
||||
@ -172,7 +199,8 @@ export function checkHit(data, playerIdx, posX, posY) {
|
||||
}
|
||||
|
||||
for (let i = 0; i < ship.type + 2; i++) {
|
||||
boardRender[ship.posX + multips[1] * i][ship.posY + multips[0] * i] = true;
|
||||
console.log(`boardRender[${ship.posX + multips[1] * i}][${ship.posY + multips[0] * i}]`)
|
||||
boardRender[ship.posX + multips[1] * i][ship.posY + multips[0] * i] = {fieldIdx: i, originPosX: ship.posX, originPosY: ship.posY};
|
||||
}
|
||||
});
|
||||
|
||||
@ -180,6 +208,10 @@ export function checkHit(data, playerIdx, posX, posY) {
|
||||
}
|
||||
|
||||
export function validateShipPosition(ships, type, posX, posY, rot) {
|
||||
if (type < 0 || type > 3 || rot < 0 || rot > 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let boardRender = [];
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
|
Loading…
Reference in New Issue
Block a user