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:
@@ -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%;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user