public/index.html

分割 3 / 6 · 元ファイル 410〜631行付近

原文の連続部分です。長い圧縮行は行の途中で分割する場合があります。全分割を順に連結するとファイル全文になります。

      sendLook();
      return;
    }
    if(d.y==='s') applySnap(d);
  };
  ws.onclose=function(e){
    NET.on=false;
    if(NET.ping){ clearInterval(NET.ping); NET.ping=0; }
    if(e&&e.code===4001) return;
    if(scr!=='play'){ NET.mode='off'; return; }
    NET.tries++;
    if(NET.tries<3) setTimeout(netOpen,700*NET.tries);
    else{ NET.mode='off'; world.sim='full'; netMsg='ひとりで続けます'; joinMsg=2.2; }
  };
}
function netStop(){
  NET.on=false; NET.mode='off';
  if(NET.ping){ clearInterval(NET.ping); NET.ping=0; }
  if(NET.ws){ try{ NET.ws.close(1000,'bye'); }catch(e){} NET.ws=null; }
}
function applySnap(s){
  var before=world.ps.length;
  var ev=world.apply(s,meId);
  for(var i=0;i<ev.length;i++) onEvent(ev[i]);
  if(world.ps.length>before && before>0){ seJoin(); netMsg='相方が来た'; joinMsg=2.2; }
  else if(world.ps.length<before){ netMsg='相方が抜けた'; joinMsg=2.2; }
  var p=myP();
  if(world.over || !p || !p.alive) endGame();
}
function onEvent(e){
  var z,G;
  if(e.e==='zkill'){
    z=world.zById(e.id); G=z?zGeo(z):{x:MX(e.x),hy:MY(1.42),shY:MY(1.2),bot:L.floorY};
    if(!NET.on){ burst(G.x,G.hy,16,'#9fbf83'); burst(G.x,G.hy,8,'#d8cf9e'); seKill(); }
    if(e.rock) seRock();
    floatUp(G.x,G.hy-14,'+'+e.n); pop=1; seScrap();
  }else if(e.e==='ckill'){
    if(!NET.on){ burst(MX(e.x),MY(e.y),12,'#3a3f46'); seCrow(); }
    floatUp(MX(e.x),MY(e.y)-12,'+'+e.n,'#9fd8ff'); pop=1; seScrap();
  }else if(e.e==='zknock'){
    if(!NET.on){ z=world.zById(e.id); if(z){ G=zGeo(z); dust(G.x-L.hr*0.4,(G.shY+G.bot)/2,5); } seKnock(); }
  }else if(e.e==='grab'){ seGrab(); if(e.p===meId) shake=1; }
  else if(e.e==='peck'){ if(e.p===meId) shake=0.7; seCrow(); }
  else if(e.e==='free'){ if(e.p===meId) floatUp(MX(myX()),MY(2.1),'はなれた','#9fd8ff'); }
  else if(e.e==='swap'){ seSwap(); }
  else if(e.e==='rock'){ if(e.p!==meId) seRock(); }
  else if(e.e==='down'){ if(e.p===meId) endGame(); }
  else if(e.e==='over'){ endGame(); }
  else if(e.e==='join'){ if(e.p!==meId&&NET.on){ seJoin(); netMsg='相方が来た'; joinMsg=2.2; } }
  else if(e.e==='left'){ if(e.p!==meId&&NET.on){ netMsg='相方が抜けた'; joinMsg=2.2; } }
}

/* ===== 指: 引いて離す(フリースローと同じ手触り。数字も同じ) ===== */
var V0=4.6, VR=4.6, EXP=1.15;
var aiming=false, sx=0, sy=0, ax=0, ay=0, pull=0, ang=52, arm=62, armT=0, cool=0;
var rockArm=false, shake=0;
function speedMS(){ return V0+VR*Math.pow(pull/L.maxPull,EXP); }
function aimFrom(px,py){
  var dx=sx-px, dy=sy-py;
  pull=Math.min(L.maxPull,Math.hypot(dx,dy));
  var a=Math.atan2(-dy,dx)*180/Math.PI;
  if(dx<=0 && Math.abs(a)>90) a=(a>0?180-a:-180-a);
  ang=Math.max(14,Math.min(84,a));
  ax=px; ay=py;
}
function rockLeft(){ var p=myP(); return p?Math.max(0,p.bT-world.t):WC.BOULDER_CD; }
function shoot(){
  var rock=rockArm&&rockLeft()<=0;
  if(rock){ if(NET.on) netSend({y:'rock'}); else world.useRock(meId); rockArm=false; seRock(); }
  else if(rockArm){ rockArm=false; }
  var rr=L.stoneR*(rock?3:1);
  var v=speedMS()*L.ppm*(rock?0.82:1), r=ang*Math.PI/180;
  var b=Mt.Bodies.circle(handX(),handY(),rr,Object.assign({label:'stone'},STONE));
  b.zgRock=rock?1:0;
  Mt.Body.setVelocity(b,{ x:Math.cos(r)*v/60, y:-Math.sin(r)*v/60 });
  Mt.Body.setAngularVelocity(b,rock?-0.07:-0.16);
  Mt.Composite.add(eng.world,b);
  S.push({ b:b, t:0, rest:0, cool:0, rock:rock, r:rr, px:b.position.x, py:b.position.y });
  throws++; armT=1; cool=rock?0.35:0.14; pull=0; seThrow();
}
function dropStone(s){
  try{ Mt.Composite.remove(eng.world,s.b); }catch(e){}
  var i=S.indexOf(s); if(i>=0) S.splice(i,1);
}
function canThrow(){
  var p=myP();
  return scr==='play' && cool<=0 && S.length<3 && !!p && p.alive;
}

/* ===== 押せる所(canvasの上のボタン) ===== */
var BTN=[];
function btn(id,x,y,w,h){ BTN.push({id:id,x:x,y:y,w:w,h:h}); }
function btnAt(px,py){
  for(var i=BTN.length-1;i>=0;i--){ var b=BTN[i];
    if(px>=b.x&&px<=b.x+b.w&&py>=b.y&&py<=b.y+b.h) return b.id; }
  return null;
}
function down(p){
  ac();
  var hit=btnAt(p.x,p.y);
  if(scr==='title'){
    if(hit==='start') startGame();
    else if(hit==='shop') openShop();
    else if(hit==='avatar') openAvatar();
    return;
  }
  if(scr==='result'){
    if(overT>0.5){ if(hit==='again') startGame(); else if(hit==='top') toTitle(); }
    return;
  }
  if(hit==='rock'){ if(rockLeft()<=0){ rockArm=!rockArm; seSwap(); } return; }
  if(hit==='swap'){ if(world.canSwap()){ if(NET.on) netSend({y:'swap'}); else world.swap(); } return; }
  if(!canThrow()) return;
  aiming=true; sx=p.x; sy=p.y; ax=p.x; ay=p.y; pull=0;
}
function move(p){ if(aiming) aimFrom(p.x,p.y); }
function up(){
  if(!aiming) return;
  aiming=false;
  if(pull<18){ pull=0; return; }
  if(canThrow()) shoot(); else pull=0;
}
(function(){
  var id=null;
  function pt(e){ var r=stage.getBoundingClientRect(); return { x:e.clientX-r.left, y:e.clientY-r.top }; }
  stage.addEventListener('pointerdown',function(e){
    if(id!==null) return; id=e.pointerId;
    try{ stage.setPointerCapture(id); }catch(err){}
    down(pt(e));
  });
  stage.addEventListener('pointermove',function(e){ if(e.pointerId===id) move(pt(e)); });
  function end(e){ if(e.pointerId!==id) return; up(); id=null; }
  stage.addEventListener('pointerup',end);
  stage.addEventListener('pointercancel',end);
})();

/* ===== 1コマ ===== */
function physics(dt){
  acc+=dt*1000; var n=0;
  while(acc>=STEP && n<4){
    for(var i=0;i<S.length;i++){ S[i].px=S[i].b.position.x; S[i].py=S[i].b.position.y; }
    Mt.Engine.update(eng,STEP);
    for(var j=S.length-1;j>=0;j--) hitTest(S[j]);
    acc-=STEP; n++;
  }
  if(acc>STEP*4) acc=0;
  for(var k=S.length-1;k>=0;k--){
    var s=S[k]; s.t+=dt; if(s.cool>0) s.cool-=dt;
    var p=s.b.position, v=s.b.velocity, sp=Math.hypot(v.x,v.y)*60;
    if(p.x<-40||p.x>W+80||p.y>H+90||s.t>7){ dropStone(s); continue; }
    if(sp<44 && p.y+s.r>L.floorY-3){ s.rest+=dt; if(s.rest>1.0) dropStone(s); }
    else s.rest=0;
  }
}
function stepP(dt){
  var i,q;
  for(i=P.length-1;i>=0;i--){
    q=P[i]; q.t+=dt;
    if(q.t>q.life){ P.splice(i,1); continue; }
    q.vy+=900*dt; q.x+=q.vx*dt; q.y+=q.vy*dt;
    if(q.y>L.floorY){ q.y=L.floorY; q.vy*=-0.3; q.vx*=0.6; }
  }
  for(i=FL.length-1;i>=0;i--){ FL[i].t+=dt; FL[i].y-=26*dt; if(FL[i].t>1.0) FL.splice(i,1); }
}
function step(dt){
  if(cool>0) cool-=dt;
  if(shake>0) shake-=dt*2.4;
  if(joinMsg>0) joinMsg-=dt;
  physics(dt);
  if(scr==='play'&&!FREEZE){
    var wasR=rockLeft();
    world.step(dt);
    if(!NET.on){ var ev=world.ev.slice(); world.ev.length=0; for(var i=0;i<ev.length;i++) onEvent(ev[i]); }
    else world.ev.length=0;
    if(wasR>0 && rockLeft()<=0) seRockRdy();
  }else if(scr==='result'){ overT+=dt; world.step(dt); world.ev.length=0; }
  stepP(dt);
  if(pop>0) pop-=dt*2.2;
  var want=(aiming?ang:62);
  if(armT>0){ armT-=dt*3.2; want=8; }
  arm+=(want-arm)*Math.min(1,dt*(armT>0?26:9));
}

/* ===== 絵(全部コードで描く) ===== */
function drawBG(){
  var sky=g2.createLinearGradient(0,0,0,L.floorY);
  sky.addColorStop(0,'#080c14'); sky.addColorStop(0.62,'#141d29'); sky.addColorStop(1,'#232b31');
  g2.fillStyle=sky; g2.fillRect(-20,-20,W+40,L.floorY+20);
  var mx=W*0.80, my=L.floorY*0.20, mr=Math.max(12,L.ppm*0.42);
  var gl=g2.createRadialGradient(mx,my,mr*0.5,mx,my,mr*4.6);
  gl.addColorStop(0,'rgba(226,226,200,.22)'); gl.addColorStop(1,'rgba(226,226,200,0)');
  g2.fillStyle=gl; g2.beginPath(); g2.arc(mx,my,mr*4.6,0,7); g2.fill();
  g2.fillStyle='#e8e4cc'; g2.beginPath(); g2.arc(mx,my,mr,0,7); g2.fill();
  g2.fillStyle='#141d29'; g2.beginPath(); g2.arc(mx+mr*0.42,my-mr*0.30,mr*0.88,0,7); g2.fill();
  var i;
  for(i=0;i<stars.length;i++){ var s=stars[i];
    g2.fillStyle='rgba(240,240,215,'+s.a+')'; g2.beginPath(); g2.arc(s.x,s.y,s.r,0,7); g2.fill(); }
  for(i=0;i<cloud.length;i++){ var cl=cloud[i];
    g2.fillStyle='rgba(190,200,215,'+cl.a+')';
    for(var ci=0;ci<3;ci++){ g2.beginPath();
      g2.ellipse(cl.x+(ci-1)*cl.w*0.26, cl.y+(ci===1?-cl.h*0.30:0),
        cl.w*(ci===1?0.30:0.24), cl.h*(ci===1?0.62:0.44),0,0,7); g2.fill(); } }
  for(var j=0;j<bldg.length;j++){ var b=bldg[j];
    g2.fillStyle='#0e1419'; g2.fillRect(b.x,L.floorY-b.h,b.w,b.h);
    g2.fillStyle='rgba(210,170,90,.18)';
    for(var k=0;k<3;k++) for(var m=0;m<2;m++){ if((j+k+m)%3) continue;
      g2.fillRect(b.x+6+m*(b.w*0.45),L.floorY-b.h+7+k*(b.h*0.28),b.w*0.20,b.h*0.13); } }
  g2.fillStyle='#181a14'; g2.fillRect(-20,L.floorY,W+40,H-L.floorY+20);
  g2.strokeStyle='rgba(220,210,170,.38)'; g2.lineWidth=2;
  g2.beginPath(); g2.moveTo(0,L.floorY); g2.lineTo(W,L.floorY); g2.stroke();
  g2.fillStyle='rgba(200,190,150,.10)';
  for(var n=0;n<26;n++){ var gx=(n*137)%W, gy=L.floorY+6+((n*61)%Math.max(8,(H-L.floorY)-10));
    g2.fillRect(gx,gy,3+((n*7)%9),1.5); }
}
function drawStoneAt(x,y,rot,r,rock){
  g2.save(); g2.translate(x,y); g2.rotate(rot);
  if(rock){
    g2.fillStyle='#6f6a60';
    g2.beginPath();
    for(var i=0;i<9;i++){ var a=i/9*Math.PI*2, rr=r*(0.84+((i*7)%4)*0.09);
      if(i===0) g2.moveTo(Math.cos(a)*rr,Math.sin(a)*rr); else g2.lineTo(Math.cos(a)*rr,Math.sin(a)*rr); }
    g2.closePath(); g2.fill();