WEBLEB
Inicio
Editora de código
Chat
Reto
Iniciar sesión
Pro
Español
English
Français
Español
NECESITABA PUBLICAR
45
1
Juegos
k2007531
Seguir
1
Remix
Abrir en el editor
Pantalla completa
Comentar
Publica tu código
0
HTML
Copy
Web Rhythm Hero
Score:
0
Start Game
A
S
K
L
CSS
Copy
* { box-sizing: border-box; margin: 0; padding: 0; } body { background: #111424; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; color: #fff; display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; } .game-container { display: flex; flex-direction: column; align-items: center; width: 100%; max-width: 500px; } .ui-panel { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: 15px; background: #1b1f38; border-radius: 10px 10px 0 0; border-bottom: 3px solid #ff007f; } .score-box { font-size: 1.5rem; font-weight: bold; color: #00ffff; text-shadow: 0 0 10px rgba(0,255,255,0.5); } #start-btn { padding: 10px 20px; font-size: 1rem; font-weight: bold; background: #ff007f; color: white; border: none; border-radius: 5px; cursor: pointer; transition: 0.2s; } #start-btn:hover { background: #ff55aa; box-shadow: 0 0 15px #ff007f; } /* The Rhythm Highway */ .tracks-container { position: relative; display: flex; width: 100%; height: 500px; background: linear-gradient(to bottom, #16192b, #0d0f1d); border: 4px solid #1b1f38; border-top: none; /* Optional: creates an arcade-like tilted highway angle */ perspective: 400px; } .track { position: relative; flex: 1; height: 100%; border-right: 1px dashed rgba(255, 255, 255, 0.1); display: flex; flex-direction: column; justify-content: flex-end; align-items: center; } .track:last-child { border-right: none; } /* Individual track theme accents */ #track-0 { border-left: 2px solid #ff3333; } #track-1 { border-left: 1px solid #33ff33; } #track-2 { border-left: 1px solid #3333ff; } #track-3 { border-right: 2px solid #ffff33; } .key-indicator { width: 80%; padding: 10px 0; margin-bottom: 10px; text-align: center; background: rgba(255, 255, 255, 0.1); border-radius: 5px; font-weight: bold; font-size: 1.2rem; z-index: 3; pointer-events: none; } /* Flash effect when a correct key is hit */ .track.active-hit { background: linear-gradient(to top, rgba(255, 255, 255, 0.15), transparent); } /* Target baseline line */ .hit-zone { position: absolute; bottom: 50px; left: 0; width: 100%; height: 4px; background: rgba(255, 255, 255, 0.4); box-shadow: 0 0 10px white; pointer-events: none; z-index: 2; } /* Falling Rhythm Notes */ .note { position: absolute; width: 75%; height: 25px; border-radius: 5px; box-shadow: 0 0 12px rgba(255,255,255,0.4); z-index: 1; } /* Unique color matching for tracks */ .note-0 { background: #ff3333; box-shadow: 0 0 15px #ff3333; } .note-1 { background: #33ff33; box-shadow: 0 0 15px #33ff33; } .note-2 { background: #3333ff; box-shadow: 0 0 15px #3333ff; } .note-3 { background: #ffff33; box-shadow: 0 0 15px #ffff33; }
JS
Copy
// Game configurations const TRACK_KEYS = { 'a': 0, 's': 1, 'k': 2, 'l': 3 }; const NOTE_SPEED = 4; // Pixels dropped per frame const HIT_THRESHOLD = 30; // Margin of error allowance (in pixels) const TARGET_Y = 450; // Vertical destination of the target line (500px height - 50px bottom) let score = 0; let isPlaying = false; let gameLoopId; let noteSpawnInterval; let activeNotes = []; // Audio Setup via Web Audio API let audioCtx = null; const trackFrequencies = [261.63, 329.63, 392.00, 523.25]; // C4, E4, G4, C5 arpeggio chord // DOM Elements const scoreEl = document.getElementById('score'); const startBtn = document.getElementById('start-btn'); const tracks = [ document.getElementById('track-0'), document.getElementById('track-1'), document.getElementById('track-2'), document.getElementById('track-3') ]; // Initialize Synthesizer Sound function playNoteSound(trackIndex) { if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)(); let osc = audioCtx.createOscillator(); let gainNode = audioCtx.createGain(); osc.type = 'triangle'; osc.frequency.setValueAtTime(trackFrequencies[trackIndex], audioCtx.currentTime); gainNode.gain.setValueAtTime(0.3, audioCtx.currentTime); // Smooth audio tail-off fadeout gainNode.gain.exponentialRampToValueAtTime(0.0001, audioCtx.currentTime + 0.3); osc.connect(gainNode); gainNode.connect(audioCtx.destination); osc.start(); osc.stop(audioCtx.currentTime + 0.3); } // Spawn Notes function spawnNote() { if (!isPlaying) return; // Pick a random track lane (0 to 3) const trackIndex = Math.floor(Math.random() * 4); const trackEl = tracks[trackIndex]; const noteEl = document.createElement('div'); noteEl.classList.add('note', `note-${trackIndex}`); noteEl.style.top = '0px'; trackEl.appendChild(noteEl); activeNotes.push({ element: noteEl, track: trackIndex, y: 0 }); } // Primary Animation Loop updates physical frame movements function updateGame() { for (let i = activeNotes.length - 1; i >= 0; i--) { let note = activeNotes[i]; note.y += NOTE_SPEED; note.element.style.top = note.y + 'px'; // Remove note if it drops past bottom boundaries if (note.y > 500) { note.element.remove(); activeNotes.splice(i, 1); // Optional: Subtract score or count "Miss" here if desired } } if (isPlaying) { gameLoopId = requestAnimationFrame(updateGame); } } // Register User Key Input Hits function handleInput(trackIndex) { // Provide visual baseline flash feedback tracks[trackIndex].classList.add('active-hit'); setTimeout(() => tracks[trackIndex].classList.remove('active-hit'), 100); // Look for the lowest note inside the corresponding track lane let noteHitIndex = activeNotes.findIndex(note => note.track === trackIndex); if (noteHitIndex !== -1) { let note = activeNotes[noteHitIndex]; let accuracy = Math.abs(note.y - TARGET_Y); // If note is within target range if (accuracy <= HIT_THRESHOLD) { score += 10; scoreEl.textContent = score; playNoteSound(trackIndex); // Remove the struck note note.element.remove(); activeNotes.splice(noteHitIndex, 1); } } } // State Control function startGame() { if (isPlaying) return; // Clear legacy elements activeNotes.forEach(n => n.element.remove()); activeNotes = []; score = 0; scoreEl.textContent = score; isPlaying = true; startBtn.innerText = "Playing..."; startBtn.style.opacity = "0.6"; // Start Loops gameLoopId = requestAnimationFrame(updateGame); noteSpawnInterval = setInterval(spawnNote, 600); // New note drops every 600ms } // Event Listeners startBtn.addEventListener('click', startGame); window.addEventListener('keydown', (e) => { const key = e.key.toLowerCase(); if (key in TRACK_KEYS) { handleInput(TRACK_KEYS[key]); } });
Comentarios
1
Inicia sesión para unirte a la conversación
…