Files
2026-04-16 17:20:19 +02:00

140 lines
7.0 KiB
JavaScript

// ========== RENDERING ==========
// Extends Game.prototype — must be loaded after game.js
Object.assign(Game.prototype, {
_draw(){
const c=this.cx;
c.fillStyle=CO.bg;c.fillRect(0,0,CW,CH);
c.fillStyle=CO.hud;c.fillRect(0,0,CW,HUD_TOP);c.fillRect(0,CH-HUD_BOT,CW,HUD_BOT);
if(this.state==='start'){this._hud(c);return}
this._maze(c);this._dDots(c);this._dMed(c);this._dPatient(c);this._dPain(c);this._dPl(c);this._dFx(c);
if(this.challActive){
const pct=this.challTimer/(FPS*CHALL_DURATION),bw=CW-16,bx=8,by=HUD_TOP-5;
c.fillStyle='rgba(0,0,0,0.5)';c.fillRect(bx,by,bw,4);
c.fillStyle=pct>0.5?'#22c55e':pct>0.25?'#f59e0b':'#ef4444';
c.fillRect(bx,by,bw*pct,4);
}
this._hud(c);
},
_maze(c){
for(let r=0;r<ROWS;r++)for(let col=0;col<COLS;col++){
const t=MAP[r][col],x=col*TILE,y=r*TILE+HUD_TOP;
if(t===1){
c.fillStyle=CO.wall;c.fillRect(x,y,TILE,TILE);
c.strokeStyle=CO.we;c.lineWidth=1;
const w=(dr,dc)=>{const rr=r+dr,cc=col+dc;if(rr<0||rr>=ROWS||cc<0||cc>=COLS)return true;const v=MAP[rr][cc];return v===1||v===3};
if(!w(-1,0)){c.beginPath();c.moveTo(x,y+1.5);c.lineTo(x+TILE,y+1.5);c.stroke()}
if(!w(1,0)){c.beginPath();c.moveTo(x,y+TILE-1.5);c.lineTo(x+TILE,y+TILE-1.5);c.stroke()}
if(!w(0,-1)){c.beginPath();c.moveTo(x+1.5,y);c.lineTo(x+1.5,y+TILE);c.stroke()}
if(!w(0,1)){c.beginPath();c.moveTo(x+TILE-1.5,y);c.lineTo(x+TILE-1.5,y+TILE);c.stroke()}
}
else if(t===3){c.fillStyle=CO.gW;c.fillRect(x,y,TILE,TILE)}
else if(t===4){c.fillStyle=CO.gD;c.fillRect(x,y+TILE*.35,TILE,TILE*.3)}
}
},
_dPatient(c){
if(!this.patient)return;
const x=this.patient.c*TILE+TILE/2,y=this.patient.r*TILE+HUD_TOP+TILE/2;
c.save();c.translate(x,y);
// pulsing glow
c.globalAlpha=0.25+0.2*Math.abs(Math.sin(this.fr*0.08));
c.fillStyle='#EC4899';c.beginPath();c.arc(0,0,10,0,Math.PI*2);c.fill();
c.globalAlpha=1;
const sc=0.9+0.08*Math.sin(this.fr*0.1);c.scale(sc,sc);
// pain aura
c.strokeStyle='#EF4444';c.lineWidth=0.8;
for(let i=0;i<6;i++){const a=i*Math.PI/3;c.beginPath();c.moveTo(Math.cos(a)*5,Math.sin(a)*5);c.lineTo(Math.cos(a)*9,Math.sin(a)*9);c.stroke()}
// head
c.fillStyle='#FCD9B6';c.beginPath();c.arc(0,-4,3,0,Math.PI*2);c.fill();
// torso
c.fillStyle='#93C5FD';c.fillRect(-2,-1,5,6);
// legs
c.fillStyle='#FCD9B6';c.fillRect(-3,5,2,4);c.fillRect(1,5,2,4);
// arms raised
c.strokeStyle='#FCD9B6';c.lineWidth=1.5;
c.beginPath();c.moveTo(-2,1);c.lineTo(-8,-3);c.stroke();
c.beginPath();c.moveTo(3,1);c.lineTo(9,-3);c.stroke();
// sad eyebrows
c.strokeStyle='#555';c.lineWidth=0.8;
c.beginPath();c.moveTo(-2,-6);c.lineTo(-1,-5);c.stroke();
c.beginPath();c.moveTo(2,-6);c.lineTo(1,-5);c.stroke();
// eyes
c.fillStyle='#333';c.fillRect(-2,-5,1,1);c.fillRect(1,-5,1,1);
// frown
c.strokeStyle='#8B0000';c.lineWidth=0.8;
c.beginPath();c.arc(0,-2,1.5,0,Math.PI,true);c.stroke();
c.restore();
},
_dMed(c){
for(const m of this.meds){
if(m.eaten)continue;
const x=m.c*TILE+TILE/2,y=m.r*TILE+HUD_TOP+TILE/2;
const sc=1+0.06*Math.sin(m.pulse);
c.save();c.translate(x,y);c.scale(sc,sc);
const pw=14,ph=7,r=ph/2;
// left (red) half
c.fillStyle='#EF4444';
c.beginPath();c.arc(-pw/2+r,0,r,Math.PI/2,Math.PI*3/2);c.lineTo(0,-r);c.lineTo(0,r);c.closePath();c.fill();
// right (white) half
c.fillStyle='#FFF';
c.beginPath();c.arc(pw/2-r,0,r,-Math.PI/2,Math.PI/2);c.lineTo(0,r);c.lineTo(0,-r);c.closePath();c.fill();
// outline
c.strokeStyle='rgba(0,0,0,0.4)';c.lineWidth=0.5;
c.beginPath();c.arc(-pw/2+r,0,r,Math.PI/2,Math.PI*3/2);c.arc(pw/2-r,0,r,-Math.PI/2,Math.PI/2);c.closePath();c.stroke();
c.restore();
}
},
_dDots(c){c.fillStyle=CO.dot;for(const d of this.dots)if(!d.e)c.fillRect(d.c*TILE+TILE/2-2,d.r*TILE+HUD_TOP+TILE/2-2,4,4)},
_dPain(c){
for(const p of this.pains){if(p.eaten)continue;const x=p.x+TILE/2,y=p.y+TILE/2,pu=1+.06*Math.sin(p.pulse),r=TILE*.44*pu;
c.save();c.translate(x,y);c.fillStyle=p.scared?CO.pSc:CO.pB;c.beginPath();c.arc(0,2,r,Math.PI,0,false);c.lineTo(r,4);c.lineTo(-r,4);c.closePath();c.fill();
if(!p.scared){c.strokeStyle=CO.pBo;c.lineWidth=1.5;[-r*.5,0,r*.5].forEach(bx=>{c.beginPath();c.moveTo(bx,-r*.15);c.lineTo(bx-2,-r*.55);c.lineTo(bx+1,-r*.45);c.lineTo(bx-1,-r*.9);c.stroke()})}
else{c.fillStyle='#FFF';c.fillRect(-3,-4,2,2);c.fillRect(2,-4,2,2);c.strokeStyle='#FFF';c.lineWidth=1;c.beginPath();for(let i=0;i<5;i++){const qx=-4+i*2;i===0?c.moveTo(qx,1):c.lineTo(qx,i%2===0?1:3)}c.stroke()}
c.restore()}
},
_dPl(c){
const p=this.pl,x=p.x+TILE/2,y=p.y+TILE/2,r=TILE*.44;
c.save();c.translate(x,y);const dir=p.moving?p.dir:p.lastFace;
c.rotate({right:0,down:Math.PI/2,left:Math.PI,up:-Math.PI/2}[dir]||0);
const mo=p.mouth*.45;c.fillStyle=CO.kid;c.beginPath();c.arc(0,0,r,mo,Math.PI*2-mo,false);c.lineTo(0,0);c.closePath();c.fill();
const ey=dir==='left'?r*.4:-r*.4;
c.fillStyle=CO.kE;c.beginPath();c.arc(-r*.1,ey,r*.18,0,Math.PI*2);c.fill();
c.fillStyle='#000';c.beginPath();c.arc(-r*.05,ey,r*.08,0,Math.PI*2);c.fill();
c.restore();
if(this.hasMed){
c.save();c.translate(x,y-r-6);
const pw=7,ph=4,pr=ph/2;
c.fillStyle='#EF4444';c.beginPath();c.arc(-pw/2+pr,0,pr,Math.PI/2,Math.PI*3/2);c.lineTo(0,-pr);c.lineTo(0,pr);c.closePath();c.fill();
c.fillStyle='#FFF';c.beginPath();c.arc(pw/2-pr,0,pr,-Math.PI/2,Math.PI/2);c.lineTo(0,pr);c.lineTo(0,-pr);c.closePath();c.fill();
c.restore();
}
},
_dFx(c){
for(const f of this.fx){const pg=1-f.t/f.mx,al=1-pg;const hr=parseInt(f.co.slice(1,3),16),hg=parseInt(f.co.slice(3,5),16),hb=parseInt(f.co.slice(5,7),16);
if(f.tp==='glow'){c.fillStyle=`rgba(${hr},${hg},${hb},${al*.4})`;c.beginPath();c.arc(f.x,f.y,12+pg*25,0,Math.PI*2);c.fill()}
else if(f.tp==='exp'){for(let i=0;i<8;i++){const a=i/8*Math.PI*2,d=pg*28;c.fillStyle=`rgba(255,${0|120+135*(1-pg)},0,${al})`;c.fillRect(f.x+Math.cos(a)*d-2,f.y+Math.sin(a)*d-2,4,4)}}
else if(f.tp==='burst'){c.strokeStyle=`rgba(${hr},${hg},${hb},${al})`;c.lineWidth=2;c.beginPath();c.arc(f.x,f.y,pg*18,0,Math.PI*2);c.stroke()}}
},
_hud(c){
c.font='10px "Press Start 2P",monospace';c.textBaseline='middle';const ty=HUD_TOP/2;
c.fillStyle=CO.hudT;c.textAlign='left';c.fillText('PUNKTE: '+(this.lsc+this.sc),8,ty);
c.textAlign='center';c.fillText('LEVEL '+this.lv,CW/2,ty);
const sec=0|this.lt/FPS;c.fillStyle=CO.hudT;c.textAlign='right';c.fillText('ZEIT: '+(0|sec/60)+':'+String(sec%60).padStart(2,'0'),CW-8,ty);
const by=CH-HUD_BOT/2;
for(let i=0;i<this.lives;i++){const lx=16+i*26;c.fillStyle=CO.kid;c.beginPath();c.arc(lx,by,8,.3,Math.PI*2-.3);c.lineTo(lx,by);c.closePath();c.fill();c.fillStyle='#FFF';c.beginPath();c.arc(lx-1,by-3,2.5,0,Math.PI*2);c.fill();c.fillStyle='#000';c.beginPath();c.arc(lx,by-3,1,0,Math.PI*2);c.fill()}
}
});