Fix textures/button/lasers & add ads

This commit is contained in:
Sysy's
2026-03-31 11:52:30 +02:00
committed by M1n-0
parent 63c4244e92
commit 1c59e7af7a
5 changed files with 476 additions and 239 deletions

View File

@@ -16,7 +16,7 @@ body {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-family: 'Arial', sans-serif; font-family: Arial, sans-serif;
user-select: none; user-select: none;
} }
@@ -61,29 +61,18 @@ main {
flex-wrap: wrap; flex-wrap: wrap;
} }
/* ================================
GRID
================================ */
.map { .map {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0px;
padding: 10px; padding: 10px;
background: #DADEEF; background: #dadeef;
border-radius: 5px; border-radius: 5px;
} }
.lign { .lign {
display: flex; display: flex;
gap: 0px;
margin: 0;
} }
/* ================================
CELLS
================================ */
.cell { .cell {
width: clamp(28px, 5.5vmin, 60px); width: clamp(28px, 5.5vmin, 60px);
height: clamp(28px, 5.5vmin, 60px); height: clamp(28px, 5.5vmin, 60px);
@@ -91,7 +80,6 @@ main {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
margin: 0;
position: relative; position: relative;
background-color: #2a2a2a; background-color: #2a2a2a;
user-select: none; user-select: none;
@@ -102,12 +90,8 @@ main {
outline: 2px dashed rgba(0, 0, 0, 0.2); outline: 2px dashed rgba(0, 0, 0, 0.2);
} }
/* ================================
CASES TYPE
================================ */
.empty { .empty {
background-color: #DADEEF; background-color: #dadeef;
} }
.empty:hover { .empty:hover {
@@ -148,14 +132,16 @@ main {
.door { .door {
background-color: #DADEEF; background-color: #DADEEF;
background-image: url("../img/tiles/WoodenDoor.svg"); background-image: url("../img/tiles/WoodenDoor.svg");
transform: rotate(90deg); background-size: contain;
background-size: 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: end;
} }
.door-open { .door-open {
opacity: 0.5; background-image: url("../img/tiles/WoodenDoor_openned.svg");
background-size: contain;
background-repeat: no-repeat;
background-position: end;
} }
.button { .button {
@@ -166,18 +152,18 @@ main {
background-position: center; background-position: center;
} }
.button-active { .button-2 {
opacity: 0.7;
}
.demi-wall {
background-color: #DADEEF; background-color: #DADEEF;
background-image: url("../img/tiles/VerticaleSemi.svg"); background-image: url("../img/tiles/ButtonQuarter.svg"), url("../img/tiles/Tuile.svg");
background-size: 100%; background-size: 100% 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
} }
.button-active {
opacity: 0.7;
}
.target { .target {
background-color: #DADEEF; background-color: #DADEEF;
background-image: url("../img/tiles/Trigger.svg"); background-image: url("../img/tiles/Trigger.svg");
@@ -218,41 +204,57 @@ main {
background-position: center; background-position: center;
} }
/* ================================ .laser-overlay {
LIGHT LASER position: absolute;
================================ */ inset: 0;
pointer-events: none;
.light-laser { z-index: 2;
position: relative;
} }
.laser-horizontal { .laser-horizontal {
background: linear-gradient(to bottom, transparent 0%, transparent 45%, red 45%, red 55%, transparent 55%, transparent 100%), #DADEEF --laser-color: red;
background: linear-gradient(to bottom, transparent 0%, transparent 45%, var(--laser-color) 45%, var(--laser-color) 55%, transparent 55%, transparent 100%);
} }
.laser-vertical { .laser-vertical {
background: linear-gradient(to right, transparent 0%, transparent 45%, red 45%, red 55%, transparent 55%, transparent 100%), #DADEEF; --laser-color: red;
background: linear-gradient(to right, transparent 0%, transparent 45%, var(--laser-color) 45%, var(--laser-color) 55%, transparent 55%, transparent 100%);
} }
.laser-diagonal-down { .laser-diagonal-down {
background: linear-gradient(45deg, transparent 0%, transparent 46%, red 46%, red 54%, transparent 54%, transparent 100%), #DADEEF; --laser-color: red;
background: linear-gradient(45deg, transparent 0%, transparent 46%, var(--laser-color) 46%, var(--laser-color) 54%, transparent 54%, transparent 100%);
} }
.laser-diagonal-up { .laser-diagonal-up {
background: linear-gradient(135deg, transparent 0%, transparent 46%, red 46%, red 54%, transparent 54%, transparent 100%), #DADEEF; --laser-color: red;
background: linear-gradient(135deg, transparent 0%, transparent 46%, var(--laser-color) 46%, var(--laser-color) 54%, transparent 54%, transparent 100%);
} }
/* ================================ .laser-color-white {
MIRROR --laser-color: #f8f8f8;
================================ */ }
.laser-color-red {
--laser-color: #ff3b30;
}
.laser-color-blue {
--laser-color: #2d7ff9;
}
.laser-color-yellow {
--laser-color: #ffd400;
}
.btn-mirror { .btn-mirror {
background: none; background: none;
border: none; border: none;
cursor: pointer; cursor: pointer;
height: 100%;
width: 100%; width: 100%;
height: 100%;
position: relative; position: relative;
z-index: 3;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -262,35 +264,60 @@ main {
width: 80%; width: 80%;
height: 80%; height: 80%;
object-fit: contain; object-fit: contain;
pointer-events: none;
} }
.button-door { .glass-item {
background: none; width: 54px;
height: 54px;
border: none; border: none;
cursor: pointer; border-radius: 10px;
width: 100%; cursor: grab;
height: 100%; position: relative;
position: absolute; box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.1);
inset: 0; user-select: none;
color: #223;
font-size: 0.8rem;
font-weight: bold;
} }
/* ================================ .glass-item::after,
RESPONSIVE .cell-glass::after {
================================ */ content: "";
position: absolute;
inset: 10px;
border-radius: 8px;
background: rgba(255, 255, 255, 0.45);
border: 1px solid rgba(255, 255, 255, 0.8);
}
.glass-red {
background: rgba(255, 59, 48, 0.85);
}
.glass-blue {
background: rgba(45, 127, 249, 0.85);
}
.glass-yellow {
background: rgba(255, 212, 0, 0.9);
}
.cell-glass {
position: absolute;
inset: 5px;
border-radius: 8px;
opacity: 0.9;
pointer-events: none;
z-index: 4;
}
@media (max-width: 600px) { @media (max-width: 600px) {
.map { .map {
padding: 5px; padding: 5px;
border-radius: 3px;
} }
main { main {
padding: 8px; padding: 8px;
} }
} }
@media (max-height: 500px) {
.map {
padding: 4px;
}
}

View File

@@ -1,46 +1,49 @@
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="10" height="100" viewBox="0 0 10 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="1" y="1" width="88" height="98" fill="url(#paint0_linear_29_40)" stroke="url(#paint1_linear_29_40)" stroke-width="2"/> <rect x="0.5" y="0.5" width="9" height="99" fill="url(#paint0_linear_30_9)" stroke="url(#paint1_linear_30_9)"/>
<circle cx="5.5" cy="5.5" r="1.5" fill="#A7A7A7"/> <rect x="0.5" y="0.5" width="9" height="3.54545" fill="url(#paint2_linear_30_9)" stroke="url(#paint3_linear_30_9)"/>
<circle cx="5.5" cy="5.5" r="1" fill="#D7D7D7"/> <rect x="0.5" y="95.9545" width="9" height="3.54545" fill="url(#paint4_linear_30_9)" stroke="url(#paint5_linear_30_9)"/>
<circle cx="5.5" cy="94.5" r="1.5" fill="#A7A7A7"/> <rect x="0.5" y="64.1364" width="9" height="3.54545" fill="url(#paint6_linear_30_9)" stroke="url(#paint7_linear_30_9)"/>
<circle cx="5.5" cy="94.5" r="1" fill="#D7D7D7"/> <rect x="0.5" y="32.3182" width="9" height="3.54545" fill="url(#paint8_linear_30_9)" stroke="url(#paint9_linear_30_9)"/>
<circle cx="81.5" cy="5.5" r="1.5" fill="#A7A7A7"/>
<circle cx="81.5" cy="5.5" r="1" fill="#D7D7D7"/>
<circle cx="81.5" cy="94.5" r="1.5" fill="#A7A7A7"/>
<circle cx="81.5" cy="94.5" r="1" fill="#D7D7D7"/>
<rect x="90" width="10" height="100" fill="url(#paint2_linear_29_40)"/>
<rect x="85" y="4" width="8" height="4" fill="url(#paint3_linear_29_40)"/>
<rect x="85" y="92" width="8" height="4" fill="url(#paint4_linear_29_40)"/>
<rect x="85" y="64" width="8" height="4" fill="url(#paint5_linear_29_40)"/>
<rect x="85" y="32" width="8" height="4" fill="url(#paint6_linear_29_40)"/>
<defs> <defs>
<linearGradient id="paint0_linear_29_40" x1="0" y1="0" x2="99.4475" y2="89.5028" gradientUnits="userSpaceOnUse"> <linearGradient id="paint0_linear_30_9" x1="10" y1="50" x2="-1.39702e-07" y2="50" gradientUnits="userSpaceOnUse">
<stop stop-color="#846D5D"/>
<stop offset="1" stop-color="#653921"/>
</linearGradient>
<linearGradient id="paint1_linear_29_40" x1="90" y1="100" x2="-9.44751" y2="10.4972" gradientUnits="userSpaceOnUse">
<stop stop-color="#A9825B"/>
<stop offset="1" stop-color="#4D3019"/>
</linearGradient>
<linearGradient id="paint2_linear_29_40" x1="100" y1="50" x2="90" y2="50" gradientUnits="userSpaceOnUse">
<stop stop-color="#9A7B55"/> <stop stop-color="#9A7B55"/>
<stop offset="1" stop-color="#543717"/> <stop offset="1" stop-color="#543717"/>
</linearGradient> </linearGradient>
<linearGradient id="paint3_linear_29_40" x1="93" y1="6" x2="85" y2="6" gradientUnits="userSpaceOnUse"> <linearGradient id="paint1_linear_30_9" x1="10" y1="100" x2="-9.80198" y2="98.0198" gradientUnits="userSpaceOnUse">
<stop stop-color="#A9825B"/>
<stop offset="1" stop-color="#4D3019"/>
</linearGradient>
<linearGradient id="paint2_linear_30_9" x1="10" y1="2.27273" x2="0" y2="2.27273" gradientUnits="userSpaceOnUse">
<stop stop-color="#3F3F3F"/> <stop stop-color="#3F3F3F"/>
<stop offset="1" stop-color="#878787"/> <stop offset="1" stop-color="#878787"/>
</linearGradient> </linearGradient>
<linearGradient id="paint4_linear_29_40" x1="93" y1="94" x2="85" y2="94" gradientUnits="userSpaceOnUse"> <linearGradient id="paint3_linear_30_9" x1="10" y1="4.54545" x2="6.57534" y2="-2.98879" gradientUnits="userSpaceOnUse">
<stop stop-color="#A9825B"/>
<stop offset="1" stop-color="#4D3019"/>
</linearGradient>
<linearGradient id="paint4_linear_30_9" x1="10" y1="97.7273" x2="0" y2="97.7273" gradientUnits="userSpaceOnUse">
<stop stop-color="#3F3F3F"/> <stop stop-color="#3F3F3F"/>
<stop offset="1" stop-color="#878787"/> <stop offset="1" stop-color="#878787"/>
</linearGradient> </linearGradient>
<linearGradient id="paint5_linear_29_40" x1="93" y1="66" x2="85" y2="66" gradientUnits="userSpaceOnUse"> <linearGradient id="paint5_linear_30_9" x1="10" y1="100" x2="6.57534" y2="92.4657" gradientUnits="userSpaceOnUse">
<stop stop-color="#A9825B"/>
<stop offset="1" stop-color="#4D3019"/>
</linearGradient>
<linearGradient id="paint6_linear_30_9" x1="10" y1="65.9091" x2="0" y2="65.9091" gradientUnits="userSpaceOnUse">
<stop stop-color="#3F3F3F"/> <stop stop-color="#3F3F3F"/>
<stop offset="1" stop-color="#878787"/> <stop offset="1" stop-color="#878787"/>
</linearGradient> </linearGradient>
<linearGradient id="paint6_linear_29_40" x1="93" y1="34" x2="85" y2="34" gradientUnits="userSpaceOnUse"> <linearGradient id="paint7_linear_30_9" x1="10" y1="68.1818" x2="6.57534" y2="60.6476" gradientUnits="userSpaceOnUse">
<stop stop-color="#A9825B"/>
<stop offset="1" stop-color="#4D3019"/>
</linearGradient>
<linearGradient id="paint8_linear_30_9" x1="10" y1="34.0909" x2="0" y2="34.0909" gradientUnits="userSpaceOnUse">
<stop stop-color="#3F3F3F"/> <stop stop-color="#3F3F3F"/>
<stop offset="1" stop-color="#878787"/> <stop offset="1" stop-color="#878787"/>
</linearGradient> </linearGradient>
<linearGradient id="paint9_linear_30_9" x1="10" y1="36.3636" x2="6.57534" y2="28.8294" gradientUnits="userSpaceOnUse">
<stop stop-color="#A9825B"/>
<stop offset="1" stop-color="#4D3019"/>
</linearGradient>
</defs> </defs>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,53 @@
<svg width="100" height="10" viewBox="0 0 100 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<g transform="rotate(90) translate(0, -100)">
<rect x="0.5" y="0.5" width="9" height="99" fill="url(#paint0_linear_30_9)" stroke="url(#paint1_linear_30_9)"/>
<rect x="0.5" y="0.5" width="9" height="3.54545" fill="url(#paint2_linear_30_9)" stroke="url(#paint3_linear_30_9)"/>
<rect x="0.5" y="95.9545" width="9" height="3.54545" fill="url(#paint4_linear_30_9)" stroke="url(#paint5_linear_30_9)"/>
<rect x="0.5" y="64.1364" width="9" height="3.54545" fill="url(#paint6_linear_30_9)" stroke="url(#paint7_linear_30_9)"/>
<rect x="0.5" y="32.3182" width="9" height="3.54545" fill="url(#paint8_linear_30_9)" stroke="url(#paint9_linear_30_9)"/>
</g>
<defs>
<!-- unchanged -->
<linearGradient id="paint0_linear_30_9" x1="10" y1="50" x2="0" y2="50" gradientUnits="userSpaceOnUse">
<stop stop-color="#9A7B55"/>
<stop offset="1" stop-color="#543717"/>
</linearGradient>
<linearGradient id="paint1_linear_30_9" x1="10" y1="100" x2="-9.80198" y2="98.0198" gradientUnits="userSpaceOnUse">
<stop stop-color="#A9825B"/>
<stop offset="1" stop-color="#4D3019"/>
</linearGradient>
<linearGradient id="paint2_linear_30_9" x1="10" y1="2.27273" x2="0" y2="2.27273" gradientUnits="userSpaceOnUse">
<stop stop-color="#3F3F3F"/>
<stop offset="1" stop-color="#878787"/>
</linearGradient>
<linearGradient id="paint3_linear_30_9" x1="10" y1="4.54545" x2="6.57534" y2="-2.98879" gradientUnits="userSpaceOnUse">
<stop stop-color="#A9825B"/>
<stop offset="1" stop-color="#4D3019"/>
</linearGradient>
<linearGradient id="paint4_linear_30_9" x1="10" y1="97.7273" x2="0" y2="97.7273" gradientUnits="userSpaceOnUse">
<stop stop-color="#3F3F3F"/>
<stop offset="1" stop-color="#878787"/>
</linearGradient>
<linearGradient id="paint5_linear_30_9" x1="10" y1="100" x2="6.57534" y2="92.4657" gradientUnits="userSpaceOnUse">
<stop stop-color="#A9825B"/>
<stop offset="1" stop-color="#4D3019"/>
</linearGradient>
<linearGradient id="paint6_linear_30_9" x1="10" y1="65.9091" x2="0" y2="65.9091" gradientUnits="userSpaceOnUse">
<stop stop-color="#3F3F3F"/>
<stop offset="1" stop-color="#878787"/>
</linearGradient>
<linearGradient id="paint7_linear_30_9" x1="10" y1="68.1818" x2="6.57534" y2="60.6476" gradientUnits="userSpaceOnUse">
<stop stop-color="#A9825B"/>
<stop offset="1" stop-color="#4D3019"/>
</linearGradient>
<linearGradient id="paint8_linear_30_9" x1="10" y1="34.0909" x2="0" y2="34.0909" gradientUnits="userSpaceOnUse">
<stop stop-color="#3F3F3F"/>
<stop offset="1" stop-color="#878787"/>
</linearGradient>
<linearGradient id="paint9_linear_30_9" x1="10" y1="36.3636" x2="6.57534" y2="28.8294" gradientUnits="userSpaceOnUse">
<stop stop-color="#A9825B"/>
<stop offset="1" stop-color="#4D3019"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -15,7 +15,8 @@ const legend = {
demiWallCornerDownLeft: 11, demiWallCornerDownLeft: 11,
demiWallCornerDownRight: 12, demiWallCornerDownRight: 12,
doorOpen: 13, doorOpen: 13,
} button2: 14,
};
const laserColors = { const laserColors = {
white: "white", white: "white",
@@ -30,33 +31,46 @@ const glassOptions = [
laserColors.yellow, laserColors.yellow,
]; ];
// Grid test
let levels = [ 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, 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, 6, 6, 6, 6, 6, 6, 11, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 4, 0, 10, 6, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 5, 4, 0, 10, 6, 0, 0, 0, 0],
[0, 0, 0, 0, 7, 6, 6, 5, 6, 0, 6, 0, 0, 0, 0], [0, 0, 0, 0, 7, 6, 6, 6, 6, 0, 6, 0, 0, 0, 0],
[0, 0, 0, 0, 3, 0, 0, 0, 0, 12, 6, 0, 0, 0, 0], [0, 0, 0, 0, 3, 0, 0, 0, 0, 12, 6, 0, 0, 0, 0],
[0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 9, 0, 0, 0, 0], [0, 0, 0, 0, 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],
] ],
]; ];
let currentLevelIndex = 0; let currentLevelIndex = 0;
// Function to save initial orientation of mirrors const initialMirrorAngles = {
"6,4": 315,
};
const buttonGroups = {
"4,6": 1,
};
const doorGroups = {
"4,7": 1,
};
let laserDirection = { dx: 0, dy: 0 }; let laserDirection = { dx: 0, dy: 0 };
let laserSegments = {}; let laserSegments = {};
let mirrorOrientations = {}; let mirrorOrientations = {};
let glassPlacements = {};
let activatedButtons = {}; let activatedButtons = {};
let openedDoors = {}; let openedDoors = {};
let isLevelFinished = false;
function getCurrentLevel() {
return levels[currentLevelIndex];
}
function normalizeLaserDirection(dx, dy) { function normalizeLaserDirection(dx, dy) {
const epsilon = 0.0001; const epsilon = 0.0001;
@@ -77,6 +91,13 @@ function reflectLaser(direction, mirrorAngle) {
return normalizeLaserDirection(reflectedDx, reflectedDy); return normalizeLaserDirection(reflectedDx, reflectedDy);
} }
function reverseLaser(direction) {
return {
dx: direction.dx * -1,
dy: direction.dy * -1,
};
}
function getLaserSegmentClass(segmentDirection) { function getLaserSegmentClass(segmentDirection) {
if (!segmentDirection) { if (!segmentDirection) {
return "laser-horizontal"; return "laser-horizontal";
@@ -97,59 +118,190 @@ function getLaserSegmentClass(segmentDirection) {
return "laser-diagonal-up"; return "laser-diagonal-up";
} }
function openAdjacentDoors(x, y) { function getLaserColorClass(color) {
// Open adjacent doors (up, down, left, right) return `laser-color-${color || laserColors.white}`;
const directions = [ }
{ dx: 0, dy: -1 },
{ dx: 0, dy: 1 },
{ dx: -1, dy: 0 },
{ dx: 1, dy: 0 }
];
for (let dir of directions) { function getButtonGroup(x, y) {
const newX = x + dir.dx; const cellType = getCurrentLevel()[y][x];
const newY = y + dir.dy;
if (newX >= 0 && newX < levels[currentLevelIndex][0].length && if (cellType === legend.button2) {
newY >= 0 && newY < levels[currentLevelIndex].length) { return 2;
if (levels[currentLevelIndex][newY][newX] === legend.door) { }
openedDoors[`${newY},${newX}`] = true;
levels[currentLevelIndex][newY][newX] = legend.doorOpen; // Change state to open return buttonGroups[`${y},${x}`] || 1;
}
function getDoorGroup(x, y) {
return doorGroups[`${y},${x}`] || 1;
}
function openDoorsFromButton(x, y) {
const buttonGroup = getButtonGroup(x, y);
const level = getCurrentLevel();
for (let doorY = 0; doorY < level.length; doorY++) {
for (let doorX = 0; doorX < level[doorY].length; doorX++) {
if (level[doorY][doorX] === legend.door && getDoorGroup(doorX, doorY) === buttonGroup) {
openedDoors[`${doorY},${doorX}`] = true;
} }
} }
} }
}
loadGrid(); // Refresh grid to show opened doors function saveLaserSegment(x, y, direction, color) {
laserSegments[`${y},${x}`] = {
direction: { ...direction },
color: color,
};
}
function isGlassOnCell(x, y) {
return glassPlacements[`${y},${x}`] !== undefined;
}
function drawGlassInCell(cell, x, y) {
const glassColor = glassPlacements[`${y},${x}`];
if (!glassColor) {
return;
}
const glassDiv = document.createElement("div");
glassDiv.classList.add("cell-glass", `glass-${glassColor}`);
cell.appendChild(glassDiv);
}
function drawLaserInCell(cell, segmentData) {
if (!segmentData) {
return;
}
const laserDiv = document.createElement("div");
laserDiv.classList.add("laser-overlay");
laserDiv.classList.add(getLaserSegmentClass(segmentData.direction));
laserDiv.classList.add(getLaserColorClass(segmentData.color));
cell.appendChild(laserDiv);
}
function createPalette() {
const palette = document.getElementById("glass-palette");
if (!palette) {
return;
}
palette.innerHTML = "";
for (let i = 0; i < glassOptions.length; i++) {
const glassColor = glassOptions[i];
const glassButton = document.createElement("button");
glassButton.type = "button";
glassButton.classList.add("glass-item", `glass-${glassColor}`);
glassButton.draggable = true;
glassButton.addEventListener("dragstart", (event) => {
event.dataTransfer.effectAllowed = "copy";
event.dataTransfer.setData("application/x-glass-color", glassColor);
});
palette.appendChild(glassButton);
}
}
function addDropEvents(cell, x, y) {
cell.addEventListener("dragover", (event) => {
if (isLevelFinished) {
return;
}
if (!event.dataTransfer.types.includes("application/x-glass-color")) {
return;
}
const cellType = getCurrentLevel()[y][x];
if (cellType !== legend.empty) {
return;
}
event.preventDefault();
cell.classList.add("can-drop");
});
cell.addEventListener("dragleave", () => {
cell.classList.remove("can-drop");
});
cell.addEventListener("drop", (event) => {
if (isLevelFinished) {
return;
}
const selectedColor = event.dataTransfer.getData("application/x-glass-color");
cell.classList.remove("can-drop");
if (!selectedColor) {
return;
}
if (getCurrentLevel()[y][x] !== legend.empty) {
return;
}
event.preventDefault();
glassPlacements[`${y},${x}`] = selectedColor;
traceLaser();
});
cell.addEventListener("dblclick", () => {
if (isLevelFinished) {
return;
}
if (isGlassOnCell(x, y)) {
delete glassPlacements[`${y},${x}`];
traceLaser();
}
});
}
function blockBrowserDrop() {
document.addEventListener("dragover", (event) => {
event.preventDefault();
});
document.addEventListener("drop", (event) => {
event.preventDefault();
});
} }
function initializeMirrorOrientations() { function initializeMirrorOrientations() {
mirrorOrientations = {}; // Reset mirrorOrientations = {};
for (let y = 0; y < levels[currentLevelIndex].length; y++) { const level = getCurrentLevel();
for (let x = 0; x < levels[currentLevelIndex][y].length; x++) {
if (levels[currentLevelIndex][y][x] === legend.mirror) { for (let y = 0; y < level.length; y++) {
mirrorOrientations[`${y},${x}`] = 0; // Default angle for (let x = 0; x < level[y].length; x++) {
if (level[y][x] === legend.mirror) {
mirrorOrientations[`${y},${x}`] = initialMirrorAngles[`${y},${x}`] || 0;
} }
} }
} }
} }
// Function to print grid
let mirrorCoordinates = [];
function loadGrid() { function loadGrid() {
const mapDiv = document.getElementById("map"); // Div with map in DOM const mapDiv = document.getElementById("map");
const level = getCurrentLevel();
mapDiv.innerHTML = ""; mapDiv.innerHTML = "";
for (let y = 0; y < levels[currentLevelIndex].length; y++) { for (let y = 0; y < level.length; y++) {
const lign = document.createElement("div"); const lign = document.createElement("div");
lign.classList.add("lign"); lign.classList.add("lign");
for (let x = 0; x < levels[currentLevelIndex][y].length; x++) { for (let x = 0; x < level[y].length; x++) {
const cell = document.createElement("div"); const cell = document.createElement("div");
cell.classList.add("cell"); cell.classList.add("cell");
addDropEvents(cell, x, y);
switch (levels[currentLevelIndex][y][x]) { switch (level[y][x]) {
case legend.empty: case legend.empty:
cell.classList.add("empty"); cell.classList.add("empty");
break; break;
@@ -160,25 +312,25 @@ function loadGrid() {
cell.classList.add("colored-laser"); cell.classList.add("colored-laser");
break; break;
case legend.mirror: case legend.mirror:
cell.classList.add("mirror");
const currentAngle = mirrorOrientations[`${y},${x}`] || 0; const currentAngle = mirrorOrientations[`${y},${x}`] || 0;
const btnMirror = document.createElement("button"); const btnMirror = document.createElement("button");
btnMirror.classList.add("btn-mirror"); btnMirror.classList.add("btn-mirror");
btnMirror.type = "button"; btnMirror.type = "button";
btnMirror.style.transform = `rotate(${currentAngle}deg)`;
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.style.rotate = `${currentAngle}deg`; img.classList.add("mirror-img");
img.className = "mirror-img"; img.style.transform = `rotate(${currentAngle}deg)`;
btnMirror.appendChild(img); btnMirror.appendChild(img);
btnMirror.onmousedown = (e) => { btnMirror.onmousedown = (event) => {
e.preventDefault(); event.preventDefault();
e.stopPropagation(); event.stopPropagation();
rotateMirror(x, y, e.button === 2); if (!isLevelFinished) {
rotateMirror(x, y, event.button === 2);
}
}; };
btnMirror.oncontextmenu = (e) => e.preventDefault(); btnMirror.oncontextmenu = (event) => event.preventDefault();
cell.appendChild(btnMirror); cell.appendChild(btnMirror);
cell.classList.add("mirror");
break; break;
case legend.door: case legend.door:
cell.classList.add("door"); cell.classList.add("door");
@@ -186,22 +338,20 @@ function loadGrid() {
cell.classList.add("door-open"); cell.classList.add("door-open");
} }
break; break;
case legend.doorOpen:
cell.classList.add("door", "door-open");
break;
case legend.button: case legend.button:
cell.classList.add("button"); cell.classList.add("button");
if (activatedButtons[`${y},${x}`]) { if (activatedButtons[`${y},${x}`]) {
cell.classList.add("button-active"); cell.classList.add("button-active");
} }
let button = document.createElement("button"); break;
button.classList.add("button-door"); case legend.button2:
button.type = "button"; cell.classList.add("button", "button-2");
button.onclick = () => {
activatedButtons[`${y},${x}`] = !activatedButtons[`${y},${x}`];
if (activatedButtons[`${y},${x}`]) { if (activatedButtons[`${y},${x}`]) {
openAdjacentDoors(x, y); cell.classList.add("button-active");
} }
traceLaser();
};
cell.appendChild(button);
break; break;
case legend.wall: case legend.wall:
cell.classList.add("wall"); cell.classList.add("wall");
@@ -209,11 +359,6 @@ function loadGrid() {
case legend.target: case legend.target:
cell.classList.add("target"); cell.classList.add("target");
break; break;
case legend.ligthLaser:
cell.classList.add("light-laser");
const segmentDirection = laserSegments[`${y},${x}`];
cell.classList.add(getLaserSegmentClass(segmentDirection));
break;
case legend.demiWallCornerUpLeft: case legend.demiWallCornerUpLeft:
cell.classList.add("demi-wall-corner-up-left"); cell.classList.add("demi-wall-corner-up-left");
break; break;
@@ -226,11 +371,10 @@ 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.doorOpen:
cell.classList.add("door-open");
break;
} }
drawLaserInCell(cell, laserSegments[`${y},${x}`]);
drawGlassInCell(cell, x, y);
lign.appendChild(cell); lign.appendChild(cell);
} }
@@ -238,89 +382,76 @@ function loadGrid() {
} }
} }
loadGrid();
// Function to rotate mirror
function rotateMirror(x, y, isRightClick) { function rotateMirror(x, y, isRightClick) {
const coordKey = `${y},${x}`; const coordKey = `${y},${x}`;
if (levels[currentLevelIndex][y][x] !== legend.mirror) { if (getCurrentLevel()[y][x] !== legend.mirror) {
return; return;
} }
let currentAngle = mirrorOrientations[coordKey] || 0; let currentAngle = mirrorOrientations[coordKey] || 0;
// Rotation and normalize negative angles to [0, 360)
currentAngle = (currentAngle + (isRightClick ? 22.5 : -22.5)) % 360; currentAngle = (currentAngle + (isRightClick ? 22.5 : -22.5)) % 360;
if (currentAngle < 0) { if (currentAngle < 0) {
currentAngle += 360; currentAngle += 360;
} }
// Save
mirrorOrientations[coordKey] = currentAngle; mirrorOrientations[coordKey] = currentAngle;
traceLaser();
// Print laser light
traceLaser(true);
} }
// Function to trace
let isLevelFinished = false;
function traceLaser() { function traceLaser() {
// Reset light laser from previous trace
laserSegments = {}; laserSegments = {};
// Ne pas réinitialiser activatedButtons et openedDoors pour préserver l'état des boutons manuels activatedButtons = {};
for (let y = 0; y < levels[currentLevelIndex].length; y++) { openedDoors = {};
for (let x = 0; x < levels[currentLevelIndex][y].length; x++) { isLevelFinished = false;
if (levels[currentLevelIndex][y][x] === legend.ligthLaser) {
levels[currentLevelIndex][y][x] = legend.empty;
}
}
}
const level = getCurrentLevel();
let startLaserX; let startLaserX;
let startLaserY; let startLaserY;
// Search laser for (let y = 0; y < level.length; y++) {
for (let y = 0; y < levels[currentLevelIndex].length; y++) { for (let x = 0; x < level[y].length; x++) {
for (let x = 0; x < levels[currentLevelIndex][y].length; x++) { if (level[y][x] === legend.laser) {
if (levels[currentLevelIndex][y][x] === legend.laser) {
startLaserX = x; startLaserX = x;
startLaserY = y; startLaserY = y;
laserDirection = { dx: 1, dy: 0 }; laserDirection = { dx: 1, dy: 0 };
break; break;
} }
} }
if (startLaserX !== undefined) break;
if (startLaserX !== undefined) {
break;
}
} }
// If laser not found -> return
if (startLaserX === undefined) { if (startLaserX === undefined) {
return; return;
} }
let currentX = startLaserX; let currentX = startLaserX;
let currentY = startLaserY; let currentY = startLaserY;
let currentLaserColor = laserColors.white;
let laserActive = true; let laserActive = true;
const maxIterations = 1000; // Prevent infinite loops
let iterations = 0; let iterations = 0;
const maxIterations = 1000;
while (laserActive && iterations < maxIterations) { while (laserActive && iterations < maxIterations) {
iterations++; iterations++;
currentX += laserDirection.dx; currentX += laserDirection.dx;
currentY += laserDirection.dy; currentY += laserDirection.dy;
// Out of bounds if (currentX < 0 || currentX >= level[0].length || currentY < 0 || currentY >= level.length) {
if (currentX < 0 || currentX >= levels[currentLevelIndex][0].length || currentY < 0 || currentY >= levels[currentLevelIndex].length) {
laserActive = false; laserActive = false;
break; break;
} }
const cellType = levels[currentLevelIndex][currentY][currentX]; const cellType = level[currentY][currentX];
const glassColor = glassPlacements[`${currentY},${currentX}`];
if (glassColor) {
currentLaserColor = glassColor;
}
switch (cellType) { switch (cellType) {
case legend.laser: case legend.laser:
@@ -329,68 +460,80 @@ function traceLaser() {
break; break;
case legend.empty: case legend.empty:
levels[currentLevelIndex][currentY][currentX] = legend.ligthLaser; saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
laserSegments[`${currentY},${currentX}`] = { ...laserDirection };
break; break;
case legend.target: case legend.target:
levels[currentLevelIndex][currentY][currentX] = legend.ligthLaser; saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
laserSegments[`${currentY},${currentX}`] = { ...laserDirection };
laserActive = false; laserActive = false;
isLevelFinished = true; isLevelFinished = true;
break; break;
case legend.mirror: case legend.mirror:
if (currentLaserColor === laserColors.yellow) {
saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
} else {
const mirrorAngle = mirrorOrientations[`${currentY},${currentX}`] || 0; const mirrorAngle = mirrorOrientations[`${currentY},${currentX}`] || 0;
laserDirection = reflectLaser(laserDirection, mirrorAngle); laserDirection = reflectLaser(laserDirection, mirrorAngle);
}
break; break;
case legend.wall: case legend.wall:
laserActive = false; if (currentLaserColor === laserColors.blue) {
break; laserDirection = reverseLaser(laserDirection);
} else if (currentLaserColor === laserColors.yellow) {
case legend.door: saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
if (openedDoors[`${currentY},${currentX}`]) {
// La porte est ouverte, le laser la traverse
levels[currentLevelIndex][currentY][currentX] = legend.ligthLaser;
laserSegments[`${currentY},${currentX}`] = { ...laserDirection };
} else { } else {
// La porte est fermée, le laser s'arrête
laserActive = false; laserActive = false;
} }
break; break;
case legend.door:
case legend.doorOpen: case legend.doorOpen:
// Porte ouverte - le laser la traverse if (openedDoors[`${currentY},${currentX}`] || cellType === legend.doorOpen) {
levels[currentLevelIndex][currentY][currentX] = legend.ligthLaser; saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
laserSegments[`${currentY},${currentX}`] = { ...laserDirection }; } else if (currentLaserColor === laserColors.blue) {
laserDirection = reverseLaser(laserDirection);
} else if (currentLaserColor === laserColors.yellow) {
saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
} else {
laserActive = false;
}
break; break;
case legend.button: case legend.button:
// Activer le bouton et ouvrir les portes adjacentes case legend.button2:
if (currentLaserColor === laserColors.red) {
activatedButtons[`${currentY},${currentX}`] = true; activatedButtons[`${currentY},${currentX}`] = true;
openAdjacentDoors(currentX, currentY); openDoorsFromButton(currentX, currentY);
levels[currentLevelIndex][currentY][currentX] = legend.ligthLaser; saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
laserSegments[`${currentY},${currentX}`] = { ...laserDirection }; } else if (currentLaserColor === laserColors.yellow) {
saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
} else if (currentLaserColor === laserColors.blue) {
laserDirection = reverseLaser(laserDirection);
} else {
laserActive = false; laserActive = false;
}
break; break;
case legend.demiWallCornerUpLeft: case legend.demiWallCornerUpLeft:
laserDirection = reflectLaser(laserDirection, 135); laserDirection = reflectLaser(laserDirection, 135);
break; break;
case legend.demiWallCornerUpRight: case legend.demiWallCornerUpRight:
laserDirection = reflectLaser(laserDirection, 45); laserDirection = reflectLaser(laserDirection, 45);
break; break;
case legend.demiWallCornerDownLeft: case legend.demiWallCornerDownLeft:
laserDirection = reflectLaser(laserDirection, 45); laserDirection = reflectLaser(laserDirection, 225);
break; break;
case legend.demiWallCornerDownRight: case legend.demiWallCornerDownRight:
laserDirection = reflectLaser(laserDirection, 315); laserDirection = reflectLaser(laserDirection, 315);
break; break;
default: default:
levels[currentLevelIndex][currentY][currentX] = legend.ligthLaser; saveLaserSegment(currentX, currentY, laserDirection, currentLaserColor);
laserSegments[`${currentY},${currentX}`] = { ...laserDirection };
break; break;
} }
} }
@@ -402,22 +545,13 @@ 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() { function finish() {
setTimeout(() => { setTimeout(() => {
alert("Réussi !"); alert("Reussi !");
}, 100); }, 100);
} }
createPalette();
initializeMirrorOrientations();
blockBrowserDrop();
traceLaser();

View File

@@ -5,10 +5,30 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../../assets/css/game.css"> <link rel="stylesheet" href="../../assets/css/game.css">
<title>Game</title> <title>Game</title>
<script>(function(s){s.dataset.zone='10809858',s.src='https://n6wxm.com/vignette.min.js'})([document.documentElement, document.body].filter(Boolean).pop().appendChild(document.createElement('script')))</script>
<script>(function(s){s.dataset.zone='10809853',s.src='https://nap5k.com/tag.min.js'})([document.documentElement, document.body].filter(Boolean).pop().appendChild(document.createElement('script')))</script>
</head> </head>
<body> <body>
<script>
atOptions = {
'key' : '72b6ba1a1c26b9671167b66063c7e699',
'format' : 'iframe',
'height' : 600,
'width' : 160,
'params' : {}
};
</script>
<script src="https://www.highperformanceformat.com/72b6ba1a1c26b9671167b66063c7e699/invoke.js"></script>
<main class="game-layout">
<div id="map" class="map"></div> <div id="map" class="map"></div>
<section class="toolbox">
<h2>Vitres tintées</h2>
<div id="glass-palette" class="glass-palette"></div>
</section>
</main>
<script src="../../assets/js/game.js" defer></script> <script src="../../assets/js/game.js" defer></script>
</body> </body>
</html> </html>