Updates to background effects with levels

This commit is contained in:
Brian Fertig 2026-02-13 08:39:50 -07:00
parent bf0f6e48e9
commit 070d65e06d
1 changed files with 202 additions and 17 deletions

View File

@ -251,6 +251,69 @@
animation: levelUpAnim 1.5s forwards; animation: levelUpAnim 1.5s forwards;
} }
.wipe {
/* A fullscreen coloured overlay that slides across */
position: fixed;
inset: 0;
background: var(--wipe-color);
mix-blend-mode: screen; /* keep the glitch/scanline look */
animation: wipeAnim 0.8s ease-out forwards;
pointer-events: none;
z-index: 150; /* above .bg-effect but below UI */
}
/* Wipe moves from left → right */
@keyframes wipeAnim {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
/* ------------------------------------------------------------------ */
/* 2⃣ Define a palette of 10 neon colours (CSS custom properties) */
/* ------------------------------------------------------------------ */
:root {
/* existing vars … */
--neon-0: #c266c2; /* muted magenta */
--neon-1: #66c2c2; /* muted cyan */
--neon-2: #c26633; /* muted orangered */
--neon-3: #66c266; /* muted chartreuse */
--neon-4: #c2668a; /* muted deep pink */
--neon-5: #66c28a; /* muted spring green */
--neon-6: #c28533; /* muted dark orange */
--neon-7: #6688c2; /* muted deep sky blue */
--neon-8: #c266a0; /* muted hot pink */
--neon-9: #66c266; /* muted lawn green */
}
/* --------------------------------------------------------------
Digital Rain (Matrixstyle) sits above .bg-effect, below UI
-------------------------------------------------------------- */
.digital-rain {
position: fixed;
inset: 0;
pointer-events: none;
z-index: 0;
background: transparent;
}
/* Glitch flash that appears when wind changes */
body.glitch-flash::after {
content: "";
position: fixed;
inset: 0;
background: rgba(255,255,255,0.3);
mix-blend-mode: screen;
pointer-events: none;
animation: glitchFlash 0.3s forwards;
}
/* Flash animation */
@keyframes glitchFlash {
0% { opacity: 0; }
50% { opacity: 1; }
100% { opacity: 0; }
}
</style> </style>
</head> </head>
<body> <body>
@ -260,6 +323,8 @@
<audio id="sfx-levelUp" src="fx/levelUp.mp3" preload="auto"></audio> <audio id="sfx-levelUp" src="fx/levelUp.mp3" preload="auto"></audio>
<div class="bg-effect"></div> <div class="bg-effect"></div>
<canvas class="digital-rain"></canvas>
<div id="level-up-overlay" class="level-up">Level Up!</div> <div id="level-up-overlay" class="level-up">Level Up!</div>
@ -607,44 +672,156 @@
} }
} }
// 10colour neon palette (same order as the CSS vars above)
const NEON_PALETTE = [
getComputedStyle(document.documentElement).getPropertyValue('--neon-0').trim(),
getComputedStyle(document.documentElement).getPropertyValue('--neon-1').trim(),
getComputedStyle(document.documentElement).getPropertyValue('--neon-2').trim(),
getComputedStyle(document.documentElement).getPropertyValue('--neon-3').trim(),
getComputedStyle(document.documentElement).getPropertyValue('--neon-4').trim(),
getComputedStyle(document.documentElement).getPropertyValue('--neon-5').trim(),
getComputedStyle(document.documentElement).getPropertyValue('--neon-6').trim(),
getComputedStyle(document.documentElement).getPropertyValue('--neon-7').trim(),
getComputedStyle(document.documentElement).getPropertyValue('--neon-8').trim(),
getComputedStyle(document.documentElement).getPropertyValue('--neon-9').trim(),
];
function levelUp() { function levelUp() {
level++; level++;
// Increase Speed (Decrease interval)
// Cap at minimum 100ms
dropInterval = Math.max(100, 1000 - (level * 120)); dropInterval = Math.max(100, 1000 - (level * 120));
// Visual feedback on UI
document.getElementById('level-value').innerText = level; document.getElementById('level-value').innerText = level;
// Flash border effect // Flash border (unchanged)
const container = document.getElementById('game-container'); const container = document.getElementById('game-container');
container.style.borderColor = '#fff'; container.style.borderColor = '#fff';
setTimeout(() => { setTimeout(() => container.style.borderColor = '#333', 200);
container.style.borderColor = '#333';
}, 200);
playSFX('sfx-levelUp'); playSFX('sfx-levelUp');
// *** advance to next music track ***
nextTrack(); nextTrack();
// ----- NEW: show “Level Up!” animation ----- // ----- NEW: LevelUp “Level Up!” overlay (unchanged) -----
const overlay = document.getElementById('level-up-overlay'); const overlay = document.getElementById('level-up-overlay');
overlay.classList.remove('active'); // reset (in case its still there) overlay.classList.remove('active');
// Force reflow so the removal takes effect
void overlay.offsetWidth; void overlay.offsetWidth;
overlay.classList.add('active'); overlay.classList.add('active');
// Remove the class after the animation finishes (1.5s)
setTimeout(() => overlay.classList.remove('active'), 1500); setTimeout(() => overlay.classList.remove('active'), 1500);
/* -------------------------------------------------------------
* NEW SECTION background colour change + wipe effect
* ------------------------------------------------------------- */
// 1⃣ Pick a random neon colour
const newColor = NEON_PALETTE[Math.floor(Math.random() * NEON_PALETTE.length)];
// 2⃣ Apply it to the .bg-effect element (the base background)
const bg = document.querySelector('.bg-effect');
bg.style.background = newColor;
// 3⃣ Create a temporary wipe overlay
const wipe = document.createElement('div');
wipe.className = 'wipe';
// expose the colour to the CSS animation via a custom property
wipe.style.setProperty('--wipe-color', newColor);
document.body.appendChild(wipe);
// 4⃣ Remove the wipe element after the animation finishes
wipe.addEventListener('animationend', () => wipe.remove());
} }
function updateScore() { function updateScore() {
document.getElementById('score').innerText = score; document.getElementById('score').innerText = score;
document.getElementById('lines').innerText = linesClearedTotal; document.getElementById('lines').innerText = linesClearedTotal;
} }
// --------------------------------------------------------------
// DIGITAL RAIN (Matrixstyle) added after the existing script
// --------------------------------------------------------------
// Canvas & context for the rain effect
const rainCanvas = document.querySelector('.digital-rain');
const rainCtx = rainCanvas.getContext('2d');
// Resize canvas to fill the viewport
function resizeRainCanvas() {
rainCanvas.width = window.innerWidth;
rainCanvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeRainCanvas);
resizeRainCanvas();
// Characters used for the rain (feel free to customise)
const RAIN_CHARS = 'アァカサタナハマヤラワガザダバパイィキシチニヒミリヰギジヂビピウゥクスツヌフムユルヲグズブポエェケセテネヘメレヱゲゼデベペオォコソトホモヨロヲゴゾボポ01'.split('');
// Rain drop definition
class RainDrop {
constructor(x) {
this.x = x; // column (pixel)
this.y = Math.random() * -rainCanvas.height; // start above view
this.speed = 2 + Math.random() * 3; // fall speed
this.char = RAIN_CHARS[Math.floor(Math.random()*RAIN_CHARS.length)];
}
update(windAngle) {
// Apply wind: slight horizontal drift
this.x += Math.sin(windAngle) * 0.5;
this.y += this.speed + Math.cos(windAngle) * 0.5;
// Reset when offscreen
if (this.y > rainCanvas.height) {
this.y = Math.random() * -100;
this.x = Math.random() * rainCanvas.width;
this.char = RAIN_CHARS[Math.floor(Math.random()*RAIN_CHARS.length)];
}
}
draw(ctx) {
ctx.fillStyle = '#0ff';
ctx.font = '16px monospace';
ctx.fillText(this.char, this.x, this.y);
}
}
// Initialise a pool of drops (one per ~20px column)
let rainDrops = [];
function initRain() {
rainDrops = [];
const cols = Math.floor(rainCanvas.width / 20);
for (let i = 0; i < cols; i++) {
rainDrops.push(new RainDrop(i * 20));
}
}
initRain();
// Wind handling
let windAngle = 0; // radians
function changeWind() {
// Random new direction between -30° and +30°
windAngle = (Math.random() - 0.5) * (Math.PI / 3);
triggerGlitchFlash(); // flash when wind shifts
}
// Change wind every 812 seconds
setInterval(changeWind, 8000 + Math.random() * 4000);
// Glitch flash helper
function triggerGlitchFlash() {
document.body.classList.add('glitch-flash');
setTimeout(() => document.body.classList.remove('glitch-flash'), 300);
}
// Rain animation loop (runs alongside the game loop)
let rainRunning = false;
function rainLoop() {
if (!rainRunning) return; // stop when game ends
rainCtx.clearRect(0, 0, rainCanvas.width, rainCanvas.height);
// Update & draw each drop
rainDrops.forEach(drop => {
drop.update(windAngle);
drop.draw(rainCtx);
});
requestAnimationFrame(rainLoop);
}
// --- PARTICLE SYSTEM (The Cool Stuff) --- // --- PARTICLE SYSTEM (The Cool Stuff) ---
class Particle { class Particle {
@ -786,17 +963,25 @@
playerReset(); playerReset();
startMusic(); startMusic();
update(); update();
// ---- NEW: start rain ----
rainRunning = true;
rainLoop();
} }
function gameOver() { function gameOver() {
document.getElementById('game-over-screen').style.display = 'flex'; document.getElementById('game-over-screen').style.display = 'flex';
cancelAnimationFrame(update); cancelAnimationFrame(update);
// ---- NEW: stop rain ----
rainRunning = false;
} }
function resetGame() { function resetGame() {
startGame(); startGame();
} }
</script> </script>
</body> </body>
</html> </html>