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>Resonance Rift Rally</title>
- <style>
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
- body {
- font-family: 'Courier New', monospace;
- background: linear-gradient(135deg, #0a0015 0%, #1a0033 100%);
- overflow: hidden;
- color: #fff;
- }
- #gameCanvas {
- display: block;
- background: radial-gradient(ellipse at center, #1a0033 0%, #0a0015 100%);
- box-shadow: 0 0 50px rgba(138, 43, 226, 0.5);
- }
- .ui-overlay {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- pointer-events: none;
- z-index: 10;
- }
- .score-display {
- position: absolute;
- top: 20px;
- left: 20px;
- font-size: 24px;
- color: #00ffff;
- text-shadow: 0 0 10px #00ffff, 0 0 20px #00ffff;
- pointer-events: none;
- }
- .speed-display {
- position: absolute;
- top: 60px;
- left: 20px;
- font-size: 18px;
- color: #ff00ff;
- text-shadow: 0 0 10px #ff00ff;
- }
- .tone-indicator {
- position: absolute;
- top: 20px;
- right: 20px;
- display: flex;
- gap: 10px;
- }
- .tone-btn {
- width: 60px;
- height: 60px;
- border-radius: 50%;
- border: 3px solid #fff;
- display: flex;
- align-items: center;
- justify-content: center;
- font-weight: bold;
- font-size: 14px;
- transition: all 0.2s;
- pointer-events: all;
- cursor: pointer;
- text-shadow: 0 0 5px currentColor;
- }
- .tone-btn.low {
- background: rgba(255, 0, 100, 0.3);
- border-color: #ff0064;
- color: #ff0064;
- }
- .tone-btn.mid {
- background: rgba(0, 255, 200, 0.3);
- border-color: #00ffc8;
- color: #00ffc8;
- }
- .tone-btn.high {
- background: rgba(138, 43, 226, 0.3);
- border-color: #8a2be2;
- color: #8a2be2;
- }
- .tone-btn.active {
- transform: scale(1.2);
- box-shadow: 0 0 30px currentColor;
- }
- .start-screen {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- text-align: center;
- pointer-events: all;
- z-index: 100;
- }
- .start-screen h1 {
- font-size: 48px;
- margin-bottom: 20px;
- background: linear-gradient(45deg, #ff00ff, #00ffff, #ff00ff);
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
- animation: pulse 2s ease-in-out infinite;
- }
- .start-screen button {
- padding: 15px 40px;
- font-size: 24px;
- background: linear-gradient(45deg, #8a2be2, #ff00ff);
- border: none;
- border-radius: 50px;
- color: white;
- cursor: pointer;
- transition: all 0.3s;
- box-shadow: 0 0 20px rgba(138, 43, 226, 0.5);
- }
- .start-screen button:hover {
- transform: scale(1.1);
- box-shadow: 0 0 40px rgba(138, 43, 226, 0.8);
- }
- .instructions {
- margin-top: 20px;
- font-size: 16px;
- color: #00ffff;
- line-height: 1.8;
- }
- .game-over {
- display: none;
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- text-align: center;
- pointer-events: all;
- z-index: 100;
- background: rgba(0, 0, 0, 0.8);
- padding: 40px;
- border-radius: 20px;
- border: 3px solid #ff00ff;
- }
- .game-over h2 {
- font-size: 36px;
- color: #ff00ff;
- margin-bottom: 20px;
- }
- @keyframes pulse {
- 0%, 100% { opacity: 1; }
- 50% { opacity: 0.7; }
- }
- @keyframes ripple {
- 0% {
- transform: scale(1);
- opacity: 1;
- }
- 100% {
- transform: scale(1.5);
- opacity: 0;
- }
- }
- </style>
- </head>
- <body>
- <canvas id="gameCanvas"></canvas>
- <div class="ui-overlay">
- <div class="score-display">
- Score: <span id="score">0</span>
- </div>
- <div class="speed-display">
- Speed: <span id="speed">0</span>
- </div>
- <div class="tone-indicator">
- <div class="tone-btn low" data-tone="low">LOW<br>Q</div>
- <div class="tone-btn mid" data-tone="mid">MID<br>W</div>
- <div class="tone-btn high" data-tone="high">HIGH<br>E</div>
- </div>
- </div>
- <div class="start-screen" id="startScreen">
- <h1>RESONANCE RIFT RALLY</h1>
- <button id="startBtn">START RACE</button>
- <div class="instructions">
- Match the glowing tunnel tones!<br>
- Press Q (Low) · W (Mid) · E (High)<br>
- or click the tone buttons<br>
- Avoid discordant red zones with your mouse!
- </div>
- </div>
- <div class="game-over" id="gameOver">
- <h2>RACE COMPLETE!</h2>
- <p style="font-size: 24px; color: #00ffff;">Final Score: <span id="finalScore">0</span></p>
- <button id="restartBtn" style="margin-top: 20px; padding: 10px 30px; font-size: 18px; background: linear-gradient(45deg, #8a2be2, #ff00ff); border: none; border-radius: 50px; color: white; cursor: pointer;">RACE AGAIN</button>
- </div>
- <script>
- const canvas = document.getElementById('gameCanvas');
- const ctx = canvas.getContext('2d');
- canvas.width = window.innerWidth;
- canvas.height = window.innerHeight;
- // Audio Context
- const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
- // Game State
- let gameState = 'menu';
- let score = 0;
- let speed = 0;
- let baseSpeed = 3;
- let maxSpeed = 12;
- let currentTone = 'mid';
- let activeTone = null;
- let toneMatchTime = 0;
- // Vehicle
- const vehicle = {
- x: canvas.width / 2,
- y: canvas.height - 150,
- width: 40,
- height: 60,
- vx: 0,
- vy: 0
- };
- // Tunnel segments
- const segments = [];
- const segmentHeight = 100;
- let segmentSpeed = 5;
- // Obstacles
- const obstacles = [];
- // Particles
- const particles = [];
- // Tones
- const tones = {
- low: { freq: 220, color: '#ff0064', key: 'q' },
- mid: { freq: 440, color: '#00ffc8', key: 'w' },
- high: { freq: 880, color: '#8a2be2', key: 'e' }
- };
- // Initialize segments
- function initSegments() {
- segments.length = 0;
- for (let i = 0; i < 15; i++) {
- segments.push(createSegment(i * segmentHeight));
- }
- }
- function createSegment(y) {
- const toneKeys = Object.keys(tones);
- const tone = toneKeys[Math.floor(Math.random() * toneKeys.length)];
- return {
- y: y,
- tone: tone,
- width: canvas.width * 0.6,
- x: canvas.width * 0.2,
- phase: Math.random() * Math.PI * 2
- };
- }
- // Create obstacle
- function createObstacle(y) {
- obstacles.push({
- x: Math.random() * (canvas.width * 0.6) + canvas.width * 0.2,
- y: y,
- width: 50,
- height: 50,
- type: 'discord'
- });
- }
- // Play tone
- function playTone(tone) {
- const oscillator = audioCtx.createOscillator();
- const gainNode = audioCtx.createGain();
- oscillator.connect(gainNode);
- gainNode.connect(audioCtx.destination);
- oscillator.frequency.value = tones[tone].freq;
- oscillator.type = 'sine';
- gainNode.gain.setValueAtTime(0.3, audioCtx.currentTime);
- gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.3);
- oscillator.start(audioCtx.currentTime);
- oscillator.stop(audioCtx.currentTime + 0.3);
- }
- // Play negative tone on hit
- function playNegativeTone() {
- const oscillator = audioCtx.createOscillator();
- const gainNode = audioCtx.createGain();
- oscillator.connect(gainNode);
- gainNode.connect(audioCtx.destination);
- oscillator.frequency.value = 100; // Low, dissonant freq for negative feel
- oscillator.type = 'sawtooth'; // Gritty waveform
- gainNode.gain.setValueAtTime(0.5, audioCtx.currentTime);
- gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.5);
- oscillator.start(audioCtx.currentTime);
- oscillator.stop(audioCtx.currentTime + 0.5);
- }
- // Create particles
- function createParticles(x, y, color) {
- for (let i = 0; i < 10; i++) {
- particles.push({
- x: x,
- y: y,
- vx: (Math.random() - 0.5) * 5,
- vy: (Math.random() - 0.5) * 5,
- life: 1,
- color: color
- });
- }
- }
- // Update game
- function update() {
- if (gameState !== 'playing') return;
- // Update speed
- speed = baseSpeed + (score / 100);
- speed = Math.min(speed, maxSpeed);
- segmentSpeed = speed;
- // Move segments
- segments.forEach(seg => {
- seg.y += segmentSpeed;
- seg.phase += 0.05;
- });
- // Remove off-screen segments and add new ones
- if (segments[0].y > canvas.height) {
- segments.shift();
- segments.push(createSegment(segments[segments.length - 1].y - segmentHeight));
- if (Math.random() < 0.3) {
- createObstacle(segments[segments.length - 1].y + 50);
- }
- }
- // Current segment tone
- const currentSegment = segments.find(seg =>
- seg.y < vehicle.y && seg.y + segmentHeight > vehicle.y
- );
- if (currentSegment) {
- currentTone = currentSegment.tone;
- // Check tone match
- if (activeTone === currentTone) {
- toneMatchTime++;
- score += 1;
- speed += 0.01;
- if (toneMatchTime % 10 === 0) {
- createParticles(vehicle.x, vehicle.y, tones[currentTone].color);
- }
- } else {
- toneMatchTime = 0;
- if (activeTone !== null) {
- speed *= 0.98;
- }
- }
- }
- // Move obstacles
- obstacles.forEach((obs, index) => {
- obs.y += segmentSpeed;
- // Collision detection
- if (obs.y > vehicle.y - vehicle.height &&
- obs.y < vehicle.y + vehicle.height &&
- obs.x > vehicle.x - vehicle.width &&
- obs.x < vehicle.x + vehicle.width) {
- score = Math.max(0, score - 50);
- playNegativeTone(); // Added negative tone on hit
- obstacles.splice(index, 1);
- createParticles(obs.x, obs.y, '#ff0000');
- speed *= 0.7;
- }
- if (obs.y > canvas.height) {
- obstacles.splice(index, 1);
- }
- });
- // Update particles
- particles.forEach((p, index) => {
- p.x += p.vx;
- p.y += p.vy;
- p.life -= 0.02;
- if (p.life <= 0) {
- particles.splice(index, 1);
- }
- });
- // Vehicle position is now controlled by mouse on x, no drift
- // (Mouse handling added below)
- // Update UI
- document.getElementById('score').textContent = Math.floor(score);
- document.getElementById('speed').textContent = speed.toFixed(1);
- }
- // Draw game
- function draw() {
- ctx.fillStyle = '#0a0015';
- ctx.fillRect(0, 0, canvas.width, canvas.height);
- // Draw segments with soundwave effect
- segments.forEach((seg, index) => {
- const color = tones[seg.tone].color;
- const alpha = seg.tone === currentTone ? 0.3 : 0.1;
- // Soundwave ripples
- for (let wave = 0; wave < 3; wave++) {
- ctx.strokeStyle = color + Math.floor(alpha * 255 * (1 - wave * 0.3)).toString(16).padStart(2, '0');
- ctx.lineWidth = 3;
- ctx.beginPath();
- for (let x = seg.x; x < seg.x + seg.width; x += 10) {
- const waveOffset = Math.sin((x * 0.02) + seg.phase + (wave * 0.5)) * 30;
- const y1 = seg.y + waveOffset;
- const y2 = seg.y + segmentHeight + waveOffset;
- if (x === seg.x) {
- ctx.moveTo(x, y1);
- } else {
- ctx.lineTo(x, y1);
- }
- }
- ctx.stroke();
- }
- // Segment glow
- if (seg.tone === currentTone && activeTone === currentTone) {
- ctx.fillStyle = color + '20';
- ctx.fillRect(seg.x, seg.y, seg.width, segmentHeight);
- }
- });
- // Draw obstacles
- obstacles.forEach(obs => {
- ctx.fillStyle = '#ff0000';
- ctx.shadowBlur = 20;
- ctx.shadowColor = '#ff0000';
- ctx.fillRect(obs.x - obs.width / 2, obs.y - obs.height / 2, obs.width, obs.height);
- // X pattern
- ctx.strokeStyle = '#ffffff';
- ctx.lineWidth = 3;
- ctx.beginPath();
- ctx.moveTo(obs.x - obs.width / 2, obs.y - obs.height / 2);
- ctx.lineTo(obs.x + obs.width / 2, obs.y + obs.height / 2);
- ctx.moveTo(obs.x + obs.width / 2, obs.y - obs.height / 2);
- ctx.lineTo(obs.x - obs.width / 2, obs.y + obs.height / 2);
- ctx.stroke();
- ctx.shadowBlur = 0;
- });
- // Draw particles
- particles.forEach(p => {
- ctx.fillStyle = p.color + Math.floor(p.life * 255).toString(16).padStart(2, '0');
- ctx.beginPath();
- ctx.arc(p.x, p.y, 3, 0, Math.PI * 2);
- ctx.fill();
- });
- // Draw vehicle
- ctx.save();
- ctx.translate(vehicle.x, vehicle.y);
- // Vehicle glow
- if (activeTone === currentTone) {
- ctx.shadowBlur = 30;
- ctx.shadowColor = tones[currentTone].color;
- }
- // Vehicle body
- ctx.fillStyle = activeTone ? tones[currentTone].color : '#00ffff';
- ctx.beginPath();
- ctx.moveTo(0, -vehicle.height / 2);
- ctx.lineTo(vehicle.width / 2, vehicle.height / 2);
- ctx.lineTo(0, vehicle.height / 3);
- ctx.lineTo(-vehicle.width / 2, vehicle.height / 2);
- ctx.closePath();
- ctx.fill();
- // Vehicle trail
- ctx.strokeStyle = activeTone ? tones[currentTone].color : '#00ffff';
- ctx.lineWidth = 2;
- ctx.beginPath();
- ctx.moveTo(0, vehicle.height / 2);
- ctx.lineTo(0, vehicle.height / 2 + 20);
- ctx.stroke();
- ctx.restore();
- ctx.shadowBlur = 0;
- }
- // Game loop
- function gameLoop() {
- update();
- draw();
- requestAnimationFrame(gameLoop);
- }
- // Input handling
- document.addEventListener('keydown', (e) => {
- if (gameState !== 'playing') return;
- Object.keys(tones).forEach(tone => {
- if (e.key.toLowerCase() === tones[tone].key) {
- setActiveTone(tone);
- }
- });
- });
- document.addEventListener('keyup', (e) => {
- if (gameState !== 'playing') return;
- Object.keys(tones).forEach(tone => {
- if (e.key.toLowerCase() === tones[tone].key) {
- clearActiveTone(tone);
- }
- });
- });
- // Tone button handling
- document.querySelectorAll('.tone-btn').forEach(btn => {
- btn.addEventListener('mousedown', () => {
- if (gameState !== 'playing') return;
- const tone = btn.dataset.tone;
- setActiveTone(tone);
- });
- btn.addEventListener('mouseup', () => {
- if (gameState !== 'playing') return;
- const tone = btn.dataset.tone;
- clearActiveTone(tone);
- });
- btn.addEventListener('mouseleave', () => {
- if (gameState !== 'playing') return;
- const tone = btn.dataset.tone;
- clearActiveTone(tone);
- });
- });
- function setActiveTone(tone) {
- activeTone = tone;
- playTone(tone);
- document.querySelector(`.tone-btn[data-tone="${tone}"]`).classList.add('active');
- }
- function clearActiveTone(tone) {
- if (activeTone === tone) {
- activeTone = null;
- }
- document.querySelector(`.tone-btn[data-tone="${tone}"]`).classList.remove('active');
- }
- // Mouse control for vehicle x-position
- canvas.addEventListener('mousemove', (e) => {
- if (gameState !== 'playing') return;
- const rect = canvas.getBoundingClientRect();
- const mouseX = e.clientX - rect.left;
- vehicle.x = Math.max(canvas.width * 0.2, Math.min(canvas.width * 0.8 - vehicle.width, mouseX));
- });
- // Start game
- document.getElementById('startBtn').addEventListener('click', () => {
- document.getElementById('startScreen').style.display = 'none';
- gameState = 'playing';
- score = 0;
- speed = baseSpeed;
- initSegments();
- obstacles.length = 0;
- particles.length = 0;
- });
- document.getElementById('restartBtn').addEventListener('click', () => {
- document.getElementById('gameOver').style.display = 'none';
- gameState = 'playing';
- score = 0;
- speed = baseSpeed;
- vehicle.x = canvas.width / 2;
- initSegments();
- obstacles.length = 0;
- particles.length = 0;
- });
- // Window resize
- window.addEventListener('resize', () => {
- canvas.width = window.innerWidth;
- canvas.height = window.innerHeight;
- vehicle.x = canvas.width / 2;
- vehicle.y = canvas.height - 150; // Keep y tethered
- });
- // Initialize and start
- initSegments();
- gameLoop();
- </script>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment