Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Lattice Labyrinth Legends - 2D</title>
- <style>
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
- body {
- background: linear-gradient(135deg, #0a0014, #1a0033, #0a0014);
- background-size: 400% 400%;
- animation: galaxyShift 20s ease infinite;
- color: #fff;
- font-family: 'Courier New', monospace;
- overflow: hidden;
- display: flex;
- justify-content: center;
- align-items: center;
- min-height: 100vh;
- }
- @keyframes galaxyShift {
- 0%, 100% { background-position: 0% 50%; }
- 50% { background-position: 100% 50%; }
- }
- #gameContainer {
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 20px;
- }
- #labyrinthWrapper {
- position: relative;
- padding: 20px;
- background: rgba(0, 0, 0, 0.3);
- border: 2px solid rgba(0, 255, 255, 0.2);
- border-radius: 10px;
- box-shadow: 0 0 30px rgba(0, 255, 255, 0.2);
- }
- #labyrinth {
- position: relative;
- width: 550px;
- height: 550px;
- display: grid;
- grid-template-columns: repeat(11, 1fr);
- grid-template-rows: repeat(11, 1fr);
- gap: 0;
- }
- .latticeNode {
- width: 50px;
- height: 50px;
- border: 1px solid rgba(0, 255, 255, 0.2);
- background: rgba(0, 20, 40, 0.5);
- position: relative;
- transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
- }
- .latticeNode.active {
- background: radial-gradient(circle at center, rgba(0, 255, 255, 0.2), rgba(0, 255, 255, 0.05));
- border-color: #00ffff;
- box-shadow:
- 0 0 15px rgba(0, 255, 255, 0.4),
- inset 0 0 10px rgba(0, 255, 255, 0.2);
- animation: nodePulse 2s ease-in-out infinite;
- }
- @keyframes nodePulse {
- 0%, 100% {
- border-color: #00ffff;
- box-shadow:
- 0 0 15px rgba(0, 255, 255, 0.4),
- inset 0 0 10px rgba(0, 255, 255, 0.2);
- }
- 50% {
- border-color: #00ff88;
- box-shadow:
- 0 0 25px rgba(0, 255, 255, 0.6),
- inset 0 0 15px rgba(0, 255, 255, 0.3);
- }
- }
- .latticeNode.blocked {
- background: radial-gradient(circle at center, rgba(255, 0, 102, 0.2), rgba(255, 0, 102, 0.05));
- border-color: #ff0066;
- box-shadow:
- 0 0 10px rgba(255, 0, 102, 0.3),
- inset 0 0 5px rgba(255, 0, 102, 0.2);
- }
- .latticeNode.start {
- background: radial-gradient(circle at center, rgba(0, 255, 136, 0.3), rgba(0, 255, 136, 0.1)) !important;
- border: 2px solid #00ff88 !important;
- box-shadow:
- 0 0 20px rgba(0, 255, 136, 0.5),
- inset 0 0 15px rgba(0, 255, 136, 0.3) !important;
- }
- .latticeNode.end {
- background: radial-gradient(circle at center, rgba(255, 215, 0, 0.3), rgba(255, 215, 0, 0.1)) !important;
- border: 2px solid #ffd700 !important;
- box-shadow:
- 0 0 20px rgba(255, 215, 0, 0.5),
- inset 0 0 15px rgba(255, 215, 0, 0.3) !important;
- animation: endPulse 1s ease-in-out infinite;
- }
- @keyframes endPulse {
- 0%, 100% { transform: scale(1); }
- 50% { transform: scale(1.05); }
- }
- #player {
- position: absolute;
- width: 30px;
- height: 30px;
- background: radial-gradient(circle at center, #ffffff, #00ff88, #00ff88);
- border-radius: 50%;
- box-shadow:
- 0 0 20px #00ff88,
- 0 0 40px #00ff88,
- 0 0 60px rgba(0, 255, 136, 0.5),
- inset 0 0 15px rgba(255, 255, 255, 0.8);
- z-index: 10;
- transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
- animation: playerGlow 1.5s ease-in-out infinite;
- pointer-events: none;
- }
- @keyframes playerGlow {
- 0%, 100% {
- box-shadow:
- 0 0 20px #00ff88,
- 0 0 40px #00ff88,
- 0 0 60px rgba(0, 255, 136, 0.5),
- inset 0 0 15px rgba(255, 255, 255, 0.8);
- }
- 50% {
- box-shadow:
- 0 0 30px #00ff88,
- 0 0 50px #00ff88,
- 0 0 80px rgba(0, 255, 136, 0.7),
- inset 0 0 20px rgba(255, 255, 255, 1);
- }
- }
- .guardian {
- position: absolute;
- width: 35px;
- height: 35px;
- pointer-events: none;
- z-index: 5;
- opacity: 0;
- transition: opacity 0.5s;
- }
- .guardian.visible {
- opacity: 1;
- animation: guardianFloat 3s ease-in-out infinite;
- }
- .guardian::before {
- content: '◈';
- font-size: 35px;
- color: #ff00ff;
- text-shadow:
- 0 0 15px #ff00ff,
- 0 0 30px #ff00ff,
- 0 0 45px rgba(255, 0, 255, 0.5);
- display: block;
- animation: guardianSpin 4s linear infinite;
- }
- @keyframes guardianFloat {
- 0%, 100% { transform: translateY(0); }
- 50% { transform: translateY(-5px); }
- }
- @keyframes guardianSpin {
- from { transform: rotate(0deg); }
- to { transform: rotate(360deg); }
- }
- #hud {
- display: flex;
- gap: 30px;
- align-items: center;
- background: rgba(0, 0, 0, 0.7);
- padding: 15px 25px;
- border: 1px solid #00ffff;
- border-radius: 5px;
- box-shadow: 0 0 20px rgba(0, 255, 255, 0.3);
- }
- .hudItem {
- font-size: 14px;
- color: #00ffff;
- text-shadow: 0 0 10px rgba(0, 255, 255, 0.5);
- white-space: nowrap;
- }
- .hudItem span {
- color: #00ff88;
- font-weight: bold;
- }
- #cycleIndicator {
- width: 150px;
- height: 8px;
- background: rgba(0, 0, 0, 0.8);
- border: 1px solid #00ffff;
- border-radius: 4px;
- position: relative;
- overflow: hidden;
- }
- #cycleBar {
- height: 100%;
- background: linear-gradient(90deg, #00ff88, #00ffff);
- width: 0%;
- transition: width 0.1s linear;
- box-shadow: 0 0 10px rgba(0, 255, 255, 0.8);
- }
- #message {
- position: fixed;
- top: 20%;
- left: 50%;
- transform: translate(-50%, -50%);
- font-size: 28px;
- font-weight: bold;
- color: #fff;
- text-align: center;
- text-shadow:
- 0 0 20px rgba(255, 255, 255, 0.8),
- 0 0 40px rgba(0, 255, 255, 0.6);
- opacity: 0;
- transition: opacity 0.5s;
- z-index: 200;
- pointer-events: none;
- }
- #message.show {
- opacity: 1;
- }
- .particle {
- position: absolute;
- width: 3px;
- height: 3px;
- background: #00ffff;
- border-radius: 50%;
- pointer-events: none;
- opacity: 0.6;
- animation: particleDrift 4s linear infinite;
- }
- @keyframes particleDrift {
- 0% {
- transform: translate(0, 0);
- opacity: 0;
- }
- 10% {
- opacity: 0.6;
- }
- 90% {
- opacity: 0.6;
- }
- 100% {
- transform: translate(var(--drift-x), -100px);
- opacity: 0;
- }
- }
- #controls {
- background: rgba(0, 0, 0, 0.7);
- padding: 10px 20px;
- border: 1px solid #00ffff;
- border-radius: 5px;
- text-align: center;
- }
- .controlInfo {
- color: #00ffff;
- font-size: 12px;
- margin: 3px;
- }
- .pathIndicator {
- position: absolute;
- width: 100%;
- height: 100%;
- pointer-events: none;
- }
- .pathIndicator::after {
- content: '';
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- width: 10px;
- height: 10px;
- background: rgba(0, 255, 255, 0.5);
- border-radius: 50%;
- animation: pathDot 2s ease-in-out infinite;
- }
- @keyframes pathDot {
- 0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 0.5; }
- 50% { transform: translate(-50%, -50%) scale(1.5); opacity: 0.8; }
- }
- </style>
- </head>
- <body>
- <div id="gameContainer">
- <div id="hud">
- <div class="hudItem">ROUND: <span id="round">1</span></div>
- <div class="hudItem">CRYSTALS: <span id="score">0</span></div>
- <div class="hudItem">SHIFT CYCLE:</div>
- <div id="cycleIndicator">
- <div id="cycleBar"></div>
- </div>
- <div class="hudItem">MOVES: <span id="moves">0</span></div>
- </div>
- <div id="labyrinthWrapper">
- <div id="labyrinth"></div>
- <div id="player"></div>
- </div>
- <div id="controls">
- <div class="controlInfo">↑↓←→ or WASD to move | Watch the shift cycle!</div>
- <div class="controlInfo">Navigate from GREEN (top-left) to GOLD (bottom-right)</div>
- </div>
- <div id="message"></div>
- </div>
- <script>
- class LatticeLabyrinth {
- constructor() {
- this.gridSize = 11;
- this.nodes = [];
- this.playerPos = { x: 0, y: 0 };
- this.startPos = { x: 0, y: 0 };
- this.endPos = { x: 10, y: 10 };
- this.score = 0;
- this.round = 1;
- this.moves = 0;
- this.cycleTime = 4000;
- this.currentCycle = 0;
- this.guardians = [];
- this.particles = [];
- this.shiftTimer = null;
- this.init();
- }
- init() {
- this.createLattice();
- this.createGuardians();
- this.setupControls();
- this.startCycles();
- this.updatePlayerPosition();
- this.createParticleEffects();
- this.showMessage("Navigate to the GOLDEN EXIT!", 3000);
- }
- createLattice() {
- const container = document.getElementById('labyrinth');
- container.innerHTML = '';
- for (let y = 0; y < this.gridSize; y++) {
- this.nodes[y] = [];
- for (let x = 0; x < this.gridSize; x++) {
- const node = document.createElement('div');
- node.className = 'latticeNode';
- // Create initial maze pattern
- const isActive = this.generateInitialMaze(x, y);
- this.nodes[y][x] = {
- element: node,
- active: isActive,
- x, y
- };
- if (isActive) {
- node.classList.add('active');
- } else {
- node.classList.add('blocked');
- }
- // Mark start and end positions
- if (x === this.startPos.x && y === this.startPos.y) {
- node.classList.add('start');
- this.nodes[y][x].active = true;
- }
- if (x === this.endPos.x && y === this.endPos.y) {
- node.classList.add('end');
- this.nodes[y][x].active = true;
- }
- container.appendChild(node);
- }
- }
- // Ensure there's always a path
- this.ensurePathExists();
- }
- generateInitialMaze(x, y) {
- // Create an interesting initial pattern
- const pattern = (x + y) % 3;
- const diagonal = Math.abs(x - y) < 2;
- const cross = (x === 5 || y === 5);
- // Combine patterns for variety
- return pattern !== 0 || diagonal || cross || Math.random() > 0.3;
- }
- ensurePathExists() {
- // Always ensure start and end are connected
- const path = this.findPath(this.startPos, this.endPos);
- if (!path) {
- // Create a simple guaranteed path
- for (let i = 0; i <= 10; i++) {
- this.nodes[i][i].active = true;
- this.nodes[i][i].element.classList.remove('blocked');
- this.nodes[i][i].element.classList.add('active');
- }
- }
- }
- findPath(start, end) {
- // Simple pathfinding check (BFS)
- const queue = [start];
- const visited = new Set([`${start.x},${start.y}`]);
- while (queue.length > 0) {
- const current = queue.shift();
- if (current.x === end.x && current.y === end.y) {
- return true;
- }
- const neighbors = [
- { x: current.x + 1, y: current.y },
- { x: current.x - 1, y: current.y },
- { x: current.x, y: current.y + 1 },
- { x: current.x, y: current.y - 1 }
- ];
- for (const neighbor of neighbors) {
- const key = `${neighbor.x},${neighbor.y}`;
- if (neighbor.x >= 0 && neighbor.x < this.gridSize &&
- neighbor.y >= 0 && neighbor.y < this.gridSize &&
- !visited.has(key) &&
- this.nodes[neighbor.y][neighbor.x].active) {
- visited.add(key);
- queue.push(neighbor);
- }
- }
- }
- return false;
- }
- createGuardians() {
- const positions = [
- { x: 5, y: 5 },
- { x: 3, y: 7 },
- { x: 7, y: 3 },
- { x: 8, y: 8 }
- ];
- this.guardians = [];
- positions.forEach(pos => {
- const guardian = document.createElement('div');
- guardian.className = 'guardian';
- const node = this.nodes[pos.y][pos.x].element;
- const rect = node.getBoundingClientRect();
- const labRect = document.getElementById('labyrinth').getBoundingClientRect();
- guardian.style.left = `${rect.left - labRect.left + 7.5}px`;
- guardian.style.top = `${rect.top - labRect.top + 7.5}px`;
- document.getElementById('labyrinthWrapper').appendChild(guardian);
- this.guardians.push({ element: guardian, x: pos.x, y: pos.y });
- });
- }
- createParticleEffects() {
- setInterval(() => {
- if (this.particles.length < 15) {
- const particle = document.createElement('div');
- particle.className = 'particle';
- const labyrinth = document.getElementById('labyrinthWrapper');
- particle.style.left = `${Math.random() * 550 + 20}px`;
- particle.style.top = `${550 + 20}px`;
- particle.style.setProperty('--drift-x', `${(Math.random() - 0.5) * 100}px`);
- labyrinth.appendChild(particle);
- this.particles.push(particle);
- setTimeout(() => {
- particle.remove();
- this.particles = this.particles.filter(p => p !== particle);
- }, 4000);
- }
- }, 300);
- }
- startCycles() {
- // Shift the maze periodically
- this.shiftTimer = setInterval(() => {
- this.shiftLattice();
- this.currentCycle++;
- }, this.cycleTime);
- // Update cycle bar animation
- setInterval(() => {
- const progress = ((Date.now() % this.cycleTime) / this.cycleTime) * 100;
- document.getElementById('cycleBar').style.width = `${progress}%`;
- }, 50);
- }
- shiftLattice() {
- const pattern = this.currentCycle % 5;
- for (let y = 0; y < this.gridSize; y++) {
- for (let x = 0; x < this.gridSize; x++) {
- const node = this.nodes[y][x];
- const prevActive = node.active;
- // Skip start and end positions
- if ((x === this.startPos.x && y === this.startPos.y) ||
- (x === this.endPos.x && y === this.endPos.y)) {
- continue;
- }
- switch(pattern) {
- case 0: // Horizontal wave
- node.active = Math.sin((x + this.currentCycle * 0.5)) > -0.3;
- break;
- case 1: // Vertical wave
- node.active = Math.sin((y + this.currentCycle * 0.5)) > -0.3;
- break;
- case 2: // Spiral pattern
- const dist = Math.sqrt(Math.pow(x - 5, 2) + Math.pow(y - 5, 2));
- node.active = Math.sin(dist - this.currentCycle * 0.5) > -0.2;
- break;
- case 3: // Checkerboard shift
- node.active = ((x + y + this.currentCycle) % 3) !== 0;
- break;
- case 4: // Random controlled chaos
- if (Math.random() > 0.8) {
- node.active = !node.active;
- } else if (Math.random() > 0.6) {
- node.active = true;
- }
- break;
- }
- // Keep player's current position active
- if (x === this.playerPos.x && y === this.playerPos.y) {
- node.active = true;
- }
- // Update visuals
- if (node.active !== prevActive) {
- if (node.active) {
- node.element.classList.remove('blocked');
- node.element.classList.add('active');
- } else {
- node.element.classList.remove('active');
- node.element.classList.add('blocked');
- }
- }
- }
- }
- // Ensure path still exists
- this.ensurePathExists();
- this.updateGuardians();
- }
- updateGuardians() {
- this.guardians.forEach(guardian => {
- const distance = Math.abs(guardian.x - this.playerPos.x) +
- Math.abs(guardian.y - this.playerPos.y);
- if (distance < 3) {
- guardian.element.classList.add('visible');
- if (distance === 0) {
- this.collectCrystal();
- // Move guardian to new position
- guardian.x = Math.floor(Math.random() * this.gridSize);
- guardian.y = Math.floor(Math.random() * this.gridSize);
- const node = this.nodes[guardian.y][guardian.x].element;
- const rect = node.getBoundingClientRect();
- const labRect = document.getElementById('labyrinth').getBoundingClientRect();
- guardian.element.style.left = `${rect.left - labRect.left + 7.5}px`;
- guardian.element.style.top = `${rect.top - labRect.top + 7.5}px`;
- }
- } else {
- guardian.element.classList.remove('visible');
- }
- });
- }
- collectCrystal() {
- this.score += 25;
- document.getElementById('score').textContent = this.score;
- this.showMessage("Memory Crystal +25!", 1500);
- }
- setupControls() {
- document.addEventListener('keydown', (e) => {
- let newX = this.playerPos.x;
- let newY = this.playerPos.y;
- switch(e.key.toLowerCase()) {
- case 'arrowup':
- case 'w':
- newY--;
- break;
- case 'arrowdown':
- case 's':
- newY++;
- break;
- case 'arrowleft':
- case 'a':
- newX--;
- break;
- case 'arrowright':
- case 'd':
- newX++;
- break;
- default:
- return;
- }
- e.preventDefault();
- // Check bounds and if node is active
- if (newX >= 0 && newX < this.gridSize &&
- newY >= 0 && newY < this.gridSize &&
- this.nodes[newY][newX].active) {
- this.playerPos.x = newX;
- this.playerPos.y = newY;
- this.moves++;
- document.getElementById('moves').textContent = this.moves;
- this.updatePlayerPosition();
- // Check win condition
- if (newX === this.endPos.x && newY === this.endPos.y) {
- this.completeRound();
- }
- } else {
- this.showMessage("Path blocked!", 800);
- }
- });
- }
- updatePlayerPosition() {
- const player = document.getElementById('player');
- const node = this.nodes[this.playerPos.y][this.playerPos.x].element;
- const rect = node.getBoundingClientRect();
- const wrapperRect = document.getElementById('labyrinthWrapper').getBoundingClientRect();
- player.style.left = `${rect.left - wrapperRect.left + 10}px`;
- player.style.top = `${rect.top - wrapperRect.top + 10}px`;
- }
- showMessage(text, duration) {
- const msg = document.getElementById('message');
- msg.textContent = text;
- msg.classList.add('show');
- setTimeout(() => {
- msg.classList.remove('show');
- }, duration);
- }
- completeRound() {
- this.score += 100;
- this.round++;
- document.getElementById('score').textContent = this.score;
- document.getElementById('round').textContent = this.round;
- this.showMessage(`ROUND ${this.round - 1} COMPLETE! +100`, 2500);
- setTimeout(() => {
- // Reset for next round
- this.playerPos = { x: 0, y: 0 };
- this.moves = 0;
- document.getElementById('moves').textContent = this.moves;
- this.currentCycle = 0;
- // Make maze progressively harder
- this.cycleTime = Math.max(2000, this.cycleTime - 200);
- // Regenerate maze
- this.createLattice();
- this.updatePlayerPosition();
- this.updateGuardians();
- this.showMessage(`ROUND ${this.round} - BEGIN!`, 2000);
- }, 2600);
- }
- }
- // Initialize the game
- const game = new LatticeLabyrinth();
- // Handle window resize
- window.addEventListener('resize', () => {
- game.updatePlayerPosition();
- });
- </script>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment