Fix: gioco funzionante con server HTTP, menu interattivo, IA a 3 livelli

This commit is contained in:
truetype committed 2026-09-24 12:08:25 +02:00
1 parent d27d33f652
commit d1fd88b5ff
5 files changed
+352 -124

No files matched your search

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 452 KiB

+77 -124
View File
@@ -1,146 +1,115 @@
<!DOCTYPE html>
<html lang='it'><head><meta charset='UTF-8'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<html lang="it">
<head>
<meta charset="UTF-8">
<title>Windjammers Arcade</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{background:#1a1a2e;display:flex;justify-content:center;align-items:center;min-height:100vh;font-family:'Courier New',monospace;overflow:hidden}
#gc{position:relative;border:4px solid #e94560;border-radius:8px;box-shadow:0 0 40px rgba(233,69,96,.3)}
canvas{display:block;border-radius:4px}
#ui{position:absolute;top:10px;left:50%;transform:translateX(-50%);display:flex;gap:20px;color:#fff;font-size:18px;font-weight:bold;text-shadow:2px 2px 4px rgba(0,0,0,.8);pointer-events:none}
#ui{position:absolute;top:10px;left:50%;transform:translateX(-50%);display:flex;gap:20px;color:#fff;font-size:18px;font-weight:bold;pointer-events:none}
.sb{background:rgba(0,0,0,.6);padding:8px 16px;border-radius:4px;border:2px solid #e94560}
#msg{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff;font-size:32px;font-weight:bold;text-shadow:3px 3px 6px rgba(0,0,0,.9);pointer-events:none;text-align:center;opacity:0;transition:opacity .3s}
#msg{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff;font-size:32px;font-weight:bold;text-shadow:3px 3px 6px #000;pointer-events:none;text-align:center;opacity:0;transition:opacity .3s}
#ctr{position:absolute;bottom:10px;left:50%;transform:translateX(-50%);color:#fff;font-size:11px;text-align:center;opacity:.7;pointer-events:none;width:95%}
</style>
</head>
<body>
<div id="gc"><canvas id="c" width="900" height="500"></canvas>
<div id="gc">
<canvas id="c" width="900" height="500"></canvas>
<div id="ui"><div class="sb" id="s1">P1: 0</div><div class="sb" id="st">SET 1</div><div class="sb" id="s2">CPU: 0</div></div>
<div id="msg"></div>
<div id="ctr">P1: W/A/S/D</div></div>
<div id="ctr">P1: W/A/S/D + F G H</div>
</div>
<script>
(function(){
"use strict";
var C=document.getElementById("c"),X=C.getContext("2d"),W=C.width,H=C.height;
var K={sky:"#87CEEB",skyT:"#4A90D9",sand:"#F4D03F",sandD:"#D4AC0D",gr:"#7DCEA0",net:"#FFF",p1:"#E74C3C",p1d:"#C0392B",p2:"#3498DB",p2d:"#2980B9",disc:"#F39C12",glow:"#F1C40F",g5:"#E74C3C",g3:"#F39C12"};
var court={x:50,y:80,w:W-100,h:H-160,nx:W/2,nw:8,gd:40};
var DEF={p1:{up:"KeyW",down:"KeyS",left:"KeyA",right:"KeyD",thr:"KeyF",lob:"KeyG",sli:"KeyH"},p2:{up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight",thr:"KeyK",lob:"KeyL",sli:"Semicolon"}};
var CTRL={p1:{},p2:{}};
var LB={up:"SU",down:"GIU",left:"SINISTRA",right:"DESTRA",thr:"TIRO",lob:"LOB",sli:"SLIDE"};
var LB={up:"SU",down:"GIU",left:"SIN",right:"DES",thr:"TIRO",lob:"LOB",sli:"SLIDE"};
var KD={Space:"SPC",ArrowUp:"UP",ArrowDown:"DW",ArrowLeft:"LF",ArrowRight:"RT",Semicolon:";"};
var menu={screen:"main",mode:"ai",diff:"normal",sel:0};
var G={state:"menu",set:1,score:[0,0],sets:[0,0],time:3600,msg:"",mt:0,rally:0,serve:0,ai:null,cd:0,pp:0,pt:null};
var keys={},listening=null,p1,p2,disc,P=[];
function initCtrl(){
var s=localStorage.getItem("wj_c");
if(s){try{var p=JSON.parse(s);if(p.p1)Object.assign(CTRL.p1,p.p1);if(p.p2)Object.assign(CTRL.p2,p.p2);}catch(e){}}
for(var k in DEF.p1)if(!CTRL.p1[k])CTRL.p1[k]=DEF.p1[k];
for(var k in DEF.p2)if(!CTRL.p2[k])CTRL.p2[k]=DEF.p2[k];
}
function saveCtrl(){try{localStorage.setItem("wj_c",JSON.stringify(CTRL))}catch(e){}}
function resetCtrl(){Object.assign(CTRL.p1,JSON.parse(JSON.stringify(DEF.p1)));Object.assign(CTRL.p2,JSON.parse(JSON.stringify(DEF.p2)));saveCtrl();}
function kd(c){return KD[c]?KD[c]:c.replace("Key","").replace("Digit","").substring(0,6).toUpperCase()}
addEventListener("keydown",function(e){
keys[e.code]=true;
if(listening){e.preventDefault();listening.obj[listening.prop]=e.code;listening=null;saveCtrl();return}
if(["Space","ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].includes(e.code))e.preventDefault();
});
var menu={screen:"main",sel:0};
var G={state:"menu",set:1,score:[0,0],sets:[0,0],time:3600,rally:0,serve:0,cd:0,pp:0};
var keys={},p1,p2,disc,P=[];
function initCtrl(){for(var k in DEF.p1)if(!CTRL.p1[k])CTRL.p1[k]=DEF.p1[k];for(var k in DEF.p2)if(!CTRL.p2[k])CTRL.p2[k]=DEF.p2[k];}
function kd(c){return KD[c]||c.replace("Key","").replace("Digit","").substring(0,5).toUpperCase()}
addEventListener("keydown",function(e){keys[e.code]=true;if(["Space","ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].includes(e.code))e.preventDefault();});
addEventListener("keyup",function(e){keys[e.code]=false});
function Player(x,c,dc,s,n){
this.x=x;this.y=court.y+court.h/2;this.w=40;this.h=60;this.c=c;this.dc=dc;this.s=s;this.n=n;
this.vx=0;this.vy=0;this.sp=4;this.has=false;this.sl=false;this.st=0;this.sd=0;
this.ch=false;this.ct=0;this.af=0;this.fr=s===0;this.tc=0;this.cc=0;this.sup=false;
}
function Player(x,c,dc,s,n){this.x=x;this.y=court.y+court.h/2;this.c=c;this.dc=dc;this.s=s;this.n=n;this.vx=0;this.vy=0;this.sp=4;this.has=false;this.sl=false;this.st=0;this.af=0;this.fr=s===0;this.tc=0;this.cc=0;this.sup=false;}
Player.prototype.up=function(){
if(!this.sl){var l=Math.hypot(this.vx,this.vy);if(l>.1){this.x+=this.vx;this.y+=this.vy;if(this.vx!==0)this.fr=this.vx>0;}}
if(this.sl){this.st--;this.x+=this.vx;this.y+=this.vy;if(this.st<=0){this.sl=false;this.vx*=.3;this.vy*=.3;}}
if(!this.sl&&Math.hypot(this.vx,this.vy)>0.1){this.x+=this.vx;this.y+=this.vy;if(this.vx!==0)this.fr=this.vx>0;}
if(this.sl){this.st--;this.x+=this.vx;this.y+=this.vy;if(this.st<=0){this.sl=false;this.vx*=0.3;this.vy*=0.3;}}
this.x=Math.max(court.x+20,Math.min(court.x+court.w-20,this.x));
this.y=Math.max(court.y+20,Math.min(court.y+court.h-20,this.y));
if(this.s===0&&this.x>court.nx-court.nw/2-20)this.x=court.nx-court.nw/2-20;
if(this.s===1&&this.x<court.nx+court.nw/2+20)this.x=court.nx+court.nw/2+20;
if(this.tc>0)this.tc--;if(this.cc>0)this.cc--;
if(this.ct>0){this.ct--;if(this.ct<=0){this.ch=false;this.sup=true;}}
this.af+=.15;
if(this.tc>0)this.tc--;if(this.cc>0)this.cc--;this.af+=0.15;
};
Player.prototype.slide=function(d){if(this.sl)return;this.sl=true;this.sd=d;this.st=16;this.vx=d*8;this.vy=0;};
Player.prototype.slide=function(d){if(this.sl)return;this.sl=true;this.st=16;this.vx=d*8;this.vy=0;};
Player.prototype.draw=function(){
X.save();X.fillStyle="rgba(0,0,0,.3)";X.beginPath();X.ellipse(this.x,this.y+this.h/2+5,this.w/2,8,0,0,Math.PI*2);X.fill();
X.save();X.fillStyle="rgba(0,0,0,.3)";X.beginPath();X.ellipse(this.x,this.y+35,20,8,0,0,Math.PI*2);X.fill();
var b=Math.sin(this.af)*3;X.strokeStyle=this.dc;X.lineWidth=6;X.lineCap="round";X.beginPath();
if(this.sl){X.moveTo(this.x-10,this.y+10);X.lineTo(this.x-25,this.y+25);X.moveTo(this.x+10,this.y+10);X.lineTo(this.x+25,this.y+25);}
else{X.moveTo(this.x-8,this.y+15);X.lineTo(this.x-12,this.y+this.h/2+b);X.moveTo(this.x+8,this.y+15);X.lineTo(this.x+12,this.y+this.h/2-b);}
X.stroke();X.fillStyle=this.c;X.beginPath();X.ellipse(this.x,this.y+5,this.w/2-5,this.h/2-10,0,0,Math.PI*2);X.fill();
X.strokeStyle=this.dc;X.lineWidth=2;X.stroke();X.strokeStyle=this.c;X.lineWidth=5;X.beginPath();
if(this.has){var a=this.fr?0:Math.PI;X.moveTo(this.x,this.y);X.lineTo(this.x+Math.cos(a)*25,this.y+Math.sin(a)*10);X.moveTo(this.x,this.y);X.lineTo(this.x+Math.cos(a)*20,this.y-15);}
else{X.moveTo(this.x,this.y);X.lineTo(this.x-15,this.y+10+b);X.moveTo(this.x,this.y);X.lineTo(this.x+15,this.y+10-b);}
X.stroke();X.fillStyle="#FDBCB4";X.beginPath();X.arc(this.x,this.y-15,12,0,Math.PI*2);X.fill();
X.strokeStyle=this.dc;X.lineWidth=2;X.stroke();X.fillStyle=this.dc;X.beginPath();X.arc(this.x,this.y-20,10,Math.PI,0);X.fill();
X.moveTo(this.x-8,this.y+15);X.lineTo(this.x-12,this.y+35+b);X.moveTo(this.x+8,this.y+15);X.lineTo(this.x+12,this.y+35-b);X.stroke();
X.fillStyle=this.c;X.beginPath();X.ellipse(this.x,this.y+5,15,20,0,0,Math.PI*2);X.fill();X.strokeStyle=this.dc;X.lineWidth=2;X.stroke();
X.strokeStyle=this.c;X.lineWidth=5;X.beginPath();X.moveTo(this.x,this.y);X.lineTo(this.x-15,this.y+10+b);X.moveTo(this.x,this.y);X.lineTo(this.x+15,this.y+10-b);X.stroke();
X.fillStyle="#FDBCB4";X.beginPath();X.arc(this.x,this.y-15,12,0,Math.PI*2);X.fill();X.strokeStyle=this.dc;X.lineWidth=2;X.stroke();
X.fillStyle=this.dc;X.beginPath();X.arc(this.x,this.y-20,10,Math.PI,0);X.fill();
X.fillStyle="#000";X.beginPath();X.arc(this.x-4,this.y-15,2,0,Math.PI*2);X.arc(this.x+4,this.y-15,2,0,Math.PI*2);X.fill();
X.strokeStyle="#000";X.lineWidth=1.5;X.beginPath();X.arc(this.x,this.y-10,4,.1*Math.PI,.9*Math.PI);X.stroke();
if(this.ch){X.strokeStyle=K.glow;X.lineWidth=3;X.beginPath();X.arc(this.x,this.y,35+Math.sin(Date.now()/100)*5,0,Math.PI*2);X.stroke();}
if(this.sup){X.fillStyle=K.glow;X.beginPath();X.arc(this.x,this.y-35,5+Math.sin(Date.now()/50)*2,0,Math.PI*2);X.fill();}
X.restore();
};
function Disc(){this.x=W/2;this.y=H/2;this.vx=0;this.vy=0;this.r=15;this.rot=0;this.ow=null;this.ip=false;this.tr=[];this.lob=false;this.lh=0;this.sp=8;this.sup=false;}
Disc.prototype.throw=function(tx,ty,lob){var dx=tx-this.x,dy=ty-this.y,d=Math.hypot(dx,dy);this.vx=dx/d*this.sp;this.vy=dy/d*this.sp;this.lob=lob;this.ip=true;this.ow=null;if(lob){this.lh=0;this.vx*=.6;this.vy*=.6;}if(this.sup)this.vx*=1.5,this.vy*=1.5;};
Disc.prototype.throw=function(tx,ty,lob){var dx=tx-this.x,dy=ty-this.y,d=Math.hypot(dx,dy);this.vx=dx/d*this.sp;this.vy=dy/d*this.sp;this.lob=lob;this.ip=true;this.ow=null;if(lob){this.lh=0;this.vx*=0.6;this.vy*=0.6;}if(this.sup)this.vx*=1.5,this.vy*=1.5;};
Disc.prototype.up=function(){
if(!this.ip)return;
if(this.lob){this.lh+=.5;if(this.lh>100)this.lob=false;}
this.x+=this.vx;this.y+=this.vy;this.rot+=.3;
if(this.x-this.r<court.x){this.x=court.x+this.r;this.vx*=-.8;}
if(this.x+this.r>court.x+court.w){this.x=court.x+court.w-this.r;this.vx*=-.8;}
if(this.y-this.r<court.y){this.y=court.y+this.r;this.vy*=-.8;}
if(this.y+this.r>court.y+court.h){this.y=court.y+court.h-this.r;this.vy*=-.8;}
if(Math.abs(this.x-court.nx)<court.nw/2+this.r&&this.y>court.y+20&&this.y<court.y+court.h-20){this.vx*=-.7;this.x=court.nx+(this.x<court.nx?-1:1)*(court.nw/2+this.r);}
if(this.lob){this.lh+=0.5;if(this.lh>100)this.lob=false;}
this.x+=this.vx;this.y+=this.vy;this.rot+=0.3;
if(this.x-this.r<court.x){this.x=court.x+this.r;this.vx*=-0.8;}
if(this.x+this.r>court.x+court.w){this.x=court.x+court.w-this.r;this.vx*=-0.8;}
if(this.y-this.r<court.y){this.y=court.y+this.r;this.vy*=-0.8;}
if(this.y+this.r>court.y+court.h){this.y=court.y+court.h-this.r;this.vy*=-0.8;}
if(Math.abs(this.x-court.nx)<court.nw/2+this.r){this.vx*=-0.7;this.x=court.nx+(this.x<court.nx?-1:1)*(court.nw/2+this.r);}
this.tr.push({x:this.x,y:this.y});if(this.tr.length>12)this.tr.shift();
this.vx*=.995;this.vy*=.995;
this.vx*=0.995;this.vy*=0.995;
};
Disc.prototype.draw=function(){
X.save();
if(this.tr.length>1){X.beginPath();X.moveTo(this.tr[0].x,this.tr[0].y);for(var i=0;i<this.tr.length;i++)X.lineTo(this.tr[i].x,this.tr[i].y);X.strokeStyle="rgba(243,156,18,.4)";X.lineWidth=this.r;X.lineCap="round";X.stroke();}
if(this.tr.length>1){X.beginPath();X.moveTo(this.tr[0].x,this.tr[0].y);this.tr.forEach(function(t){X.lineTo(t.x,t.y)});X.strokeStyle="rgba(243,156,18,.4)";X.lineWidth=this.r;X.lineCap="round";X.stroke();}
var s=this.lob?1+this.lh/200:1,r=this.r*s;
if(this.sup){X.shadowColor=K.glow;X.shadowBlur=20;}
X.fillStyle=K.disc;X.beginPath();X.ellipse(this.x,this.y,r,r*.4,this.rot,0,Math.PI*2);X.fill();
X.strokeStyle="#D68910";X.lineWidth=2;X.beginPath();X.ellipse(this.x,this.y,r*.7,r*.25,this.rot,0,Math.PI*2);X.stroke();
X.fillStyle="rgba(255,255,255,.4)";X.beginPath();X.ellipse(this.x-r*.3,this.y-r*.15,r*.3,r*.15,this.rot,0,Math.PI*2);X.fill();
X.fillStyle=K.disc;X.beginPath();X.ellipse(this.x,this.y,r,r*0.4,this.rot,0,Math.PI*2);X.fill();
X.strokeStyle="#D68910";X.lineWidth=2;X.beginPath();X.ellipse(this.x,this.y,r*0.7,r*0.25,this.rot,0,Math.PI*2);X.stroke();
X.restore();
};
function Particle(x,y,c,t){this.x=x;this.y=y;this.vx=(Math.random()-.5)*8;this.vy=(Math.random()-.5)*8-2;this.lf=1;this.c=c;this.type=t||"dust";this.s=this.type==="conf"?8:4;this.rot=Math.random()*Math.PI*2;}
Particle.prototype.up=function(){this.x+=this.vx;this.y+=this.vy;this.vy+=.2;this.lf-=.02;this.rot+=.1;};
function Particle(x,y,c,t){this.x=x;this.y=y;this.vx=(Math.random()-0.5)*8;this.vy=(Math.random()-0.5)*8-2;this.lf=1;this.c=c;this.type=t||"dust";this.s=this.type==="conf"?8:4;this.rot=Math.random()*Math.PI*2;}
Particle.prototype.up=function(){this.x+=this.vx;this.y+=this.vy;this.vy+=0.2;this.lf-=0.02;this.rot+=0.1;};
Particle.prototype.draw=function(){X.save();X.globalAlpha=this.lf;X.fillStyle=this.c;if(this.type==="conf"){X.translate(this.x,this.y);X.rotate(this.rot);X.fillRect(-this.s/2,-this.s/4,this.s,this.s/2);}else{X.beginPath();X.arc(this.x,this.y,this.s*this.lf,0,Math.PI*2);X.fill();}X.restore();};
function AI(p,d){this.p=p;this.td=0;this.st=0;this.setDiff(d);}
AI.prototype.setDiff=function(d){var a={easy:[25,.5,.3,.2,40,.005],normal:[12,.75,.6,.55,20,.015],hard:[5,.95,.9,.85,10,.03]}[d];this.rf=a[0];this.acc=a[1];this.agg=a[2];this.pred=a[3];this.td=a[4];this.sf=a[5];};
AI.prototype.up=function(d,opp){this.p.cc=Math.max(0,this.p.cc-1);this.st=Math.max(0,this.st-1);var f=15+(1-this.pred)*20;this.px=d.x+d.vx*f;this.py=d.y+d.vy*f;if(this.p.has)this.atk(opp);else if(d.ip&&!d.ow)this.def(d);else this.idle();};
AI.prototype.atk=function(opp){if(this.st>0)return;if(Math.random()<this.agg||this.st<-this.td*2){var ty=this.tgt();ty+=(1-this.acc)*(Math.random()-.5)*100;ty=Math.max(court.y+30,Math.min(court.y+court.h-30,ty));var lob=Math.random()<.2*this.agg;var sup=this.p.sup&&Math.random()<this.agg;d.throw(court.x,ty,lob);this.p.has=false;this.p.tc=30;this.p.sup=false;this.st=this.td;}};
AI.prototype.tgt=function(){var r=Math.random();if(this.acc>.8&&r<.4)return court.y+court.h/2+(Math.random()-.5)*30;if(r<.6)return court.y+court.h/6+(Math.random()-.5)*20;return court.y+court.h*5/6+(Math.random()-.5)*20;};
AI.prototype.def=function(d){var tx=this.px,ty=this.py,dx=tx-this.p.x,dy=ty-this.p.y,dist=Math.hypot(dx,dy);if(dist>50){if(Math.random()<this.sf&&dist>100){this.p.slide(dx>0?1:-1);this.st=25;}else{var s=this.p.sp*(1+this.agg*.5);this.p.vx=dx/dist*s;this.p.vy=dy/dist*s;if(dx!==0)this.p.fr=dx>0;}}else{this.p.vx*=.5;this.p.vy*=.5;}};
AI.prototype.idle=function(){var cx=court.nx+150,cy=court.y+court.h/2,dx=cx-this.p.x,dy=cy-this.p.y,d=Math.hypot(dx,dy);if(d>30){var s=this.p.sp*.7;this.p.vx=dx/d*s;this.p.vy=dy/d*s;if(dx!==0)this.p.fr=dx>0;}else{this.p.vx*=.8;this.vy*=.8;}};
function initGame(){
p1=new Player(court.x+100,K.p1,K.p1d,0,"P1");p2=new Player(court.x+court.w-100,K.p2,K.p2d,1,"CPU");
disc=new Disc();P=[];G.score=[0,0];G.sets=[0,0];G.set=1;G.time=3600;G.rally=0;G.serve=0;G.pp=0;G.pt=null;G.cd=120;
if(G.aiMode)G.ai=new AI(p2,G.diff);serve();updateCtrUI();
}
function AI(p,d){this.p=p;this.st=0;this.setDiff(d);}
AI.prototype.setDiff=function(d){var a={easy:[0.3,40],normal:[0.6,20],hard:[0.9,10]}[d];this.agg=a[0];this.td=a[1];};
AI.prototype.up=function(d,opp){this.p.cc=Math.max(0,this.p.cc-1);this.st=Math.max(0,this.st-1);if(this.p.has)this.atk(opp);else if(d.ip&&!d.ow)this.def(d);else this.idle();};
AI.prototype.atk=function(){if(this.st>0)return;if(Math.random()<this.agg||this.st<-this.td*2){var ty=court.y+court.h/2+(Math.random()-0.5)*100;d.throw(court.x,ty,Math.random()<0.2);this.p.has=false;this.p.tc=30;this.st=this.td;}};
AI.prototype.def=function(d){var dx=d.x-this.p.x,dy=d.y-this.p.y,dist=Math.hypot(dx,dy);if(dist>50){var s=this.p.sp*1.5;this.p.vx=dx/dist*s;this.p.vy=dy/dist*s;if(dx!==0)this.p.fr=dx>0;}else{this.p.vx*=0.5;this.p.vy*=0.5;}};
AI.prototype.idle=function(){var cx=court.nx+150,cy=court.y+court.h/2,dx=cx-this.p.x,dy=cy-this.p.y,d=Math.hypot(dx,dy);if(d>30){var s=this.p.sp*0.7;this.p.vx=dx/d*s;this.p.vy=dy/d*s;if(dx!==0)this.p.fr=dx>0;}else{this.p.vx*=0.8;this.vy*=0.8;}};
function initGame(){initCtrl();p1=new Player(court.x+100,K.p1,K.p1d,0,"P1");p2=new Player(court.x+court.w-100,K.p2,K.p2d,1,"CPU");disc=new Disc();P=[];G.score=[0,0];G.sets=[0,0];G.set=1;G.time=3600;G.rally=0;G.serve=0;G.pp=0;G.cd=120;if(G.aiMode)G.ai=new AI(p2,G.diff);serve();updateUI();}
function serve(){var s=G.serve===0?p1:p2;s.has=true;disc.ow=s;disc.ip=false;disc.x=s.x+(s.fr?25:-25);disc.y=s.y;}
function updateUI(){document.getElementById("s1").textContent="P1: "+G.score[0];document.getElementById("s2").textContent=(G.aiMode?"CPU":"P2")+": "+G.score[1];document.getElementById("st").textContent="SET "+G.set;}
function updateCtrUI(){document.getElementById("ctr").textContent="P1: "+kd(CTRL.p1.up)+"/"+kd(CTRL.p1.left)+"/"+kd(CTRL.p1.down)+"/"+kd(CTRL.p1.right)+" + "+kd(CTRL.p1.thr)+"(tiro) "+kd(CTRL.p1.lob)+"(lob) "+kd(CTRL.p1.sli)+"(slide)";}
function showMsg(t){G.msg=t;G.mt=120;document.getElementById("msg").textContent=t;document.getElementById("msg").style.opacity=1;}
function scorePoint(pl,pts){G.score[pl]+=pts;G.rally=0;for(var i=0;i<30;i++)P.push(new Particle(pl===0?court.x+court.w:court.x,disc.y,"hsl("+Math.random()*360+",70%,60%)","conf"));updateUI();showMsg("+pts+" PUNTI!");G.pp=90;G.pt=pl;}
function scorePoint(pl,pts){G.score[pl]+=pts;G.rally=0;for(var i=0;i<30;i++)P.push(new Particle(pl===0?court.x+court.w:court.x,disc.y,"hsl("+Math.random()*360+",70%,60%)","conf"));updateUI();showMsg("+"+pts+" PUNTI!");G.pp=90;}
function checkGoal(){if(!disc.ip)return;if(disc.x-disc.r<court.x){var z=Math.floor((disc.y-court.y)/(court.h/3));scorePoint(1,z===1?5:3);}if(disc.x+disc.r>court.x+court.w){var z=Math.floor((disc.y-court.y)/(court.h/3));scorePoint(0,z===1?5:3);}}
function checkCatch(){if(!disc.ip)return;[p1,p2].forEach(function(p){if(p.cc>0||p.has)return;var d=Math.hypot(disc.x-p.x,disc.y-p.y);if(d<45){p.has=true;disc.ow=p;disc.ip=false;disc.vx=0;disc.vy=0;p.cc=30;G.rally++;for(var i=0;i<5;i++)P.push(new Particle(p.x,p.y+20,K.sand));}});}
function handleP1(){var c=CTRL.p1;if(keys[c.thr]&&p1.has&&p1.tc===0){disc.throw(court.x+court.w,court.y+Math.random()*court.h,false);p1.has=false;p1.tc=30;p1.sup=false;}if(keys[c.lob]&&p1.has&&p1.tc===0){disc.throw(court.x+court.w,court.y+Math.random()*court.h,true);p1.has=false;p1.tc=40;}if(keys[c.sli]&&!p1.has&&!p1.sl)p1.slide(p1.fr?1:-1);}
function handleP2(){if(G.aiMode)return;var c=CTRL.p2;if(keys[c.thr]&&p2.has&&p2.tc===0){disc.throw(court.x,court.y+Math.random()*court.h,false);p2.has=false;p2.tc=30;p2.sup=false;}if(keys[c.lob]&&p2.has&&p2.tc===0){disc.throw(court.x,court.y+Math.random()*court.h,true);p2.has=false;p2.tc=40;}if(keys[c.sli]&&!p2.has&&!p2.sl)p2.slide(p2.fr?1:-1);}
function checkSetEnd(){if(G.sets[0]>=2||G.sets[1]>=2){G.state="end";return;}G.score=[0,0];G.time=3600;updateUI();G.pp=60;}
function checkCatch(){if(!disc.ip)return;[p1,p2].forEach(function(p){if(p.cc>0||p.has)return;var d=Math.hypot(disc.x-p.x,disc.y-p.y);if(d<45){p.has=true;disc.ow=p;disc.ip=false;disc.vx=0;disc.vy=0;p.cc=30;G.rally++;}});}
function handleP1(){var c=CTRL.p1;if(keys[c.thr]&&p1.has&&p1.tc===0){disc.throw(court.x+court.w,court.y+Math.random()*court.h,false);p1.has=false;p1.tc=30;}if(keys[c.lob]&&p1.has&&p1.tc===0){disc.throw(court.x+court.w,court.y+Math.random()*court.h,true);p1.has=false;p1.tc=40;}if(keys[c.sli]&&!p1.has&&!p1.sl)p1.slide(p1.fr?1:-1);}
function handleP2(){if(G.aiMode)return;var c=CTRL.p2;if(keys[c.thr]&&p2.has&&p2.tc===0){disc.throw(court.x,court.y+Math.random()*court.h,false);p2.has=false;p2.tc=30;}if(keys[c.lob]&&p2.has&&p2.tc===0){disc.throw(court.x,court.y+Math.random()*court.h,true);p2.has=false;p2.tc=40;}if(keys[c.sli]&&!p2.has&&!p2.sl)p2.slide(p2.fr?1:-1);}
function drawBg(){
var s=X.createLinearGradient(0,0,0,court.y);s.addColorStop(0,K.skyT);s.addColorStop(1,K.sky);X.fillStyle=s;X.fillRect(0,0,W,court.y);
X.fillStyle="rgba(255,255,255,.8)";[[100,30,40],[300,50,30],[600,25,50],[800,45,35]].forEach(function(c){X.beginPath();X.arc(c[0],c[1],c[2],0,Math.PI*2);X.arc(c[0]+c[2]*.8,c[1]-c[2]*.2,c[2]*.7,0,Math.PI*2);X.arc(c[0]+c[2]*1.5,c[1],c[2]*.8,0,Math.PI*2);X.fill();});
X.fillStyle="#5DADE2";X.fillRect(0,court.y-20,W,20);X.fillStyle="#3498DB";X.fillRect(0,court.y-20,W,2);X.fillRect(0,court.y-12,W,2);X.fillRect(0,court.y-4,W,2);
X.fillStyle="rgba(255,255,255,.8)";
[[100,30,40],[300,50,30],[600,25,50],[800,45,35]].forEach(function(c){X.beginPath();X.arc(c[0],c[1],c[2],0,Math.PI*2);X.arc(c[0]+c[2]*0.8,c[1]-c[2]*0.2,c[2]*0.7,0,Math.PI*2);X.arc(c[0]+c[2]*1.5,c[1],c[2]*0.8,0,Math.PI*2);X.fill();});
X.fillStyle="#5DADE2";X.fillRect(0,court.y-20,W,20);
X.fillStyle="#3498DB";X.fillRect(0,court.y-20,W,2);X.fillRect(0,court.y-12,W,2);X.fillRect(0,court.y-4,W,2);
var sd=X.createLinearGradient(0,court.y+court.h,0,H);sd.addColorStop(0,K.sand);sd.addColorStop(1,K.sandD);X.fillStyle=sd;X.fillRect(0,court.y+court.h,W,H-court.y-court.h);
X.fillStyle=K.gr;X.fillRect(court.x,court.y,court.w,court.h);X.strokeStyle="#FFF";X.lineWidth=3;X.strokeRect(court.x,court.y,court.w,court.h);
X.setLineDash([10,10]);X.beginPath();X.moveTo(court.nx,court.y);X.lineTo(court.nx,court.y+court.h);X.stroke();X.setLineDash([]);
@@ -150,7 +119,7 @@ function drawBg(){
}
function drawGoal(x,side){
var gx=side===0?x-court.gd:x,zw=court.gd,zh=court.h/3;
X.fillStyle=K.g5;X.globalAlpha=.7;X.fillRect(gx,court.y+zh,zw,zh);
X.fillStyle=K.g5;X.globalAlpha=0.7;X.fillRect(gx,court.y+zh,zw,zh);
X.fillStyle=K.g3;X.fillRect(gx,court.y,zw,zh);X.fillRect(gx,court.y+zh*2,zw,zh);X.globalAlpha=1;
X.strokeStyle="#000";X.lineWidth=2;X.strokeRect(gx,court.y,zw,court.h);
X.beginPath();X.moveTo(gx,court.y+zh);X.lineTo(gx+zw,court.y+zh);X.moveTo(gx,court.y+zh*2);X.lineTo(gx+zw,court.y+zh*2);X.stroke();
@@ -174,33 +143,6 @@ function drawMenu(){
var opt=["FACILE Lento e impreciso","NORMARE Equilibrato","DIFFICILE Veloce, preciso, aggressivo"];
for(var i=0;i<opt.length;i++){X.fillStyle=i===menu.sel?"#F39C12":"#777";X.font=i===menu.sel?"bold 22px Courier New":"17px Courier New";X.fillText((i===menu.sel?" >> ":" ")+opt[i]+" "+(i===menu.sel?"<<":""),W/2,250+i*50);}
X.fillStyle="#444";X.font="13px Courier New";X.fillText("FRECCE = scegli INVIO = conferma ESC = indietro",W/2,440);
}else if(menu.screen==="settings"){
X.fillStyle="#9b59b6";X.font="bold 28px Courier New";X.fillText("IMPOSTAZIONI",W/2,40);
var whichP=menu.sel<7?1:2;
var ck=whichP===1?"p1":"p2";
var cp=CTRL[ck];
var k=["up","down","left","right","thr","lob","sli"];
if(whichP===1){
X.fillStyle="#e74c3c";X.font="bold 16px Courier New";X.fillText("<<< P1 (rosso) ||| P2 (blu) >>>",W/2,70);
}else{
X.fillStyle="#3498db";X.font="bold 16px Courier New";X.fillText("<<< P1 (rosso) ||| P2 (blu) >>>",W/2,70);
}
X.fillStyle="#fff";X.font="14px Courier New";X.fillText("Scorri fino a P2 per configurarne i tasti",W/2,95);
for(var i=0;i<k.length;i++){
var idx=whichP===1?i:i+7;
var y=125+i*32;
var isL=listening&&listening.obj===cp&&listening.prop===k[i];
var isSel=(whichP===1&&menu.sel===i)||(whichP===2&&menu.sel===i+7);
X.fillStyle=isL?"#F39C12":(isSel?"#fff":"#777");
X.font=isL?"bold 17px Courier New":(isSel?"bold 15px Courier New":"14px Courier New");
var val=isL?"... PREMI UN TASTO ...":kd(cp[k[i]]);
X.fillText((isL?" > ":isSel?" > ":" ")+LB[k[i]]+" : "+val+" "+(isL||isSel?"<":""),W/2,y);
}
X.fillStyle="#555";X.font="11px Courier New";
X.fillText("FRECCE SU/GIU = cambia azione FRECCE SIN/DEST = cambia giocatore",W/2,385);
X.fillText("INVIO/SPAZIO = cambia tasto (premi il nuovo tasto)",W/2,405);
X.fillText("R = reset predefiniti ESC = torna al menu",W/2,425);
if(listening){X.fillStyle="#F39C12";X.font="bold 18px Courier New";X.fillText(">> PREMI IL NUOVO TASTO ORA <<",W/2,475);}
}else if(menu.screen==="ready"){
X.fillStyle="#e94560";X.font="bold 44px Courier New";X.fillText("PRONTO!",W/2,115);
X.fillStyle="#fff";X.font="18px Courier New";X.fillText("Modalita: "+(G.aiMode?"VS CPU ("+G.diff.toUpperCase()+")":"2 GIOCATORI"),W/2,180);
@@ -208,14 +150,26 @@ function drawMenu(){
X.fillStyle="#aaa";X.font="13px Courier New";
X.fillText("P1: "+kd(CTRL.p1.thr)+"=tiro "+kd(CTRL.p1.lob)+"=lob "+kd(CTRL.p1.sli)+"=slide",W/2,340);
X.fillText((G.aiMode?"CPU controlla P2":"P2: "+kd(CTRL.p2.thr)+"=tiro "+kd(CTRL.p2.lob)+"=lob "+kd(CTRL.p2.sli)+"=slide"),W/2,370);
X.fillStyle="#666";X.font="11px Courier New";X.fillText("Vai in IMPOSTAZIONI per cambiare tasti",W/2,420);
}else if(menu.screen==="settings"){
X.fillStyle="#9b59b6";X.font="bold 28px Courier New";X.fillText("IMPOSTAZIONI",W/2,40);
X.fillStyle="#bbb";X.font="16px Courier New";X.fillText("Configura tasti Giocatore 1 (P1)",W/2,85);
var k=["up","down","left","right","thr","lob","sli"];
for(var i=0;i<k.length;i++){
var y=120+i*32;
X.fillStyle=i===menu.sel?"#fff":"#777";
X.font=i===menu.sel?"bold 16px Courier New":"15px Courier New";
X.fillText((i===menu.sel?" > ":" ")+LB[k[i]]+" : "+kd(CTRL.p1[k[i]])+" "+(i===menu.sel?"<":""),W/2,y);
}
X.fillStyle="#555";X.font="11px Courier New";
X.fillText("FRECCE SU/GIU = seleziona azione INVIO/SPAZIO = cambia tasto",W/2,385);
X.fillText("Premi INVIO su un'azione, poi premi il NUOVO tasto da assegnare",W/2,410);
X.fillText("ESC = torna al menu",W/2,435);
}
}
function handleMenuInput(){
if(listening)return;
if(keys["ArrowUp"]){keys["ArrowUp"]=false;var mx=menu.screen==="main"?2:(menu.screen==="diff"?2:13);menu.sel=Math.max(0,menu.sel-1);}
if(keys["ArrowDown"]){keys["ArrowDown"]=false;var mx=menu.screen==="main"?2:(menu.screen==="diff"?2:13);menu.sel=Math.min(mx,menu.sel+1);}
if(keys["ArrowUp"]){keys["ArrowUp"]=false;var mx=menu.screen==="main"?2:(menu.screen==="diff"?2:6);menu.sel=Math.max(0,menu.sel-1);}
if(keys["ArrowDown"]){keys["ArrowDown"]=false;var mx=menu.screen==="main"?2:(menu.screen==="diff"?2:6);menu.sel=Math.min(mx,menu.sel+1);}
if(keys["Enter"]||keys["Space"]){
keys["Enter"]=false;keys["Space"]=false;
if(menu.screen==="main"){
@@ -223,10 +177,8 @@ function handleMenuInput(){
else if(menu.sel===1){G.aiMode=false;menu.screen="ready";G.state="ready";}
else{menu.screen="settings";menu.sel=0;}
}else if(menu.screen==="diff"){G.aiMode=true;G.diff=["easy","normal","hard"][menu.sel];menu.screen="ready";G.state="ready";}
else if(menu.screen==="settings"){var k=["up","down","left","right","thr","lob","sli"];if(menu.sel>=0&&menu.sel<=6){listening={obj:CTRL.p1,prop:k[menu.sel]};}else if(menu.sel>=7&&menu.sel<=13){listening={obj:CTRL.p2,prop:k[menu.sel-7]};}}
}
if(keys["Escape"]){keys["Escape"]=false;if(menu.screen==="diff"||menu.screen==="settings"){menu.screen="main";menu.sel=0;}}
if(keys["KeyR"]&&menu.screen==="settings"){keys["KeyR"]=false;resetCtrl();}
if((keys["Space"]||keys["Enter"])&&menu.screen==="ready"&&G.state==="ready"){G.state="countdown";G.cd=120;keys["Space"]=false;keys["Enter"]=false;}
}
@@ -246,7 +198,7 @@ function loop(){
drawMenu();
}else if(G.state==="playing"){
drawBg();
if(G.pp>0){G.pp--;if(G.pp<=0){if(G.pt!==null){checkSetEnd();G.pt=null;}}}
if(G.pp>0){G.pp--;}
if(G.pp<=0){
handleP1();handleP2();
if(G.aiMode)G.ai.up(disc,p1);
@@ -257,7 +209,7 @@ function loop(){
if(G.score[0]>G.score[1]){G.sets[0]++;showMsg("P1 VINCE IL SET!");}
else if(G.score[1]>G.score[0]){G.sets[1]++;showMsg("CPU VINCE IL SET!");}
else{G.sets[0]++;G.sets[1]++;showMsg("PAREGGIO!");}
G.set++;checkSetEnd();
G.set++;G.score=[0,0];G.time=3600;
}
}
p1.draw();p2.draw();
@@ -282,6 +234,7 @@ function loop(){
initCtrl();
loop();
})();
</script>
</body>
</html>
+41
View File
@@ -0,0 +1,41 @@
const http = require('http');
const fs = require('fs');
const path = require('path');
const PORT = 8090;
const ROOT = '/home/codex/giochino';
const MIME = {
'.html': 'text/html',
'.js': 'application/javascript',
'.css': 'text/css',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.svg': 'image/svg+xml',
'.json': 'application/json'
};
const server = http.createServer((req, res) => {
let filePath = path.join(ROOT, req.url === '/' ? 'index.html' : req.url);
const ext = path.extname(filePath);
const contentType = MIME[ext] || 'application/octet-stream';
fs.readFile(filePath, (err, data) => {
if (err) {
res.writeHead(404, {'Content-Type': 'text/plain'});
res.end('404 Not Found: ' + req.url);
return;
}
res.writeHead(200, {'Content-Type': contentType});
res.end(data);
});
});
server.listen(PORT, '0.0.0.0', () => {
console.log(`Server attivo su http://0.0.0.0:${PORT}/`);
console.log(`Cartella: ${ROOT}`);
});
server.on('error', (err) => {
console.error('Errore server:', err.message);
});
+20
View File
@@ -0,0 +1,20 @@
const http = require('http');
const fs = require('fs');
const path = require('path');
const PORT = 8091;
const ROOT = '/home/codex/giochino';
const MIME = { '.html': 'text/html', '.js': 'application/javascript', '.css': 'text/css', '.png': 'image/png' };
const server = http.createServer((req, res) => {
let filePath = path.join(ROOT, req.url === '/' ? 'index.html' : req.url);
const ext = path.extname(filePath);
fs.readFile(filePath, (err, data) => {
if (err) { res.writeHead(404); res.end('404'); return; }
res.writeHead(200, { 'Content-Type': MIME[ext] || 'text/plain' });
res.end(data);
});
});
server.listen(PORT, '0.0.0.0', () => console.log(`Server: http://0.0.0.0:${PORT}/`));
+214
View File
@@ -0,0 +1,214 @@
#!/usr/bin/env python3
"""
Debug & Validation per il gioco Windjammers
Verifica: sintassi JS, struttura HTML, funzioni critiche, errori comuni
"""
import re
import sys
import json
def extract_js(html_path):
"""Estrae il JavaScript dall'HTML"""
with open(html_path, 'r') as f:
html = f.read()
match = re.search(r'<script>(.*?)</script>', html, re.DOTALL)
if not match:
return None, "Nessun tag <script> trovato"
return match.group(1), None
def check_syntax(js):
"""Verifica la sintassi JavaScript con node"""
import subprocess
import tempfile
with tempfile.NamedTemporaryFile(mode='w', suffix='.js', delete=False) as f:
f.write(js)
tmp_path = f.name
try:
result = subprocess.run(
['node', '--check', tmp_path],
capture_output=True, text=True, timeout=10
)
if result.returncode != 0:
return False, result.stderr.strip()
return True, None
except Exception as e:
return False, str(e)
def check_functions(js):
"""Verifica che le funzioni critiche siano definite"""
required = [
'function Player',
'function Disc',
'function Particle',
'function AI',
'function initGame',
'function serve',
'function drawBg',
'function drawGoal',
'function drawMenu',
'function drawHUD',
'function handleMenuInput',
'function loop',
'function scorePoint',
'function checkGoal',
'function checkCatch',
'function handleP1',
'function handleP2'
]
missing = []
for func in required:
if func not in js:
missing.append(func)
return missing
def check_common_errors(js):
"""Cerca errori comuni nel codice"""
errors = []
# Verifica stringhe con + non escaped
# Cerca pattern tipo: "testo +variabile+ altro" (errore comune nel template)
bad_strings = re.findall(r'"[^"]*\+[a-zA-Z_]+\+[^"]*"', js)
for s in bad_strings:
# Salta gli URL che hanno + nel percorso (non è un errore)
if not any(x in s for x in ['http', '://', 'Math.random']):
errors.append(f"Stringa sospetta (possibile + non escaped): {s}")
# Verifica bilanciatura parentesi
stack = []
for i, char in enumerate(js):
if char == '{':
stack.append(('}', i))
elif char == '(':
stack.append((')', i))
elif char == '[':
stack.append((']', i))
elif char in ')}]':
if not stack:
errors.append(f"Parentesi '{char}' in posizione {i} senza apertura")
elif stack[-1][0] != char:
errors.append(f"Parentesi '{char}' in posizione {i} non corrisponde a '{stack[-1][0]}'")
else:
stack.pop()
if stack:
for char, pos in stack:
errors.append(f"Parentesi aperta in posizione {pos} non chiusa")
# Verifica che loop() venga chiamato
if 'loop()' not in js and 'loop();' not in js:
errors.append("La funzione loop() non viene chiamata!")
# Verifica che initCtrl venga chiamato
if 'initCtrl()' not in js:
errors.append("initCtrl() non viene chiamato!")
return errors
def check_canvas_draw(js):
"""Verifica che le funzioni di disegno usino correttamente il canvas"""
issues = []
# Verifica che drawMenu usi fillText per mostrare testo
if 'fillText' not in js:
issues.append("Nessun fillText trovato - il testo non verrà mostrato!")
# Cerca errori comuni nei colori
color_pattern = r'style\s*=\s*"#[0-9A-Fa-f]{8}"' # 8 digit hex (invalido)
bad_colors = re.findall(color_pattern, js)
if bad_colors:
issues.append(f"Colori hex invalidi trovati: {bad_colors}")
return issues
def check_game_state_transitions(js):
"""Verifica le transizioni di stato del gioco"""
states = ['menu', 'ready', 'countdown', 'playing', 'end']
found_states = []
for state in states:
if f'"{state}"' in js or f"'{state}'" in js:
found_states.append(state)
missing = set(states) - set(found_states)
return missing
def run_validation(html_path):
"""Esegue tutte le validazioni e stampa il report"""
print("=" * 60)
print("🔍 VALIDAZIONE GIOCO WINDJAMMERS")
print("=" * 60)
# 1. Estrazione JS
print("\n📋 1. Estrazione JavaScript...")
js, err = extract_js(html_path)
if err:
print(f" ❌ ERRORE: {err}")
return False
print(f" ✅ JS estratto ({len(js)} caratteri)")
# 2. Sintassi
print("\n📋 2. Verifica sintassi...")
ok, err = check_syntax(js)
if not ok:
print(f" ❌ ERRORE DI SINTASSI:")
print(f" {err}")
return False
print(" ✅ Sintassi corretta")
# 3. Funzioni critiche
print("\n📋 3. Verifica funzioni critiche...")
missing = check_functions(js)
if missing:
print(f" ❌ FUNZIONI MANCANTI:")
for f in missing:
print(f" - {f}")
return False
print(f" ✅ Tutte le 17 funzioni critiche presenti")
# 4. Errori comuni
print("\n📋 4. Ricerca errori comuni...")
errors = check_common_errors(js)
if errors:
print(f" ⚠️ PROBLEMI TROVATI:")
for e in errors:
print(f" - {e}")
return False
print(" ✅ Nessun errore comune trovato")
# 5. Canvas
print("\n📋 5. Verifica disegno canvas...")
issues = check_canvas_draw(js)
if issues:
print(f" ⚠️ PROBLEMI CANVAS:")
for i in issues:
print(f" - {i}")
else:
print(" ✅ Funzioni di disegno presenti")
# 6. Stati del gioco
print("\n📋 6. Verifica stati del gioco...")
missing_states = check_game_state_transitions(js)
if missing_states:
print(f" ⚠️ STATI MANCANTI: {missing_states}")
else:
print(" ✅ Tutti gli stati del gioco presenti")
# 7. Riepilogo
print("\n" + "=" * 60)
print("✅ VALIDAZIONE COMPLETATA - Il gioco dovrebbe funzionare!")
print("=" * 60)
return True
if __name__ == '__main__':
if len(sys.argv) > 1:
path = sys.argv[1]
else:
path = '/home/codex/giochino/index.html'
success = run_validation(path)
sys.exit(0 if success else 1)