SingerkoneRKM/meaing_attack
0
1<!doctype html>2<html lang="en">3<head>4<meta charset="utf-8" />5<meta name="viewport" content="width=device-width,initial-scale=1" />6<title>Word Attack — Vocabulary Battle</title>7 8<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>9 10<style>11:root{12 --bg:#05050f;--panel:rgba(0,0,0,.45);--accent:#b71c1c;13 --text:#f5f5f5;--muted:#bfc6cc;14}15html,body{margin:0;height:100%;background:var(--bg);color:var(--text);font-family:Inter,system-ui;overflow:hidden}16button{background:var(--accent);border:0;color:#fff;padding:8px 12px;border-radius:8px;font-weight:600;cursor:pointer}17button.secondary{background:transparent;border:1px solid rgba(255,255,255,.08)}18.ui{position:fixed;left:12px;right:12px;top:12px;display:flex;justify-content:space-between;z-index:10}19.panel{background:var(--panel);padding:8px 12px;border-radius:8px;display:flex;gap:12px;align-items:center}20#questionBox{position:fixed;top:84px;left:50%;transform:translateX(-50%);21background:rgba(255,255,255,.05);padding:8px 16px;border-radius:8px;font-weight:700}22canvas{width:100vw;height:100vh}23.overlay{position:fixed;inset:0;background:rgba(0,0,0,.7);24display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none}25.overlay.show{opacity:1;pointer-events:auto}26.overlay-panel{background:#000;padding:24px;border-radius:12px;text-align:center}27</style>28</head>29 30<body>31 32<div class="ui">33 <div class="panel">34 <div>Score: <span id="score">0</span></div>35 <div>Lives: <span id="lives">3</span></div>36 </div>37 <div class="panel">38 <label>39 <input type="file" id="fileInput" accept=".xlsx" hidden>40 <span style="cursor:pointer">Upload Excel</span>41 </label>42 <button id="startBtn">Start</button>43 <button id="pauseBtn" class="secondary">Pause</button>44 </div>45</div>46 47<div id="questionBox">Word: <span id="currentWord">—</span></div>48<canvas id="game"></canvas>49 50<div id="overlay" class="overlay">51 <div class="overlay-panel">52 <h1>GAME OVER</h1>53 <p>Final Score: <span id="finalScore"></span></p>54 <button id="restartBtn">Restart</button>55 </div>56</div>57 58<script>59/* ---------------- CONFIG ---------------- */60const CONFIG = { lives:3, options:4 };61 62/* ---------------- DATA ---------------- */63const FALLBACK = [64 ['vivid','bright'],['fragile','easily broken'],65 ['orbit','path around a body'],['gravity','pulling force']66];67let pairs=[...FALLBACK], currentIndex=-1;68 69/* ---------------- STATE ---------------- */70let score=0,lives=CONFIG.lives,state='stopped';71let options=[], lasers=[], stars=[];72const canvas=document.getElementById('game');73const ctx=canvas.getContext('2d');74resize(); window.addEventListener('resize',resize);75 76/* ---------------- UI ---------------- */77const scoreEl=scoreSpan=document.getElementById('score');78const livesEl=document.getElementById('lives');79const wordEl=document.getElementById('currentWord');80const overlay=document.getElementById('overlay');81const finalScore=document.getElementById('finalScore');82 83/* ---------------- HELPERS ---------------- */84function resize(){85 canvas.width=window.innerWidth;86 canvas.height=window.innerHeight;87}88function rand(a,b){return a+Math.random()*(b-a);}89 90/* ---------------- STARS ---------------- */91for(let i=0;i<100;i++)stars.push({x:Math.random()*canvas.width,y:Math.random()*canvas.height,s:Math.random()*2});92 93/* ---------------- GAME FLOW ---------------- */94function nextRound(){95 currentIndex=Math.floor(Math.random()*pairs.length);96 const [word,correct]=pairs[currentIndex];97 wordEl.textContent=word;98 options=[];99 ctx.font='16px Inter, Arial';100 101 const pool=new Set([correct]);102 while(pool.size<CONFIG.options){103 pool.add(pairs[Math.floor(Math.random()*pairs.length)][1]);104 }105 [...pool].sort(()=>Math.random()-0.5).forEach(t=>{106 options.push({107 text:t,isCorrect:t===correct,108 x:rand(120,canvas.width-120),109 y:rand(-120,-40),110 vy:rand(40,80),111 w:Math.max(140,ctx.measureText(t).width+30),112 h:32,resolved:false113 });114 });115}116 117/* ---------------- INPUT ---------------- */118canvas.addEventListener('click',e=>{119 if(state!=='running')return;120 const r=canvas.getBoundingClientRect();121 const mx=e.clientX-r.left,my=e.clientY-r.top;122 const hit=options.find(o=>123 mx>o.x-o.w/2&&mx<o.x+o.w/2&&124 my>o.y-o.h/2&&my<o.y+o.h/2125 );126 if(!hit||hit.resolved)return;127 hit.resolved=true;128 lasers.push({sx:canvas.width/2,sy:canvas.height-60,tx:hit.x,ty:hit.y,a:0});129 130 if(hit.isCorrect){131 score+=20;scoreEl.textContent=score;132 setTimeout(nextRound,250);133 }else{134 lives--;livesEl.textContent=lives;135 options=options.filter(o=>o!==hit);136 if(lives<=0)gameOver();137 }138});139 140/* ---------------- LOOP ---------------- */141function loop(){142 requestAnimationFrame(loop);143 if(state!=='running')return;144 ctx.fillStyle='#03030a';ctx.fillRect(0,0,canvas.width,canvas.height);145 146 stars.forEach(s=>{s.y+=s.s;if(s.y>canvas.height)s.y=0;147 ctx.fillStyle='#fff';ctx.fillRect(s.x,s.y,2,2);});148 149 ctx.font='16px Inter, Arial';150 options.forEach(o=>{151 o.y+=o.vy*0.016;152 ctx.fillStyle='rgba(255,255,255,.06)';153 ctx.fillRect(o.x-o.w/2,o.y-o.h/2,o.w,o.h);154 ctx.fillStyle='#fff';ctx.textAlign='center';ctx.textBaseline='middle';155 ctx.fillText(o.text,o.x,o.y);156 if(o.isCorrect&&o.y>canvas.height){157 lives--;livesEl.textContent=lives;158 nextRound();159 }160 });161 162 lasers.forEach(l=>{163 l.a+=0.1;164 ctx.strokeStyle='rgba(255,80,80,.8)';165 ctx.lineWidth=4;166 ctx.beginPath();ctx.moveTo(l.sx,l.sy);ctx.lineTo(l.tx,l.ty);ctx.stroke();167 });168 lasers=lasers.filter(l=>l.a<1);169}170loop();171 172/* ---------------- CONTROL ---------------- */173function start(){174 score=0;lives=CONFIG.lives;175 scoreEl.textContent=score;livesEl.textContent=lives;176 overlay.classList.remove('show');177 state='running';nextRound();178}179function gameOver(){180 state='stopped';181 finalScore.textContent=score;182 overlay.classList.add('show');183}184 185document.getElementById('startBtn').onclick=start;186document.getElementById('restartBtn').onclick=start;187document.getElementById('pauseBtn').onclick=()=>state=state==='running'?'paused':'running';188 189/* ---------------- EXCEL ---------------- */190document.getElementById('fileInput').onchange=e=>{191 const f=e.target.files[0];if(!f)return;192 const r=new FileReader();193 r.onload=ev=>{194 const wb=XLSX.read(new Uint8Array(ev.target.result),{type:'array'});195 const rows=XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]],{header:1});196 pairs=rows.filter(r=>r[0]&&r[1]).map(r=>[String(r[0]),String(r[1])]);197 alert(`Loaded ${pairs.length} words`);198 };199 r.readAsArrayBuffer(f);200};201</script>202</body>203</html>204 