From 43752fa8e40e8257f014c2c3585a3f9c774843da Mon Sep 17 00:00:00 2001 From: Spiel-Generator Workshop Date: Sat, 14 Mar 2026 22:21:58 +0000 Subject: [PATCH] fix: s3 board+palette init, module loading order, openMGTest API - editor.html: script tags for all 14 modules now correctly BEFORE init - init script moved to last @@ -1609,7 +2341,9 @@ function runStub(id, emoji, desc, name) {
- +
+ +
@@ -1643,8 +2377,8 @@ function runStub(id, emoji, desc, name) { + - @@ -1658,7 +2392,25 @@ function runStub(id, emoji, desc, name) { - - + + diff --git a/game.html b/game.html index 6087876..82197be 100644 --- a/game.html +++ b/game.html @@ -398,13 +398,20 @@ const BG_THEMES={ }; const THEME = BG_THEMES[cfg.background] || BG_THEMES.space; -// MG_INFO wird dynamisch aus den geladenen Modulen aufgebaut -function getMgInfo(id) { - const mod = window[`MG_${id}`]; - if (mod) return { emoji: mod.emoji, name: mod.name, desc: mod.desc, controls: mod.controls }; - return { emoji: '๐ŸŽฎ', name: id, desc: 'Mini-Game!', controls: 'Variiert' }; -} - +const MG_INFO={ + snake: {emoji:'๐Ÿ',name:'Snake', desc:'Steuere die Schlange! Iss das Essen ohne gegen die Wand zu fahren.',controls:'Pfeiltasten oder WASD'}, + flappy: {emoji:'๐Ÿฆ',name:'Flappy Bird', desc:'Klick oder Leertaste, um durch die Rรถhren zu fliegen!', controls:'Klick / Leertaste'}, + memory: {emoji:'๐Ÿƒ',name:'Memory', desc:'Finde alle Paare โ€” so schnell wie mรถglich!', controls:'Mausklick'}, + quiz: {emoji:'โ“',name:'Quiz', desc:'Beantworte die Frage richtig!', controls:'Mausklick'}, + reaction: {emoji:'โšก',name:'Reaktion', desc:'Drรผck den Knopf so schnell du kannst wenn er erscheint!', controls:'Klick / Leertaste'}, + basketball:{emoji:'๐Ÿ€',name:'Basketball', desc:'Ziehe den Ball und lass ihn los um zu werfen!', controls:'Maus ziehen'}, + catch: {emoji:'๐ŸŽ',name:'ร„pfel fangen',desc:'Bewege den Korb mit den Pfeiltasten!', controls:'โ† โ†’ oder A/D'}, + maze: {emoji:'๐ŸŒ€',name:'Labyrinth', desc:'Finde den Ausgang!', controls:'Pfeiltasten / WASD'}, + simon: {emoji:'๐Ÿ”ด',name:'Simon Says', desc:'Merke und wiederhole die Farb-Sequenz!', controls:'Mausklick'}, + puzzle: {emoji:'๐Ÿงฉ',name:'Rรคtsel', desc:'Lรถse die Aufgabe!', controls:'Mausklick'}, + spotdiff: {emoji:'๐Ÿ”',name:'Unterschiede',desc:'Finde alle Unterschiede!', controls:'Mausklick'}, + typing: {emoji:'โŒจ๏ธ',name:'Tipp-Rennen', desc:'Tippe das Wort so schnell wie mรถglich!', controls:'Tastatur'}, +}; const figEmoji = FIGURES[cfg.figure] || '๐ŸŽฎ'; const LETTERS = ['A','B','C','D']; @@ -959,56 +966,47 @@ function enableRoll(){ /* โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• MINIGAME SYSTEM โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• */ function openMinigame(id){ - const info = getMgInfo(id); - currentMgId = id; - document.getElementById('mgTitle').innerHTML = `${info.emoji} ${info.name}`; - document.getElementById('mgDesc').textContent = info.desc; - document.getElementById('mgControls').innerHTML = `๐ŸŽฎ ${info.controls}`; - document.getElementById('mgResultBar').style.display = 'none'; - document.getElementById('btnMgContinue').style.display = 'none'; + const info=MG_INFO[id]||{emoji:'๐ŸŽฎ',name:id,desc:'Mini-Game!',controls:'Variiert'}; + currentMgId=id; + document.getElementById('mgTitle').innerHTML=`${info.emoji} ${info.name}`; + document.getElementById('mgDesc').textContent=info.desc; + document.getElementById('mgControls').innerHTML=`๐ŸŽฎ ${info.controls}`; + document.getElementById('mgResultBar').style.display='none'; + document.getElementById('btnMgContinue').style.display='none'; - const wrap = document.getElementById('mgCanvasWrap'); - wrap.innerHTML = ''; - wrap.style.minHeight = ''; + const wrap=document.getElementById('mgCanvasWrap'); + wrap.innerHTML=''; - if (mgActive && mgActive.stop) mgActive.stop(); - mgActive = null; mgResult = null; + if(mgActive&&mgActive.stop) mgActive.stop(); + mgActive=null; mgResult=null; playSfx('mg'); document.getElementById('mgOverlay').classList.add('open'); - const W = Math.min(560, window.innerWidth - 80) - 48; - const H = 300; + const W=Math.min(560, window.innerWidth-80)-48; + const H=260; - // Theme aus THEME-Objekt - const modCfg = { - theme: { primary: THEME.primary, glow: THEME.glow }, - quizData: quizData, - fieldIndex: pos, - devName: cfg.devName, - gameName: cfg.name, + const launchers={ + snake: launchSnake, + flappy: launchFlappy, + memory: launchMemory, + quiz: launchQuiz, + reaction:launchReaction, }; - // onResult-Handler setzen - window._mgOnResult = finishMinigame; - if (window.MGAPI) MGAPI.onResult = finishMinigame; - - const mod = window[`MG_${id}`]; - if (mod) { - mgActive = mod.launch(wrap, W, H, modCfg); - } else { - // Fallback - wrap.style.minHeight = H + 'px'; - wrap.innerHTML = `
+ if(launchers[id]){ mgActive=launchers[id](wrap,W,H); } + else { + // Placeholder for other games + wrap.style.minHeight=H+'px'; + wrap.innerHTML=`
${info.emoji}
${info.name}
-
Modul wird geladen...
+
Dieses Mini-Game wird bald verfรผgbar sein!
`; } } - function finishMinigame(won){ if(mgActive&&mgActive.stop) mgActive.stop(); mgActive=null; @@ -1053,6 +1051,213 @@ function skipMinigame(){ enableRoll(); } +/* โ•โ• SNAKE โ•โ• */ +function launchSnake(wrap,W,H){ + const canvas=document.createElement('canvas'); + canvas.width=W; canvas.height=H; + wrap.appendChild(canvas); + const ctx=canvas.getContext('2d'); + const SZ=20, cols=Math.floor(W/SZ), rows=Math.floor(H/SZ); + let snake=[{x:5,y:5},{x:4,y:5},{x:3,y:5}],dir={x:1,y:0},food={x:10,y:8},score=0,dead=false,started=true; + let raf,stopped=false; + const onKey=e=>{ + if(e.key==='ArrowUp'&&dir.y===0)dir={x:0,y:-1}; + if(e.key==='ArrowDown'&&dir.y===0)dir={x:0,y:1}; + if(e.key==='ArrowLeft'&&dir.x===0)dir={x:-1,y:0}; + if(e.key==='ArrowRight'&&dir.x===0)dir={x:1,y:0}; + if(e.key==='w')dir={x:0,y:-1}; if(e.key==='s')dir={x:0,y:1}; + if(e.key==='a')dir={x:-1,y:0}; if(e.key==='d')dir={x:1,y:0}; + }; + document.addEventListener('keydown',onKey); + let last=0, endTimer=null; + function loop(ts){ + if(stopped)return; raf=requestAnimationFrame(loop); + if(ts-last<140)return; last=ts; + if(!dead){ + const h={x:snake[0].x+dir.x,y:snake[0].y+dir.y}; + if(h.x<0||h.x>=cols||h.y<0||h.y>=rows||snake.some(s=>s.x===h.x&&s.y===h.y)){ + dead=true; + if(!endTimer) endTimer=setTimeout(()=>finishMinigame(score>=3),1200); + } else { + snake.unshift(h); + if(h.x===food.x&&h.y===food.y){score++;food={x:Math.floor(Math.random()*cols),y:Math.floor(Math.random()*rows)};} + else snake.pop(); + } + } + ctx.fillStyle='#050508'; ctx.fillRect(0,0,W,H); + ctx.fillStyle=THEME.primary; ctx.beginPath(); ctx.arc(food.x*SZ+SZ/2,food.y*SZ+SZ/2,SZ*0.4,0,Math.PI*2); ctx.fill(); + snake.forEach((s,i)=>{ + ctx.fillStyle=i===0?THEME.primary:`${THEME.primary}99`; + ctx.fillRect(s.x*SZ+1,s.y*SZ+1,SZ-2,SZ-2); + }); + ctx.fillStyle='#fff'; ctx.font='bold 13px Nunito,sans-serif'; ctx.textAlign='left'; ctx.fillText(`๐Ÿ• ${score} Ziel: 3`,8,18); + if(dead){ + ctx.fillStyle='rgba(239,68,68,0.8)'; ctx.fillRect(0,H/2-28,W,56); + ctx.fillStyle='#fff'; ctx.font='bold 20px Fredoka One,cursive'; ctx.textAlign='center'; + ctx.fillText(score>=3?'๐ŸŽ‰ Geschafft!':'๐Ÿ’€ Game Over',W/2,H/2+6); + } + } + raf=requestAnimationFrame(loop); + return{stop:()=>{stopped=true;cancelAnimationFrame(raf);document.removeEventListener('keydown',onKey);}}; +} + +/* โ•โ• FLAPPY โ•โ• */ +function launchFlappy(wrap,W,H){ + const canvas=document.createElement('canvas'); canvas.width=W; canvas.height=H; wrap.appendChild(canvas); + const ctx=canvas.getContext('2d'); + let bird={y:H/2,vy:0},pipes=[{x:W,gap:Math.random()*(H-100)+30}],score=0,dead=false,started=false; + const GRAV=0.5,JUMP=-8,PW=38,GAP=85; + let raf,stopped=false,endTimer=null; + const jump=()=>{if(!dead){bird.vy=JUMP;started=true;}}; + const onKey=e=>{if(e.code==='Space'){e.preventDefault();jump();}}; + document.addEventListener('keydown',onKey); canvas.addEventListener('click',jump); + function loop(){ + if(stopped)return; raf=requestAnimationFrame(loop); + ctx.fillStyle='#050508'; ctx.fillRect(0,0,W,H); + if(started&&!dead){ + bird.vy+=GRAV; bird.y+=bird.vy; + pipes.forEach(p=>p.x-=2.8); + if(pipes[pipes.length-1].xp.x>-PW); + pipes.forEach(p=>{if(p.x+PW<50&&!p.passed){p.passed=true;score++;}}); + if(bird.y<0||bird.y+20>H)dead=true; + pipes.forEach(p=>{if(50p.x&&(bird.yp.gap+GAP))dead=true;}); + if(dead&&!endTimer) endTimer=setTimeout(()=>finishMinigame(score>=3),1000); + } + pipes.forEach(p=>{ + ctx.fillStyle=THEME.primary+'bb'; + ctx.fillRect(p.x,0,PW,p.gap); ctx.fillRect(p.x,p.gap+GAP,PW,H-p.gap-GAP); + }); + ctx.fillStyle=dead?'#ef4444':THEME.primary; + ctx.beginPath(); ctx.ellipse(50+14,bird.y+10,14,10,bird.vy*0.04,0,Math.PI*2); ctx.fill(); + ctx.fillStyle='#fff'; ctx.font='bold 13px Nunito,sans-serif'; ctx.textAlign='left'; ctx.fillText(`๐Ÿฆ ${score} Ziel: 3`,8,18); + if(!started){ctx.fillStyle='rgba(255,255,255,0.7)';ctx.textAlign='center';ctx.font='13px Nunito,sans-serif';ctx.fillText('Klicken oder Leertaste',W/2,H/2+40);} + if(dead){ctx.fillStyle='rgba(239,68,68,0.8)';ctx.fillRect(0,H/2-28,W,56);ctx.fillStyle='#fff';ctx.font='bold 20px Fredoka One,cursive';ctx.textAlign='center';ctx.fillText(score>=3?'๐ŸŽ‰ Geschafft!':'๐Ÿ’€ Daneben!',W/2,H/2+6);} + } + raf=requestAnimationFrame(loop); + return{stop:()=>{stopped=true;cancelAnimationFrame(raf);document.removeEventListener('keydown',onKey);canvas.removeEventListener('click',jump);}}; +} + +/* โ•โ• MEMORY โ•โ• */ +function launchMemory(wrap,W,H){ + const canvas=document.createElement('canvas'); canvas.width=W; canvas.height=H; wrap.appendChild(canvas); + const ctx=canvas.getContext('2d'); + const emojis=['๐Ÿฑ','๐Ÿถ','๐ŸฆŠ','๐Ÿธ','๐Ÿฆ‹','๐Ÿ ']; + const all=[...emojis,...emojis].sort(()=>Math.random()-0.5); + let cards=all.map((e,i)=>({e,i,open:false})); + let flipped=[],matched=[],checking=false,moves=0; + let raf,stopped=false; + const C=4,R=3,cw=Math.floor((W-16)/(C+0.5)),ch=Math.floor((H-16)/R); + const ox=(W-C*cw)/2, oy=(H-R*ch)/2; + canvas.addEventListener('click',e=>{ + if(checking)return; + const r=canvas.getBoundingClientRect(); + const mx=e.clientX-r.left, my=e.clientY-r.top; + for(let ri=0;ri=x&&mx=y&&my{ + if(flipped[0].e===flipped[1].e) matched.push(flipped[0].i,flipped[1].i); + else flipped.forEach(c=>c.open=false); + flipped=[]; checking=false; + if(matched.length===cards.length) setTimeout(()=>finishMinigame(true),600); + },700); + } + break; + } + } + }); + function loop(){ + if(stopped)return; raf=requestAnimationFrame(loop); + ctx.fillStyle='#050508'; ctx.fillRect(0,0,W,H); + ctx.fillStyle='#fff'; ctx.font='bold 13px Nunito,sans-serif'; ctx.textAlign='left'; ctx.fillText(`๐Ÿƒ ${matched.length/2}/${emojis.length} Paare Zรผge: ${moves}`,8,18); + for(let ri=0;ri{stopped=true;cancelAnimationFrame(raf);}}; +} + +/* โ•โ• QUIZ โ•โ• */ +function launchQuiz(wrap,W,H){ + const q=quizData[quizIdx]||null; quizIdx++; + if(!q||!q.question){ wrap.innerHTML=`
โ“
Keine Quiz-Frage hinterlegt.
`; return{stop:()=>{}};} + let answered=false; + wrap.innerHTML=` +
+
โ“ Quiz-Frage
+
${q.question}
+
+ +
+ `; + const grid=wrap.querySelector('#quizAnswers'); + LETTERS.forEach((L,i)=>{ + const btn=document.createElement('button'); + btn.style.cssText=`background:rgba(255,255,255,0.06);border:1.5px solid rgba(255,255,255,0.12);border-radius:10px;padding:10px 12px;font-family:'Nunito',sans-serif;font-size:13px;font-weight:700;color:#fff;cursor:pointer;display:flex;align-items:center;gap:8px;transition:all 0.2s;text-align:left;`; + btn.innerHTML=`${L}${q.answers[i]||'?'}`; + btn.addEventListener('mouseenter',()=>{ if(!answered) btn.style.borderColor=THEME.primary; }); + btn.addEventListener('mouseleave',()=>{ if(!answered) btn.style.borderColor='rgba(255,255,255,0.12)'; }); + btn.addEventListener('click',()=>{ + if(answered)return; answered=true; + const correct=i===q.correct; + btn.style.borderColor=correct?'#10b981':'#ef4444'; + btn.style.background=correct?'rgba(16,185,129,0.15)':'rgba(239,68,68,0.1)'; + if(!correct){ + const cBtn=grid.children[q.correct]; + cBtn.style.borderColor='#10b981'; cBtn.style.background='rgba(16,185,129,0.15)'; + } + const res=wrap.querySelector('#quizResult'); + res.style.display='block'; + res.style.color=correct?'#10b981':'#ef4444'; + res.textContent=correct?'โœ… Richtig!':'โŒ Falsch!'; + setTimeout(()=>finishMinigame(correct),1200); + }); + grid.appendChild(btn); + }); + return{stop:()=>{}}; +} + +/* โ•โ• REACTION โ•โ• */ +function launchReaction(wrap,W,H){ + const canvas=document.createElement('canvas'); canvas.width=W; canvas.height=H; wrap.appendChild(canvas); + const ctx=canvas.getContext('2d'); + let phase='wait',waitEnd=0,reactionStart=0,times=[],best=Infinity; + let raf,stopped=false; + function reset(){phase='wait';waitEnd=performance.now()+(2+Math.random()*3)*1000;}reset(); + const react=()=>{ + if(phase==='ready'){const t=performance.now()-reactionStart;times.push(t);best=Math.min(best,t);if(times.length>=3){setTimeout(()=>finishMinigame(best<600),800);}else reset();} + else if(phase==='wait'){phase='toosoon';setTimeout(reset,1000);} + }; + const onKey=e=>{if(e.code==='Space')react();}; + document.addEventListener('keydown',onKey); canvas.addEventListener('click',react); + function loop(ts){ + if(stopped)return; raf=requestAnimationFrame(loop); + if(phase==='wait'&&ts>waitEnd){phase='ready';reactionStart=performance.now();} + ctx.fillStyle=phase==='ready'?'#16a34a':phase==='toosoon'?'#7f1d1d':'#050508'; + ctx.fillRect(0,0,W,H); + ctx.textAlign='center'; + if(phase==='wait'){ctx.fillStyle='#a7a3c2';ctx.font='16px Nunito,sans-serif';ctx.fillText('Warte...',W/2,H/2-20);ctx.fillText(`${times.length}/3 Runden`,W/2,H/2+10);} + if(phase==='ready'){ctx.fillStyle='#fff';ctx.font='bold 36px Fredoka One,cursive';ctx.fillText('JETZT!',W/2,H/2);ctx.font='14px Nunito,sans-serif';ctx.fillText('Klick oder Leertaste!',W/2,H/2+36);} + if(phase==='toosoon'){ctx.fillStyle='#fca5a5';ctx.font='bold 24px Fredoka One,cursive';ctx.fillText('Zu frรผh! ๐Ÿ˜…',W/2,H/2);} + if(times.length>0){const last=times[times.length-1];ctx.fillStyle='rgba(255,255,255,0.6)';ctx.font='13px Nunito,sans-serif';ctx.fillText(`Letzte: ${Math.round(last)}ms Beste: ${Math.round(best)}ms`,W/2,H-16);} + ctx.textAlign='left'; + } + raf=requestAnimationFrame(loop); + return{stop:()=>{stopped=true;cancelAnimationFrame(raf);document.removeEventListener('keydown',onKey);canvas.removeEventListener('click',react);}}; +} /* โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• WIN / GAME OVER โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• */ function showWin(){ @@ -1088,19 +1293,5 @@ function showGameOver(){ function showMenu(){ showToast('โ˜ฐ Menรผ kommt in der finalen Version!'); } function backToEditor(){ window.close(); } - - - - - - - - - - - - - -