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.
This commit is contained in:
Sysy's
2026-03-31 13:11:30 +02:00
committed by M1n-0
parent 663e89de9e
commit 94a60de6b2
2 changed files with 133 additions and 27 deletions

View File

@@ -192,6 +192,14 @@ main {
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 {
opacity: 0.7;
}
@@ -292,6 +300,10 @@ main {
justify-content: center;
}
.btn-mirror-locked {
cursor: default;
}
.mirror-img {
width: 80%;
height: 80%;

View File

@@ -18,6 +18,7 @@ const legend = {
button2: 14,
captor: 15,
cable: 16,
rotatorButton: 17,
};
const laserColors = {
@@ -91,6 +92,10 @@ const doorGroups = {
"4,8": 2,
};
const rotatorButtons = {
"4,6": { mirrorX: 4, mirrorY: 6 },
};
let laserDirection = { dx: 0, dy: 0 };
let laserSegments = {};
let mirrorOrientations = {};
@@ -98,6 +103,8 @@ let glassPlacements = {};
let activatedButtons = {};
let openedDoors = {};
let isLevelFinished = false;
let activeRotatorButtons = {};
let rotatorIntervals = {};
function getCurrentLevel() {
return levels[currentLevelIndex];
@@ -180,6 +187,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) {
laserSegments[`${y},${x}`] = {
direction: { ...direction },
@@ -345,13 +420,20 @@ function loadGrid() {
case legend.mirror:
cell.classList.add("mirror");
const currentAngle = mirrorOrientations[`${y},${x}`] || 0;
const btnMirror = document.createElement("button");
btnMirror.classList.add("btn-mirror");
btnMirror.type = "button";
const img = document.createElement("img");
img.src = "../../assets/img/tiles/Mirror.svg";
img.classList.add("mirror-img");
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.onmousedown = (event) => {
event.preventDefault();
@@ -362,6 +444,7 @@ function loadGrid() {
};
btnMirror.oncontextmenu = (event) => event.preventDefault();
cell.appendChild(btnMirror);
}
break;
case legend.door:
cell.classList.add("door");
@@ -384,6 +467,12 @@ function loadGrid() {
cell.classList.add("button-active");
}
break;
case legend.rotatorButton:
cell.classList.add("button", "button-rotator");
if (activatedButtons[`${y},${x}`]) {
cell.classList.add("button-active");
}
break;
case legend.wall:
cell.classList.add("wall");
break;
@@ -420,20 +509,7 @@ function loadGrid() {
}
function rotateMirror(x, y, isRightClick) {
const coordKey = `${y},${x}`;
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;
rotateMirrorStep(x, y, isRightClick ? 22.5 : -22.5);
traceLaser();
}
@@ -441,6 +517,7 @@ function traceLaser() {
laserSegments = {};
activatedButtons = {};
openedDoors = {};
activeRotatorButtons = {};
isLevelFinished = false;
const level = getCurrentLevel();
@@ -553,6 +630,21 @@ function traceLaser() {
}
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:
laserDirection = reflectLaser(laserDirection, 135);
break;
@@ -575,6 +667,7 @@ function traceLaser() {
}
}
syncRotatorButtons();
loadGrid();
if (isLevelFinished) {
@@ -614,6 +707,7 @@ function nextLevel() {
currentLevelIndex++;
isLevelFinished = false;
stopAllRotatorButtons();
if (currentLevelIndex >= levels.length) {
currentLevelIndex = 0;