8 Commits

Author SHA1 Message Date
Sysy's
edea5e0972 Remove rotatorButton on lvl 1 2026-03-31 13:15:38 +02:00
Sysy's
f3809db72b Merge branch 'feature/grid' of https://git.ninolbt.com/Nono/Projet_48h into feature/grid 2026-03-31 13:12:34 +02:00
Sysy's
68b6493e50 Add rotator buttons and auto-rotating mirrors
Introduce a new rotator button tile and mirror auto-rotation feature. CSS adds styles for rotator buttons and locked mirror display. JS: add legend entry and rotatorButtons config, track activeRotatorButtons and rotatorIntervals, implement rotateMirrorStep, isMirrorControlledByButton, syncRotatorButtons and stopAllRotatorButtons; wire rotator behavior into traceLaser and loadGrid so rotator buttons activate intervals that rotate target mirrors automatically and lock out manual rotation. Refactor rotateMirror to reuse rotation step logic and ensure rotator intervals are cleared when advancing levels.
2026-03-31 13:11:30 +02:00
a267884dbe Level 3 2026-03-31 12:59:59 +02:00
64b0e5e770 Level 2 2026-03-31 12:19:52 +02:00
57b37d0139 Level 2 2026-03-31 12:16:45 +02:00
4939b74fad Level 2 2026-03-31 12:11:39 +02:00
7e5de16a02 Level 2 2026-03-31 12:09:01 +02:00
2 changed files with 247 additions and 27 deletions

View File

@@ -143,6 +143,40 @@ main {
background-position: center; background-position: center;
} }
.captor {
background-color: #DADEEF;
background-image: url("../img/tiles/Capteur-1.svg");
background-size: 100%;
background-repeat: no-repeat;
background-position: center;
transform: rotate(180deg);
}
.captor-turn {
background-color: #DADEEF;
background-image: url("../img/tiles/Capteur-2.svg");
background-size: 100%;
background-repeat: no-repeat;
background-position: center;
}
.cable {
background-color: #DADEEF;
background-image: url("../img/tiles/CableV.svg");
background-size: 100%;
background-repeat: no-repeat;
background-position: center;
transform: rotate(90deg);
}
.cable-vertical {
background-color: #DADEEF;
background-image: url("../img/tiles/CableV.svg");
background-size: 100%;
background-repeat: no-repeat;
background-position: center;
}
.door { .door {
background-color: #DADEEF; background-color: #DADEEF;
background-image: url("../img/tiles/WoodenDoor.svg"); background-image: url("../img/tiles/WoodenDoor.svg");
@@ -174,6 +208,14 @@ main {
background-position: center; background-position: center;
} }
.button-rotator {
background-color: #DADEEF;
background-image: url("../img/tiles/ButtonProfile.svg"), url("../img/tiles/Tuile.svg");
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
}
.button-active { .button-active {
opacity: 0.7; opacity: 0.7;
} }
@@ -274,6 +316,10 @@ main {
justify-content: center; justify-content: center;
} }
.btn-mirror-locked {
cursor: default;
}
.mirror-img { .mirror-img {
width: 80%; width: 80%;
height: 80%; height: 80%;

View File

@@ -16,6 +16,11 @@ const legend = {
demiWallCornerDownRight: 12, demiWallCornerDownRight: 12,
doorOpen: 13, doorOpen: 13,
button2: 14, button2: 14,
captor: 15,
cable: 16,
captorTurn: 17,
cableVertical: 18,
rotatorButton: 20,
}; };
const laserColors = { const laserColors = {
@@ -44,20 +49,66 @@ 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],
[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],
], ],
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 11, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 17, 0, 0, 3, 6, 0, 0, 0, 0],
[0, 0, 6, 6, 6, 6, 18, 6, 6, 0, 6, 0, 0, 0, 0],
[0, 0, 7, 0, 0, 0, 4, 0, 0, 12, 6, 0, 0, 0, 0],
[0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 9, 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, 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, 0, 0, 0, 0],
],
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 11, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 10, 6, 0, 0, 0, 0],
[0, 0, 0, 0, 3, 16, 16, 15, 0, 3, 6, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 6, 0, 0, 0, 0],
[0, 0, 0, 0, 12, 6, 6, 6, 6, 6, 9, 0, 0, 0, 0],
[0, 0, 0, 0, 6, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 6, 0, 0, 0, 3, 0, 7, 0, 0, 0, 0],
[0, 0, 0, 0, 6, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 10, 6, 6, 6, 6, 6, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0],
], */
]; ];
let currentLevelIndex = 0; let currentLevelIndex = 0;
const initialMirrorAngles = { const initialMirrorAngles = {
"6,4": 315, "6,4": 315,
"4,3": 315,
}; };
const buttonGroups = { const buttonGroups = {
"4,6": 1, "4,6": 1,
"4,7": 2,
}; };
const doorGroups = { const doorGroups = {
"4,7": 1, "4,7": 1,
"4,8": 2,
};
const rotatorButtons = {
}; };
let laserDirection = { dx: 0, dy: 0 }; let laserDirection = { dx: 0, dy: 0 };
@@ -67,6 +118,8 @@ let glassPlacements = {};
let activatedButtons = {}; let activatedButtons = {};
let openedDoors = {}; let openedDoors = {};
let isLevelFinished = false; let isLevelFinished = false;
let activeRotatorButtons = {};
let rotatorIntervals = {};
function getCurrentLevel() { function getCurrentLevel() {
return levels[currentLevelIndex]; return levels[currentLevelIndex];
@@ -149,6 +202,74 @@ function openDoorsFromButton(x, y) {
} }
} }
function getRotatorButtonConfig(x, y) {
return rotatorButtons[`${y},${x}`];
}
function isMirrorControlledByButton(x, y) {
const rotatorEntries = Object.values(rotatorButtons);
for (let i = 0; i < rotatorEntries.length; i++) {
const rotatorConfig = rotatorEntries[i];
if (rotatorConfig.mirrorX === x && rotatorConfig.mirrorY === y) {
return true;
}
}
return false;
}
function rotateMirrorStep(x, y, angleStep) {
const coordKey = `${y},${x}`;
if (getCurrentLevel()[y][x] !== legend.mirror) {
return;
}
let currentAngle = mirrorOrientations[coordKey] || 0;
currentAngle = (currentAngle + angleStep) % 360;
if (currentAngle < 0) {
currentAngle += 360;
}
mirrorOrientations[coordKey] = currentAngle;
}
function syncRotatorButtons() {
const rotatorKeys = Object.keys(rotatorButtons);
for (let i = 0; i < rotatorKeys.length; i++) {
const key = rotatorKeys[i];
const config = rotatorButtons[key];
const isActive = activeRotatorButtons[key] === true;
if (isActive && !rotatorIntervals[key]) {
rotatorIntervals[key] = window.setInterval(() => {
rotateMirrorStep(config.mirrorX, config.mirrorY, -22.5);
traceLaser();
}, 1000);
}
if (!isActive && rotatorIntervals[key]) {
window.clearInterval(rotatorIntervals[key]);
delete rotatorIntervals[key];
}
}
}
function stopAllRotatorButtons() {
const intervalKeys = Object.keys(rotatorIntervals);
for (let i = 0; i < intervalKeys.length; i++) {
const key = intervalKeys[i];
window.clearInterval(rotatorIntervals[key]);
}
rotatorIntervals = {};
}
function saveLaserSegment(x, y, direction, color) { function saveLaserSegment(x, y, direction, color) {
laserSegments[`${y},${x}`] = { laserSegments[`${y},${x}`] = {
direction: { ...direction }, direction: { ...direction },
@@ -314,13 +435,20 @@ function loadGrid() {
case legend.mirror: case legend.mirror:
cell.classList.add("mirror"); cell.classList.add("mirror");
const currentAngle = mirrorOrientations[`${y},${x}`] || 0; const currentAngle = mirrorOrientations[`${y},${x}`] || 0;
const btnMirror = document.createElement("button");
btnMirror.classList.add("btn-mirror");
btnMirror.type = "button";
const img = document.createElement("img"); const img = document.createElement("img");
img.src = "../../assets/img/tiles/Mirror.svg"; img.src = "../../assets/img/tiles/Mirror.svg";
img.classList.add("mirror-img"); img.classList.add("mirror-img");
img.style.transform = `rotate(${currentAngle}deg)`; img.style.transform = `rotate(${currentAngle}deg)`;
if (isMirrorControlledByButton(x, y)) {
const mirrorDisplay = document.createElement("div");
mirrorDisplay.classList.add("btn-mirror", "btn-mirror-locked");
mirrorDisplay.appendChild(img);
cell.appendChild(mirrorDisplay);
} else {
const btnMirror = document.createElement("button");
btnMirror.classList.add("btn-mirror");
btnMirror.type = "button";
btnMirror.appendChild(img); btnMirror.appendChild(img);
btnMirror.onmousedown = (event) => { btnMirror.onmousedown = (event) => {
event.preventDefault(); event.preventDefault();
@@ -331,6 +459,7 @@ function loadGrid() {
}; };
btnMirror.oncontextmenu = (event) => event.preventDefault(); btnMirror.oncontextmenu = (event) => event.preventDefault();
cell.appendChild(btnMirror); cell.appendChild(btnMirror);
}
break; break;
case legend.door: case legend.door:
cell.classList.add("door"); cell.classList.add("door");
@@ -353,6 +482,12 @@ function loadGrid() {
cell.classList.add("button-active"); cell.classList.add("button-active");
} }
break; break;
case legend.rotatorButton:
cell.classList.add("button", "button-rotator");
if (activatedButtons[`${y},${x}`]) {
cell.classList.add("button-active");
}
break;
case legend.wall: case legend.wall:
cell.classList.add("wall"); cell.classList.add("wall");
break; break;
@@ -371,6 +506,18 @@ function loadGrid() {
case legend.demiWallCornerDownRight: case legend.demiWallCornerDownRight:
cell.classList.add("demi-wall-corner-down-right"); cell.classList.add("demi-wall-corner-down-right");
break; break;
case legend.captor:
cell.classList.add("captor");
break;
case legend.cable:
cell.classList.add("cable");
break;
case legend.captorTurn:
cell.classList.add("captor-turn");
break;
case legend.cableVertical:
cell.classList.add("cable-vertical");
break;
} }
drawLaserInCell(cell, laserSegments[`${y},${x}`]); drawLaserInCell(cell, laserSegments[`${y},${x}`]);
@@ -383,20 +530,7 @@ function loadGrid() {
} }
function rotateMirror(x, y, isRightClick) { function rotateMirror(x, y, isRightClick) {
const coordKey = `${y},${x}`; rotateMirrorStep(x, y, isRightClick ? 22.5 : -22.5);
if (getCurrentLevel()[y][x] !== legend.mirror) {
return;
}
let currentAngle = mirrorOrientations[coordKey] || 0;
currentAngle = (currentAngle + (isRightClick ? 22.5 : -22.5)) % 360;
if (currentAngle < 0) {
currentAngle += 360;
}
mirrorOrientations[coordKey] = currentAngle;
traceLaser(); traceLaser();
} }
@@ -404,6 +538,7 @@ function traceLaser() {
laserSegments = {}; laserSegments = {};
activatedButtons = {}; activatedButtons = {};
openedDoors = {}; openedDoors = {};
activeRotatorButtons = {};
isLevelFinished = false; isLevelFinished = false;
const level = getCurrentLevel(); const level = getCurrentLevel();
@@ -516,6 +651,21 @@ function traceLaser() {
} }
break; break;
case legend.rotatorButton:
if (currentLaserColor === laserColors.red) {
const rotatorKey = `${currentY},${currentX}`;
activatedButtons[rotatorKey] = true;
activeRotatorButtons[rotatorKey] = true;
saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
} else if (currentLaserColor === laserColors.yellow) {
saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
} else if (currentLaserColor === laserColors.blue) {
laserDirection = reverseLaser(laserDirection);
} else {
laserActive = false;
}
break;
case legend.demiWallCornerUpLeft: case legend.demiWallCornerUpLeft:
laserDirection = reflectLaser(laserDirection, 135); laserDirection = reflectLaser(laserDirection, 135);
break; break;
@@ -538,6 +688,7 @@ function traceLaser() {
} }
} }
syncRotatorButtons();
loadGrid(); loadGrid();
if (isLevelFinished) { if (isLevelFinished) {
@@ -552,6 +703,29 @@ function finish() {
}, 100); }, 100);
} }
function nextLevel() {
currentLevelIndex++;
isLevelFinished = false;
stopAllRotatorButtons();
if (currentLevelIndex >= levels.length) {
currentLevelIndex = 0;
}
initializeMirrorOrientations();
loadGrid();
laserSegments = {};
mirrorOrientations = {};
glassPlacements = {};
activatedButtons = {};
openedDoors = {};
traceLaser();
const winOverlay = document.querySelector(".win-overlay");
winOverlay.style.visibility = "hidden";
}
createPalette(); createPalette();
initializeMirrorOrientations(); initializeMirrorOrientations();
blockBrowserDrop(); blockBrowserDrop();