diff --git a/Games/Ant_Smasher/index.html b/Games/Ant_Smasher/index.html index 6bd4b1f777..fbdbaf8769 100644 --- a/Games/Ant_Smasher/index.html +++ b/Games/Ant_Smasher/index.html @@ -3,35 +3,63 @@ Ant Smasher Game - + + + -

Ant Smasher0

- +

+ Ant Smasher + 0 +

+ + + + + +
+ + + +
+ + +
-
+
+
+
+
+
+
- + diff --git a/Games/Ant_Smasher/script.js b/Games/Ant_Smasher/script.js index 6f02773bf5..af8088fd1e 100644 --- a/Games/Ant_Smasher/script.js +++ b/Games/Ant_Smasher/script.js @@ -1,47 +1,114 @@ +// ===================== +// DOM ELEMENTS +// ===================== const holes = document.querySelectorAll(".hole"); -const scoreBoard = document.querySelector(".score"); const moles = document.querySelectorAll(".mole"); -let lastHole; +const scoreBoard = document.querySelector(".score"); +const game = document.querySelector(".game"); + +// ===================== +// GAME STATE +// ===================== +let lastHole = null; let timeUp = false; let score = 0; +let currentLevel = "easy"; -function randomTime(min, max) { +// ===================== +// LEVEL CONFIGURATION +// ===================== +const levels = { + easy: { min: 1000, max: 2000 }, + medium: { min: 600, max: 1200 }, + hard: { min: 300, max: 800 } +}; + +// ===================== +// UTILITY FUNCTIONS +// ===================== +function randomTime() { + const { min, max } = levels[currentLevel]; return Math.round(Math.random() * (max - min) + min); } function randomHole(holes) { const idx = Math.floor(Math.random() * holes.length); const hole = holes[idx]; + if (hole === lastHole) { return randomHole(holes); } + lastHole = hole; return hole; } +// ===================== +// CORE GAME LOOP +// ===================== function peep() { - const time = randomTime(500, 2000); + const time = randomTime(); const hole = randomHole(holes); + hole.classList.add("up"); + setTimeout(() => { hole.classList.remove("up"); if (!timeUp) peep(); }, time); } -function startGame() { - scoreBoard.textContent = 0; - timeUp = false; +// ===================== +// LEVEL HANDLING +// ===================== +function applyLevelClass() { + game.classList.remove("easy", "medium", "hard"); + game.classList.add(currentLevel); +} + +function setLevel(level) { + if (!levels[level]) return; + currentLevel = level; + applyLevelClass(); +} + +function autoLevelUp() { + if (score >= 10 && currentLevel !== "hard") { + setLevel("hard"); + } else if (score >= 5 && currentLevel === "easy") { + setLevel("medium"); + } +} + +// ===================== +// GAME CONTROLS +// ===================== +function startGame(level = "easy") { score = 0; + timeUp = false; + lastHole = null; + + scoreBoard.textContent = 0; + setLevel(level); + peep(); - setTimeout(() => (timeUp = true), 10000); + setTimeout(() => (timeUp = true), 10000); // 10 seconds } +// ===================== +// EVENT HANDLERS +// ===================== function bonk(e) { - if (!e.isTrusted) return; // cheater! + if (!e.isTrusted) return; // anti-cheat + score++; this.parentNode.classList.remove("up"); scoreBoard.textContent = score; + + autoLevelUp(); } +// ===================== +// EVENT LISTENERS +// ===================== moles.forEach((mole) => mole.addEventListener("click", bonk)); diff --git a/Games/Ant_Smasher/style.css b/Games/Ant_Smasher/style.css index 494f974094..e2b023564f 100644 --- a/Games/Ant_Smasher/style.css +++ b/Games/Ant_Smasher/style.css @@ -16,28 +16,39 @@ body { font-family: "Amatic SC", cursive; } +/* ===================== + HEADER & SCORE +===================== */ h1 { text-align: center; font-size: 10rem; line-height: 1; - margin-bottom: 0; + margin-bottom: 1rem; } .score { - background: rgba(255, 255, 255, 0.2); + background: rgba(255, 255, 255, 0.25); padding: 0 3rem; - line-height: 1; + line-height: 1.2; border-radius: 1rem; + display: inline-block; } +/* ===================== + GAME BOARD +===================== */ .game { width: 600px; height: 400px; display: flex; flex-wrap: wrap; margin: 0 auto; + position: relative; } +/* ===================== + HOLES +===================== */ .hole { flex: 1 0 33.33%; overflow: hidden; @@ -46,8 +57,8 @@ h1 { .hole:after { display: block; - background: url(../../assets/images/Ant_Smasher_dirt.svg) bottom center - no-repeat; + background: url("../../assets/images/Ant_Smasher_dirt.svg") + bottom center no-repeat; background-size: contain; content: ""; width: 100%; @@ -55,18 +66,60 @@ h1 { position: absolute; z-index: 2; bottom: -30px; + pointer-events: none; } +/* ===================== + MOLE +===================== */ .mole { - background: url("../../assets/images/Ant_Smasher.png") bottom center no-repeat; + background: url("../../assets/images/Ant_Smasher.png") + bottom center no-repeat; background-size: 60%; position: absolute; top: 100%; width: 100%; height: 100%; - transition: all 0.4s; + cursor: pointer; + will-change: transform, top; +} + +/* ===================== + LEVEL SPEED CONTROL +===================== */ + +/* Easy: relaxed */ +.game.easy .mole { + transition: top 0.45s ease-out; +} + +/* Medium: alert */ +.game.medium .mole { + transition: top 0.3s ease-out; } +/* Hard: frantic */ +.game.hard .mole { + transition: top 0.18s linear; +} + +/* ===================== + MOLE POP-UP STATE +===================== */ .hole.up .mole { top: 0; } + +/* ===================== + OPTIONAL VISUAL FEEDBACK +===================== */ + +/* Subtle danger tint on harder levels */ +.game.medium { + box-shadow: 0 0 15px rgba(255, 165, 0, 0.4); +} + +.game.hard { + box-shadow: 0 0 25px rgba(255, 60, 60, 0.6); +} +s \ No newline at end of file diff --git a/assets/images/Ant_Smasher_Demo.png b/assets/images/Ant_Smasher_Demo.png index a127f970f5..1845a0e23f 100644 Binary files a/assets/images/Ant_Smasher_Demo.png and b/assets/images/Ant_Smasher_Demo.png differ