let sel=0, data=[
{n:'TESS',i:'🛡️',c:'#22c55e'},{n:'FINN',i:'💣',c:'#a855f7'},{n:'LYS',i:'🎯',c:'#ef4444'},{n:'BRUX',i:'🐻',c:'#f97316'},{n:'SPIKE',i:'🌵',c:'#84cc16'},{n:'ROBO',i:'🤖',c:'#06b6d4'}
];
function pick(n){sel=n;document.getElementById('chars').innerText=data[n].i;document.getElementById('name').innerText=data[n].n;document.getElementById('selTxt').innerText=data[n].n;document.getElementById('chars').style.background=data[n].c;}
let player,bullets=[],enemies=[],gems=[],walls=[],move={x:0,y:0},isAiming=false,aimAng=0;
const canvas=document.getElementById('c'),ctx=canvas.getContext('2d');
function startBrawl(){
document.getElementById('lobby').style.display='none';document.getElementById('game').style.display='block';
canvas.width=innerWidth;canvas.height=innerHeight;
player={x:canvas.width/2,y:canvas.height/2,hp:150,max:150,speed:2.8,color:data[sel].c,ang:0,ulti:0,gems:0};
walls=[{x:80,y:80,w:30,h:160},{x:canvas.width-110,y:80,w:30,h:160},{x:80,y:canvas.height-220,w:30,h:160},{x:canvas.width-110,y:canvas.height-220,w:30,h:160}];
gems=[{x:canvas.width/2,y:canvas.height/2}];enemies=[{x:60,y:60,hp:60},{x:canvas.width-60,y:60,hp:60},{x:60,y:canvas.height-60,hp:60}];bullets=[];loop();
setupJoys();
}
function setupJoys(){
let mJ=document.getElementById('move'),mS=document.getElementById('moveStick'),aJ=document.getElementById('aim'),aS=document.getElementById('aimStick');
function make(j,s,cb,cbEnd){let act=false;function h(e){let r=j.getBoundingClientRect(),cx=r.left+55,cy=r.top+55,tx=(e.touches?e.touches[0].clientX:e.clientX)-cx,ty=(e.touches?e.touches[0].clientY:e.clientY)-cy,d=Math.hypot(tx,ty),max=30;if(d>max){let an=Math.atan2(ty,tx);cb(Math.cos(an),Math.sin(an),true,an);s.style.left=30+Math.cos(an)*max+'px';s.style.top=30+Math.sin(an)*max+'px';}else{cb(tx/max,ty/max,d>10,Math.atan2(ty,tx));s.style.left=30+tx+'px';s.style.top=30+ty+'px';}} j.addEventListener('touchstart',e=>{act=true;h(e)});j.addEventListener('touchmove',e=>{if(act){h(e);e.preventDefault()}},{passive:false});j.addEventListener('touchend',()=>{act=false;s.style.left='30px';s.style.top='30px';if(cbEnd)cbEnd();cb(0,0,false,0)});}
make(mJ,mS,(x,y)=>{move.x=x;move.y=y;if(x||y)player.ang=Math.atan2(y,x);});
make(aJ,aS,(x,y,aiming,ang)=>{isAiming=aiming;if(aiming){aimAng=ang;player.ang=ang;}},()=>{if(isAiming)shoot();isAiming=false;});
}
function shoot(){if(!player)return;let a=player.ang;for(let i=-1;i<=1;i++){let an=a+i*0.18;bullets.push({x:player.x,y:player.y,vx:Math.cos(an)*6,vy:Math.sin(an)*6,from:'p',life:40})} player.ulti=Math.min(100,player.ulti+12);}
document.getElementById('super').addEventListener('touchstart',e=>{e.preventDefault();if(player&&player.ulti>=100){for(let i=-2;i<=2;i++){let an=player.ang+i*0.2;bullets.push({x:player.x,y:player.y,vx:Math.cos(an)*7,vy:Math.sin(an)*7,from:'p',life:40})}player.ulti=0;}});
function loop(){
if(!player)return;player.x+=move.x*player.speed;player.y+=move.y*player.speed;
for(let i=bullets.length-1;i>=0;i--){let b=bullets[i];b.x+=b.vx;b.y+=b.vy;b.life--;for(let e of enemies){if(Math.hypot(b.x-e.x,b.y-e.y)<18){e.hp-=20;bullets.splice(i,1);break;}}if(b.life<=0)bullets.splice(i,1);}
for(let e of enemies){let dx=player.x-e.x,dy=player.y-e.y,d=Math.hypot(dx,dy);if(d>120){e.x+=dx/d*0.6;e.y+=dy/d*0.6;}}
for(let g of gems){if(Math.hypot(g.x-player.x,g.y-player.y)<18){player.gems++;g.x=Math.random()
span {
display: inline-block;
background:#a7e0f8;
padding:10px 8px;
margin-bottom:10px;
font-size:18px;
}
html.cafe - a realtime HTML editor and host
Edit the html in the top panel, see the result here.
Save your page and get a link to view it live, anywhere.