diff --git a/web/assets/css/game.css b/web/assets/css/game.css index bff5d45..30c5e00 100644 --- a/web/assets/css/game.css +++ b/web/assets/css/game.css @@ -17,6 +17,7 @@ body { align-items: center; justify-content: center; font-family: 'Arial', sans-serif; + user-select: none; } main { @@ -28,6 +29,36 @@ main { border-radius: 10px; min-width: fit-content; flex-shrink: 0; + gap: 16px; +} + +.game-layout { + width: min(95vw, 1000px); +} + +.toolbox { + width: 100%; + background: #dfe5f8; + border-radius: 10px; + padding: 14px; + display: flex; + flex-direction: column; + gap: 10px; +} + +.toolbox h2 { + font-size: 1rem; +} + +.toolbox p { + font-size: 0.9rem; + color: #334; +} + +.glass-palette { + display: flex; + gap: 10px; + flex-wrap: wrap; } /* ================================ @@ -63,6 +94,12 @@ main { margin: 0; position: relative; background-color: #2a2a2a; + user-select: none; + overflow: hidden; +} + +.cell.can-drop { + outline: 2px dashed rgba(0, 0, 0, 0.2); } /* ================================ @@ -71,7 +108,6 @@ main { .empty { background-color: #DADEEF; - border-color: #DADEEF; } .empty:hover { @@ -118,6 +154,10 @@ main { background-position: center; } +.door-open { + opacity: 0.5; +} + .button { background-color: #DADEEF; background-image: url("../img/tiles/ButtonComplete.svg"), url("../img/tiles/Tuile.svg"); @@ -126,6 +166,10 @@ main { background-position: center; } +.button-active { + opacity: 0.7; +} + .demi-wall { background-color: #DADEEF; background-image: url("../img/tiles/VerticaleSemi.svg"); @@ -174,7 +218,6 @@ main { background-position: center; } - /* ================================ LIGHT LASER ================================ */ @@ -221,6 +264,16 @@ main { object-fit: contain; } +.button-door { + background: none; + border: none; + cursor: pointer; + width: 100%; + height: 100%; + position: absolute; + inset: 0; +} + /* ================================ RESPONSIVE ================================ */ diff --git a/web/assets/js/game.js b/web/assets/js/game.js index c0e1e21..403fb7e 100644 --- a/web/assets/js/game.js +++ b/web/assets/js/game.js @@ -13,9 +13,23 @@ const legend = { demiWallCornerUpLeft: 9, demiWallCornerUpRight: 10, demiWallCornerDownLeft: 11, - demiWallCornerDownRight: 12 + demiWallCornerDownRight: 12, + doorOpen: 13, } +const laserColors = { + white: "white", + red: "red", + blue: "blue", + yellow: "yellow", +}; + +const glassOptions = [ + laserColors.red, + laserColors.blue, + laserColors.yellow, +]; + // Grid test let levels = [ @@ -31,6 +45,8 @@ let levels = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ] + + ]; let currentLevelIndex = 0; @@ -39,6 +55,8 @@ let currentLevelIndex = 0; let laserDirection = { dx: 0, dy: 0 }; let laserSegments = {}; let mirrorOrientations = {}; +let activatedButtons = {}; +let openedDoors = {}; function normalizeLaserDirection(dx, dy) { const epsilon = 0.0001; @@ -79,6 +97,31 @@ function getLaserSegmentClass(segmentDirection) { return "laser-diagonal-up"; } +function openAdjacentDoors(x, y) { + // Open adjacent doors (up, down, left, right) + const directions = [ + { dx: 0, dy: -1 }, + { dx: 0, dy: 1 }, + { dx: -1, dy: 0 }, + { dx: 1, dy: 0 } + ]; + + for (let dir of directions) { + const newX = x + dir.dx; + const newY = y + dir.dy; + + if (newX >= 0 && newX < levels[currentLevelIndex][0].length && + newY >= 0 && newY < levels[currentLevelIndex].length) { + if (levels[currentLevelIndex][newY][newX] === legend.door) { + openedDoors[`${newY},${newX}`] = true; + levels[currentLevelIndex][newY][newX] = legend.doorOpen; // Change state to open + } + } + } + + loadGrid(); // Refresh grid to show opened doors +} + function initializeMirrorOrientations() { mirrorOrientations = {}; // Reset for (let y = 0; y < levels[currentLevelIndex].length; y++) { @@ -139,16 +182,30 @@ function loadGrid() { break; case legend.door: cell.classList.add("door"); + if (openedDoors[`${y},${x}`]) { + cell.classList.add("door-open"); + } break; case legend.button: cell.classList.add("button"); + if (activatedButtons[`${y},${x}`]) { + cell.classList.add("button-active"); + } + let button = document.createElement("button"); + button.classList.add("button-door"); + button.type = "button"; + button.onclick = () => { + activatedButtons[`${y},${x}`] = !activatedButtons[`${y},${x}`]; + if (activatedButtons[`${y},${x}`]) { + openAdjacentDoors(x, y); + } + traceLaser(); + }; + cell.appendChild(button); break; case legend.wall: cell.classList.add("wall"); break; - case legend.demiWall: - cell.classList.add("demi-wall"); - break; case legend.target: cell.classList.add("target"); break; @@ -169,6 +226,9 @@ function loadGrid() { case legend.demiWallCornerDownRight: cell.classList.add("demi-wall-corner-down-right"); break; + case legend.doorOpen: + cell.classList.add("door-open"); + break; } lign.appendChild(cell); @@ -212,6 +272,7 @@ let isLevelFinished = false; function traceLaser() { // Reset light laser from previous trace laserSegments = {}; + // Ne pas réinitialiser activatedButtons et openedDoors pour préserver l'état des boutons manuels for (let y = 0; y < levels[currentLevelIndex].length; y++) { for (let x = 0; x < levels[currentLevelIndex][y].length; x++) { if (levels[currentLevelIndex][y][x] === legend.ligthLaser) { @@ -288,15 +349,27 @@ function traceLaser() { laserActive = false; break; - case legend.demiWall: - laserActive = false; + case legend.door: + if (openedDoors[`${currentY},${currentX}`]) { + // La porte est ouverte, le laser la traverse + levels[currentLevelIndex][currentY][currentX] = legend.ligthLaser; + laserSegments[`${currentY},${currentX}`] = { ...laserDirection }; + } else { + // La porte est fermée, le laser s'arrête + laserActive = false; + } break; - case legend.door: - laserActive = false; + case legend.doorOpen: + // Porte ouverte - le laser la traverse + levels[currentLevelIndex][currentY][currentX] = legend.ligthLaser; + laserSegments[`${currentY},${currentX}`] = { ...laserDirection }; break; case legend.button: + // Activer le bouton et ouvrir les portes adjacentes + activatedButtons[`${currentY},${currentX}`] = true; + openAdjacentDoors(currentX, currentY); levels[currentLevelIndex][currentY][currentX] = legend.ligthLaser; laserSegments[`${currentY},${currentX}`] = { ...laserDirection }; laserActive = false; @@ -306,13 +379,13 @@ function traceLaser() { laserDirection = reflectLaser(laserDirection, 135); break; case legend.demiWallCornerUpRight: - laserDirection = reflectLaser(laserDirection, 90); + laserDirection = reflectLaser(laserDirection, 45); break; case legend.demiWallCornerDownLeft: - laserDirection = reflectLaser(laserDirection, 135); + laserDirection = reflectLaser(laserDirection, 45); break; case legend.demiWallCornerDownRight: - laserDirection = reflectLaser(laserDirection, 45); + laserDirection = reflectLaser(laserDirection, 315); break; default: @@ -331,11 +404,20 @@ function traceLaser() { traceLaser(); +// Reset level state +function resetLevel() { + activatedButtons = {}; + openedDoors = {}; + laserSegments = {}; + laserDirection = { dx: 0, dy: 0 }; + isLevelFinished = false; + initializeMirrorOrientations(); + traceLaser(); +} + // If level finishh -> call this function function finish() { setTimeout(() => { alert("Réussi !"); }, 100); } - -