edu-boardgame-generator/js/minigame-test.js

155 lines
7.9 KiB
JavaScript

/* minigame-test.js — Test-Popup (preview) der Mini-Game-Module */
/* ══════════════════════════════════════════════
INIT
══════════════════════════════════════════════ */
// ── Init wird nach Modulen ausgeführt (siehe unten) ──
/* ══════════════════════════════════════════════
MINI-GAME TEST POPUP
══════════════════════════════════════════════ */
let mgTestLoop=null;
let mgTestActive=null;
function openMGTest(id, e){
e&&e.stopPropagation();
const mg=MINIGAMES.find(m=>m.id===id);if(!mg)return;
closeMGTest();
currentMGId=id;
document.getElementById('mgTestEmoji').textContent=mg.e;
document.getElementById('mgTestTitle').textContent=mg.n+' — Probespiel';
// Beschreibung aus Modul oder MINIGAMES
const mod=window['MG_'+id];
document.getElementById('mgTestDesc').textContent=mod?mod.desc:(mg.desc||'');
document.getElementById('mgTestMsg').textContent='';
document.getElementById('mgTestMsg').className='';
const ctrl=document.getElementById('mgTestControls');
ctrl.innerHTML=renderMgSettings(id)+'<div style="display:flex;gap:8px;margin-top:4px"><button class="mg-ctrl-btn" onclick="restartMGTest()">🔄 Neu starten</button><button class="mg-ctrl-btn secondary" onclick="closeMGTest()">Schließen</button></div>';
document.getElementById('mgTestOverlay').classList.add('open');
document.body.style.overflow='hidden';
// Modul-System: preview() aufrufen
const wrap=document.getElementById('mgTestWrap');
wrap.innerHTML='';
if(mod && mod.preview){
// Theme aus aktuellem ST-State
const bg=BACKGROUNDS.find(b=>b.id===ST.background);
const modCfg={
theme: bg?{primary:bg.color||'#7c3aed',glow:bg.glow||'rgba(124,58,237,0.4)'}:{primary:'#7c3aed',glow:'rgba(124,58,237,0.4)'},
quizData: ST.quizData||[],
devName: ST.devName,
gameName: ST.name,
figure: (FIGURES.find(f=>f.id===ST.figure)||{}).e || '🐦',
};
Object.assign(modCfg, getMgSettings(id));
// onResult-Handler
window._mgOnResult=(won)=>{
setMsg(won?'🏆 Gewonnen! 🎉':'💀 Verloren! Versuch es nochmal.', won?'win':'lose');
};
if(window.MGAPI) MGAPI.onResult=window._mgOnResult;
// Bug 4 Fix: requestAnimationFrame stellt sicher dass der Browser das
// Overlay gerendert hat und wrap.offsetWidth korrekt ist
requestAnimationFrame(()=>{
mgTestActive=mod.preview(wrap, Math.max(wrap.offsetWidth,360), Math.max(wrap.offsetHeight||0,560), modCfg);
});
} else {
setMsg('Vorschau für dieses Mini-Game nicht verfügbar.', 'lose');
}
}
function closeMGTest(){
// Modul stoppen falls aktiv
if(mgTestActive&&mgTestActive.stop){mgTestActive.stop();mgTestActive=null;}
if(mgTestLoop){clearInterval(mgTestLoop);cancelAnimationFrame(mgTestLoop);mgTestLoop=null;}
document.removeEventListener('keydown',mgKeyHandler);
document.removeEventListener('mousemove',mgMouseHandler);
document.getElementById('mgTestOverlay').classList.remove('open');
document.body.style.overflow='';
// Wrap leeren
const wrap=document.getElementById('mgTestWrap');
if(wrap)wrap.innerHTML='';
const canvas=document.getElementById('mgTestCanvas');
if(canvas){const ctx=canvas.getContext('2d');ctx.clearRect(0,0,canvas.width,canvas.height);}
currentMGId=null;
}
let currentMGId=null;
function restartMGTest(){
if(currentMGId)openMGTest(currentMGId,null);
}
let mgKeyHandler=null,mgMouseHandler=null;
function setMsg(txt,cls=''){const m=document.getElementById('mgTestMsg');m.textContent=txt;m.className=cls;}
/* ══════════════════════════════════════════════
SCHWIERIGKEITS-EINSTELLUNGEN je Mini-Game
Werte landen in ST.mgSettings[id] → werden exportiert (Teilen-URL)
und im fertigen Spiel angewandt.
══════════════════════════════════════════════ */
const MG_SETTINGS_DEF={
flappy:[
{key:'win', label:'Hindernisse bis Sieg', min:5, max:30, step:1, def:15},
{key:'speed',label:'Start-Tempo', min:1.8,max:4.5, step:0.1, def:2.7, fmt:v=>(+v).toFixed(1)},
{key:'gap', label:'Start-Größe Durchgang',min:110,max:210, step:5, def:168, fmt:v=>v+' px'},
{key:'rampSpeed',type:'toggle',label:'Tempo steigt pro Durchgang',def:true},
{key:'shrinkGap',type:'toggle',label:'Durchgänge werden enger', def:true},
],
flappy2p:[
{key:'bestOf', label:'Best of', min:2, max:5, step:1, def:3, fmt:v=>'Best of '+v},
{key:'speed', label:'Start-Tempo', min:1.8,max:4.5, step:0.1, def:2.7, fmt:v=>(+v).toFixed(1)},
{key:'gap', label:'Start-Größe Durchgang',min:110,max:210, step:5, def:168, fmt:v=>v+' px'},
{key:'rampSpeed',type:'toggle',label:'Tempo steigt pro Durchgang',def:true},
{key:'shrinkGap',type:'toggle',label:'Durchgänge werden enger', def:true},
],
};
// Liefert (und initialisiert mit Defaults) die Einstellungen eines Mini-Games
function getMgSettings(id){
if(!ST.mgSettings)ST.mgSettings={};
const defs=MG_SETTINGS_DEF[id];
if(!defs)return {};
if(!ST.mgSettings[id])ST.mgSettings[id]={};
defs.forEach(d=>{ if(ST.mgSettings[id][d.key]==null)ST.mgSettings[id][d.key]=d.def; });
return ST.mgSettings[id];
}
// Einstellungs-Panel im Test-Popup (Slider = Startwerte, Toggles = Steigerung obendrauf)
function renderMgSettings(id){
const defs=MG_SETTINGS_DEF[id]; if(!defs)return '';
const s=getMgSettings(id);
const rows=defs.filter(d=>d.type!=='toggle').map(d=>{
const v=s[d.key], disp=d.fmt?d.fmt(v):v;
return `<div style="display:flex;align-items:center;gap:10px;margin:7px 0;font-size:13px;color:#cdc9e6">
<span style="flex:0 0 150px">${d.label}</span>
<input type="range" min="${d.min}" max="${d.max}" step="${d.step}" value="${v}" style="flex:1;accent-color:#7c3aed;cursor:pointer"
oninput="mgSetLabel('${id}','${d.key}',this.value)" onchange="mgSetApply('${id}','${d.key}',this.value)">
<b id="mgset-${id}-${d.key}" style="flex:0 0 56px;text-align:right;color:#a78bfa">${disp}</b>
</div>`;
}).join('');
const toggles=defs.filter(d=>d.type==='toggle');
let tg='';
if(toggles.length){
tg='<div style="display:flex;gap:8px;margin-top:9px">'+toggles.map(d=>{
const on=!!s[d.key];
return `<div onclick="mgToggle('${id}','${d.key}')" style="flex:1;cursor:pointer;user-select:none;border-radius:9px;padding:8px 10px;font-size:12px;line-height:1.25;text-align:center;transition:all 0.12s;border:1.5px solid ${on?'#7c3aed':'#2e2b4a'};background:${on?'rgba(124,58,237,0.22)':'#13111f'};color:${on?'#c4b5fd':'#7c7596'}">
<div style="font-size:15px;margin-bottom:1px">${on?'✓':'○'}</div>${d.label}</div>`;
}).join('')+'</div>';
}
return `<div style="background:#13111f;border:1px solid #2e2b4a;border-radius:10px;padding:8px 12px;margin-bottom:10px">
<div style="font-size:12px;color:#7c7596;margin-bottom:2px">⚙️ Schwierigkeit — wird im geteilten Spiel übernommen</div>${rows}${tg}</div>`;
}
// Live: nur Anzeige aktualisieren (beim Ziehen)
function mgSetLabel(id,key,val){
const d=(MG_SETTINGS_DEF[id]||[]).find(x=>x.key===key); if(!d)return;
const el=document.getElementById('mgset-'+id+'-'+key);
if(el)el.textContent=d.fmt?d.fmt(val):val;
}
// Übernehmen (beim Loslassen): speichern + Vorschau neu starten
function mgSetApply(id,key,val){
getMgSettings(id)[key]=Number(val);
save();
restartMGTest();
}
// Anklickbares Feld umschalten (Steigerung an/aus)
function mgToggle(id,key){
const s=getMgSettings(id); s[key]=!s[key];
save();
restartMGTest();
}