-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathindex.js
More file actions
1 lines (1 loc) · 12.7 KB
/
index.js
File metadata and controls
1 lines (1 loc) · 12.7 KB
1
export function startGame(g={}){const fe=/Chrome/.test(navigator.userAgent)&&/Google Inc/.test(navigator.vendor),l=g.width||640,r=g.height||640,me="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAEACAYAAAADRnAGAAACGUlEQVR42u3aSQ7CMBAEQIsn8P+/hiviAAK8zFIt5QbELiTHmfEYE3L9mZE9AAAAqAVwBQ8AAAD6THY5CgAAAKbfbPX3AQAAYBEEAADAuZrC6UUyfMEEAIBiAN8OePXnAQAAsLcmmKFPAQAAgHMbm+gbr3Sdo/LtcAAAANR6GywPAgBAM4D2JXAAABoBzBjA7AmlOx8AAEAzAOcDAADovTc4vQim6wUCABAYQG8QAADd4dPd2fRVYQAAANQG0B4HAABAawDnAwAA6AXgfAAAALpA2uMAAABwPgAAgPoAM9Ci/R4AAAD2dmqcEQIAIC/AiQGuAAYAAECcRS/a/cJXkUf2AAAAoBaA3iAAALrD+gIAAADY9baX/nwAAADNADwFAADo9YK0e5FMX/UFACA5QPSNEAAAAHKtCekmDAAAAADvBljtfgAAAGgMMGOrunvCy2uCAAAACFU6BwAAwF6AGQPa/XsAAADYB+B8AAAAtU+ItD4OAwAAAFVhAACaA0T7B44/BQAAANALwGMQAAAAADYO8If2+P31AgAAQN0SWbhFDwCAZlXgaO1xAAAA1FngnA8AACAeQPSNEAAAAM4CnC64AAAA4GzN4N9NSfgKEAAAAACszO26X8/X6BYAAAD0Anid8KcLAAAAAAAAAJBnwNEvAAAA9Jns1ygAAAAAAAAAAAAAAAAAAABAQ4COCENERERERERERBrnAa1sJuUVr3rsAAAAAElFTkSuQmCC",F=37,T=39,de=32,He=500,U={x:0,y:204,w:62,h:32},be=[{x:0,y:0,w:51,h:34},{x:0,y:102,w:51,h:34}],pe=[{x:0,y:137,w:50,h:33},{x:0,y:170,w:50,h:34}],ye=[{x:0,y:68,w:50,h:32},{x:0,y:34,w:50,h:32}],N=40,ge=11*N;function we(i,t){return Math.random()*(t-i)+i}function W(i,t,e){return Math.min(Math.max(i,t),e)}function L(i,t,e){return i<=e&&i>=t}function C(i,t){const e=L(i.x,t.x,t.x+t.w)||L(t.x,i.x,i.x+i.w),s=L(i.y,t.y,t.y+t.h)||L(t.y,i.y,i.y+i.h);return e&&s}class J{x;y;constructor(t,e){this.x=typeof t>"u"?0:t,this.y=typeof e>"u"?0:e}set(t,e){this.x=t,this.y=e}}class xe{x;y;w;h;constructor(t,e,s,n){this.x=typeof t>"u"?0:t,this.y=typeof e>"u"?0:e,this.w=typeof s>"u"?0:s,this.h=typeof n>"u"?0:n}set(t,e,s,n){this.x=t,this.y=e,this.w=s,this.h=n}}let b,o,I,B,Q,m=[],Y=[],j=0,a,c,A=[],w,O=!1,R=-1,H=0,D=0,S=1,x=!1,d=!1,p="";class q{img;position;scale;bounds;doLogic;constructor(t,e,s){this.img=t,this.position=new J(e,s),this.scale=new J(1,1),this.bounds=new xe(e,s,this.img.width,this.img.height),this.doLogic=!0}update(t){}_updateBounds(){this.bounds.set(this.position.x,this.position.y,~~(.5+this.img.width*this.scale.x),~~(.5+this.img.height*this.scale.y))}_drawImage(){o.drawImage(this.img,this.position.x,this.position.y)}draw(t){this._updateBounds(),this._drawImage()}}class G extends q{clipRect;constructor(t,e,s,n){super(t,s,n),this.clipRect=e,this.bounds.set(s,n,this.clipRect.w,this.clipRect.h)}update(t){}_updateBounds(){const t=~~(.5+this.clipRect.w*this.scale.x),e=~~(.5+this.clipRect.h*this.scale.y);this.bounds.set(this.position.x-t/2,this.position.y-e/2,t,e)}_drawImage(){o.save(),o.transform(this.scale.x,0,0,this.scale.y,this.position.x,this.position.y),o.drawImage(this.img,this.clipRect.x,this.clipRect.y,this.clipRect.w,this.clipRect.h,~~(.5+-this.clipRect.w*.5),~~(.5+-this.clipRect.h*.5),this.clipRect.w,this.clipRect.h),o.restore()}draw(t){super.draw(t)}}class ve extends G{lives;xVel;bullets;bulletDelayAccumulator;score;constructor(){super(I,U,l/2,r-70),this.scale.set(.85,.85),this.lives=3,this.xVel=0,this.bullets=[],this.bulletDelayAccumulator=0,this.score=0}reset(){this.lives=3,this.score=0,this.position.set(l/2,r-70)}shoot(){const t=new X(this.position.x,this.position.y-this.bounds.h/2,1,1e3,B);this.bullets.push(t),v("shoot")}handleInput(){Z(F)?this.xVel=-175:Z(T)?this.xVel=175:this.xVel=0,$(de)&&this.bulletDelayAccumulator>.5&&(this.shoot(),this.bulletDelayAccumulator=0)}updateBullets(t){for(let e=this.bullets.length-1;e>=0;e--){let s=this.bullets[e];s.alive?s.update(t):(this.bullets.splice(e,1),s=void 0)}}update(t){this.bulletDelayAccumulator+=t,this.position.x+=this.xVel*t,this.position.x=W(this.position.x,this.bounds.w/2,l-this.bounds.w/2),this.updateBullets(t)}draw(t){super.draw(t);for(let e=0,s=this.bullets.length;e<s;e++){const n=this.bullets[e];n.alive&&n.draw(t)}}}class Ee extends G{lives;xVel;bullets;bulletDelayAccumulator;score;targetX;decisionTimer;difficulty;constructor(){super(I,U,l/2,70),this.scale.set(.85,-.85),this.lives=3,this.xVel=0,this.bullets=[],this.bulletDelayAccumulator=0,this.score=0,this.targetX=l/2,this.decisionTimer=0,this.difficulty=.7}reset(){this.lives=3,this.score=0,this.position.set(l/2,70),this.bullets=[]}shoot(){const t=new X(this.position.x,this.position.y+this.bounds.h/2,-1,800,Q);this.bullets.push(t),v("shoot")}makeDecision(t){if(this.decisionTimer+=t,this.decisionTimer<.1)return;this.decisionTimer=0;let e=null,s=1/0;for(const u of A)if(u.alive&&u.position.y>this.position.y){const M=Math.abs(u.position.x-this.position.x);M<s&&(s=M,e=u)}const n=Math.abs(a.position.x-this.position.x);if(Math.random()>.7||!e){const u=(Math.random()-.5)*(1-this.difficulty)*100;this.targetX=a.position.x+u}else if(e){const u=(Math.random()-.5)*(1-this.difficulty)*50;this.targetX=e.position.x+u}Math.abs(this.position.x-this.targetX)<30&&this.bulletDelayAccumulator>.6&&Math.random()>.3&&(this.shoot(),this.bulletDelayAccumulator=0)}updateBullets(t){for(let e=this.bullets.length-1;e>=0;e--){let s=this.bullets[e];s.alive?s.update(t):(this.bullets.splice(e,1),s=void 0)}}update(t){this.bulletDelayAccumulator+=t,this.makeDecision(t);const e=this.targetX-this.position.x;Math.abs(e)>5?this.xVel=e>0?150:-150:this.xVel=0,this.position.x+=this.xVel*t,this.position.x=W(this.position.x,this.bounds.w/2,l-this.bounds.w/2),this.updateBullets(t)}draw(t){o.save(),super.draw(t),o.restore();for(let e=0,s=this.bullets.length;e<s;e++){const n=this.bullets[e];n.alive&&n.draw(t)}}}class X extends q{direction;speed;alive;constructor(t,e,s,n,h){super(h,t,e),this.direction=s,this.speed=n,this.alive=!0}update(t){this.position.y-=this.speed*this.direction*t,(this.position.y<0||this.position.y>r)&&(this.alive=!1)}draw(t){super.draw(t)}}class Re extends G{clipRects;onFirstState;stepDelay;stepAccumulator;doShoot;bullet;alive;constructor(t,e,s){super(I,t[0],e,s),this.clipRects=t,this.scale.set(.5,.5),this.alive=!0,this.onFirstState=!0,this.stepDelay=1,this.stepAccumulator=0,this.doShoot=!1,this.bullet=void 0}toggleFrame(){this.onFirstState=!this.onFirstState,this.clipRect=this.onFirstState?this.clipRects[0]:this.clipRects[1]}shoot(){this.bullet=new X(this.position.x,this.position.y+this.bounds.w/2,-1,500,B)}update(t){this.stepAccumulator+=t,this.stepAccumulator>=this.stepDelay&&(this.position.x<this.bounds.w/2+20&&R<0&&(O=!0),R===1&&this.position.x>l-this.bounds.w/2-20&&(O=!0),this.position.y>r-100&&(d=!0,p="AI"),we(0,1e3)<=5*(this.stepDelay+1)&&(this.doShoot=!0),this.position.x+=10*R,this.toggleFrame(),this.stepAccumulator=0),this.position.y+=H,this.bullet&&this.bullet.alive?this.bullet.update(t):this.bullet=void 0}draw(t){super.draw(t),this.bullet!==void 0&&this.bullet.alive&&this.bullet.draw(t)}}class Ce{particlePool;particles;constructor(){this.particlePool=[],this.particles=[]}draw(){for(let t=this.particles.length-1;t>=0;t--){const e=this.particles[t];e.moves++,e.x+=e.xunits,e.y+=e.yunits+e.gravity*e.moves,e.life--,e.life<=0?this.particlePool.length<100?this.particlePool.push(this.particles.splice(t,1)):this.particles.splice(t,1):(o.globalAlpha=e.life/e.maxLife,o.fillStyle=e.color,o.fillRect(e.x,e.y,e.width,e.height),o.globalAlpha=1)}}createExplosion(t,e,s,n,h,E,u,M,ae){for(let re=0;re<n;re++){const Ye=Math.floor(Math.random()*360),ue=Math.floor(Math.random()*u/2)+u,_=Math.floor(Math.random()*ae)+ae/2,ce=Ye*Math.PI/180,he=Math.cos(ce)*ue,Ae=Math.sin(ce)*ue;if(this.particlePool.length>0){const f=this.particlePool.pop();f.x=t,f.y=e,f.xunits=he,f.yunits=Ae,f.life=_,f.color=s,f.width=h,f.height=E,f.gravity=M,f.moves=0,f.alpha=1,f.maxLife=_,this.particles.push(f)}else this.particles.push({x:t,y:e,xunits:he,yunits:Ae,life:_,color:s,width:h,height:E,gravity:M,moves:0,alpha:1,maxLife:_})}}}function Ie(){if(g.canvas)b=g.canvas;else{const i=g.selector||"#invaders",t=document.querySelector(i)||document.body;b=document.createElement("canvas"),t.appendChild(b)}b.width=l,b.height=r,o=b.getContext("2d"),z(!1),I=new Image,I.src=me,De(),window.addEventListener("resize",le),document.addEventListener("keydown",Ne),document.addEventListener("keyup",Qe)}function De(){const i=ee(2,8,e=>{e.fillStyle="white",e.fillRect(0,0,e.canvas.width,e.canvas.height)});B=new Image,B.src=i.toDataURL();const t=ee(2,8,e=>{e.fillStyle="#ff4444",e.fillRect(0,0,e.canvas.width,e.canvas.height)});Q=new Image,Q.src=t.toDataURL()}function z(i){o.imageSmoothingEnabled=i,o.mozImageSmoothingEnabled=i,o.oImageSmoothingEnabled=i,o.webkitImageSmoothingEnabled=i,o.msImageSmoothingEnabled=i}function k(){A=[],a=new ve,c=new Ee,w=new Ce,d=!1,p="",S=1,V(),ie()}function V(){D=0,R=-1;for(let i=0,t=5*11;i<t;i++){const e=i%11,s=Math.floor(i/11);let n=[];switch(s){case 0:case 1:n=be;break;case 2:case 3:n=pe;break;case 4:n=ye;break}A.push(new Re(n,l/2-ge/2+N/2+e*N,r/2-80+s*40)),D++}}function Ge(){A=[],V(),a.reset(),c.reset(),d=!1,p=""}function Se(){Ie(),m=[],Y=[],le()}function Z(i){return m[i]}function $(i){return!Y[i]&&m[i]}function Pe(i){O&&(O=!1,R=-R,H=15);for(let t=A.length-1;t>=0;t--){let e=A[t];if(!e.alive){A.splice(t,1),e=void 0,D--,D<1&&(S++,S>3?(d=!0,p=a.score>=c.score?"PLAYER":"AI"):V());return}e.stepDelay=(D*20-S*10)/1e3,e.stepDelay<=.05&&(e.stepDelay=.05),e.update(i),e.doShoot&&(e.doShoot=!1,e.shoot())}H=0}function Me(){const i=a.bullets;for(let e=0,s=i.length;e<s;e++){const n=i[e];for(let h=0,E=A.length;h<E;h++){const u=A[h];n.alive&&u.alive&&C(n.bounds,u.bounds)&&(u.alive=n.alive=!1,v("invaderkilled"),w.createExplosion(u.position.x,u.position.y,"white",70,5,5,3,.15,50),a.score+=25)}}const t=c.bullets;for(let e=0,s=t.length;e<s;e++){const n=t[e];for(let h=0,E=A.length;h<E;h++){const u=A[h];n.alive&&u.alive&&C(n.bounds,u.bounds)&&(u.alive=n.alive=!1,v("invaderkilled"),w.createExplosion(u.position.x,u.position.y,"#ff4444",70,5,5,3,.15,50),c.score+=25)}}}function Fe(){for(let i=0,t=A.length;i<t;i++){const e=A[i];if(e.bullet&&C(e.bullet.bounds,a.bounds))if(a.lives===0)d=!0,p="AI";else{v("explosion"),e.bullet.alive=!1,w.createExplosion(a.position.x,a.position.y,"green",100,8,8,6,.001,40),a.position.set(l/2,r-70),a.lives--;break}}for(let i=0,t=c.bullets.length;i<t;i++){const e=c.bullets[i];if(e.alive&&C(e.bounds,a.bounds))if(a.lives===0)d=!0,p="AI";else{v("explosion"),e.alive=!1,w.createExplosion(a.position.x,a.position.y,"green",100,8,8,6,.001,40),a.position.set(l/2,r-70),a.lives--;break}}for(let i=0,t=a.bullets.length;i<t;i++){const e=a.bullets[i];if(e.alive&&C(e.bounds,c.bounds))if(c.lives===0)d=!0,p="PLAYER";else{v("explosion"),e.alive=!1,w.createExplosion(c.position.x,c.position.y,"#ff4444",100,8,8,6,.001,40),c.position.set(l/2,70),c.lives--;break}}}function Te(){Me(),Fe()}function Le(i){d||(a.handleInput(),Y=m.slice(),a.update(i),c.update(i),Pe(i),Te())}function ee(i,t,e){const s=document.createElement("canvas");s.width=i,s.height=t;const n=s.getContext("2d");return e(n),s}function P(i,t,e,s,n){typeof s<"u"&&(o.fillStyle=s),typeof n<"u"&&(o.font=n+"px Play"),o.fillText(i,t,e)}function y(i,t,e,s,n){const h=o.measureText(i);P(i,t-h.width/2,e,s,n)}function te(i,t,e,s,n,h){~~(.5+Date.now()/s)%2&&y(i,t,e,n,h)}function ie(){o.fillStyle="#02ff12",o.fillRect(0,r-30,l,2),P("PLAYER: "+a.lives+" \u2665",10,r-7.5,"#02ff12",18),P("SCORE: "+a.score,180,r-7.5,"white",18),o.fillStyle="#ff4444",o.fillRect(0,28,l,2),P("AI: "+c.lives+" \u2665",10,20,"#ff4444",18),P("SCORE: "+c.score,120,20,"#ff4444",18),y("WAVE "+S+"/3",l/2,r-7.5,"yellow",18)}function Be(i){for(let t=0;t<A.length;t++)A[t].draw(i)}function se(i){a.draw(i),c.draw(i),Be(i),w.draw(),ie()}function Oe(){y(g.title||"Space Invaders",l/2,r/2.75-40,"#FFFFFF",36),y("2 PLAYER - VS AI",l/2,r/2.75,"#ffff00",28),y("\u2190 \u2192 to move, SPACE to shoot",l/2,r/2.75+40,"#888888",18),te("Press ENTER to play!",l/2,r/2+40,500,"#FFFFFF",36)}function _e(){y("GAME OVER",l/2,r/2-60,"#FFFFFF",48);const i=p==="PLAYER"?"#02ff12":"#ff4444";y(p+" WINS!",l/2,r/2,i,36),y("Player: "+a.score+" pts",l/2,r/2+50,"#02ff12",24),y("AI: "+c.score+" pts",l/2,r/2+80,"#ff4444",24),te("Press ENTER to play again!",l/2,r/2+140,500,"#FFFFFF",24)}function ne(){const i=window.performance.now();let t=i-j;t>100&&(t=100),$(13)&&(!x||d)&&(k(),x=!0),x&&!d&&Le(t/1e3),o.fillStyle="black",o.fillRect(0,0,l,r),x?d?(se(!1),_e()):se(!1):Oe(),j=i,requestAnimationFrame(ne)}function le(){const i=window.innerWidth,t=window.innerHeight,e=Math.min(i/l,t/r);fe?(b.width=l*e,b.height=r*e,z(!1),o.transform(e,0,0,e,0,0)):(b.style.width=l*e+"px",b.style.height=r*e+"px")}function Ne(i){i.preventDefault(),m[i.keyCode]=!0}function Qe(i){i.preventDefault(),m[i.keyCode]=!1}let oe;document.addEventListener("touchstart",i=>{oe={x:i.touches[0].clientX,y:i.touches[0].clientY},x&&!d?a.shoot():(k(),x=!0)}),document.addEventListener("touchmove",i=>{const e={x:i.touches[0].clientX,y:i.touches[0].clientY}.x-oe.x;e>0?(m[T]=!0,m[F]=!1):e<0&&(m[F]=!0,m[T]=!1)}),document.addEventListener("touchend",i=>{m[F]=!1,m[T]=!1});const K=document.createElement("link");K.rel="stylesheet",K.href="https://fonts.googleapis.com/css?family=Play:400,700",document.head.appendChild(K),Se(),ne(),g.autoPlay&&(k(),x=!0);async function v(i){}}