From 1925f573d7b0ecdc358ad69b8a89286eadd4d1ed Mon Sep 17 00:00:00 2001 From: Luke Date: Sat, 12 Sep 2020 23:40:20 -0400 Subject: [PATCH] Added restart button, minor tweaks, final zip --- README.md | 20 ++++++++- dist/404-orbiting-asteroids-13k.zip | Bin 0 -> 12293 bytes dist/game-window.js | 2 +- dist/index.html | 16 +++++-- package-lock.json | 4 +- package.json | 2 +- src/SpaceObject.js | 15 +++---- src/game.js | 63 +++++++++++++++++----------- 8 files changed, 82 insertions(+), 40 deletions(-) create mode 100644 dist/404-orbiting-asteroids-13k.zip diff --git a/README.md b/README.md index 52007ed..09a9d57 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,22 @@ # 404 Orbiting Asteroids for JS13k 2020 +Play the latest version: https://deathraygames.github.io/404-js13k-2020/dist/ -Sounds +## JS13k -I considered [jsfxr](https://github.com/mneubrand/jsfxr), but then found that [ZzFX micro](https://github.com/KilledByAPixel/ZzFX/blob/master/ZzFX.micro.js) is smaller and offered simple sound effects that I was looking for. I created the sounds by experimenting with [the ZzFX tool](https://killedbyapixel.github.io/ZzFX/), and put everything into a `sounds.js` file. +* [JS13k Rules](http://2020.js13kgames.com/#rules): Make a game with a package size less than 13k (13,312 bytes) in one month +* Theme: *"404"* +* Entry for this game: ...(TBD)... +* See all the entries for the competition at http://2020.js13kgames.com/ + +## Post Mortem + +I didn't have a lot of inspiration with the theme of "404", so I decided to use this challenge as an excuse to [learn WebGL](https://xem.github.io/articles/webgl-guide.html) and to improve [my physics library](https://github.com/rocket-boots/physics). I enjoyed working with basic spaceship flying as part of [Return to the Moon](https://github.com/deathraygames/lunar-lander-13k) in 2019, so settled on making a simple [Asteroids](https://en.wikipedia.org/wiki/Asteroids_(video_game)) "clone". Because there wasn't a lot of originality to the gameplay, I ended up using a very literal title: *"404 Orbiting Asteroids"*. + +I spent most of the month learning WebGL and working on a **starfield background**, which resulted in [webgl-starfield](https://github.com/rocket-boots/webgl-starfield) and a helper library [webglp](https://github.com/rocket-boots/webglp) to help smooth out some of the ugly WebGL js code. + +As a clone of classic the **gameplay** didn't require too much thought: *Fly around, shoot asteroids*. I knew I wanted some gravity to make flying more interesting, and since it [didn't make too much sense](https://twitter.com/deathraygames/status/1300966473280753664/photo/1) to have the asteroids with a strong force of gravity, I decided to add a big mass in the center. I originally wanted a sun and a few planets (like [Star Hopper Glitch Jump](https://github.com/deathraygames/star-hopper-glitch)), but knew it would be too complicated to keep the planets in orbit, so I just stuck with one mass: a sun. + +When it game time to work on the **controls** I decided to copy Reassembly, a game I really enjoy. Rotation of the ship follows the mouse, clicking fires the weapons. To make the game playable entirely by mouse I made the right-click fire the engines. Later on I also added some keyboard controls: "w" to fire engines and space bar to fire. + +After the game was playable I realized it desperately needed some **sounds** to give the experience more depth. I considered [jsfxr](https://github.com/mneubrand/jsfxr), but then found that [ZzFX micro](https://github.com/KilledByAPixel/ZzFX/blob/master/ZzFX.micro.js) is smaller and offered simple sound effects that I was looking for. I created the sounds by experimenting with [the ZzFX tool](https://killedbyapixel.github.io/ZzFX/), and put everything into a `sounds.js` file. diff --git a/dist/404-orbiting-asteroids-13k.zip b/dist/404-orbiting-asteroids-13k.zip new file mode 100644 index 0000000000000000000000000000000000000000..7f59afe3b82c3bf6ec2a682d6792c521555ca0b4 GIT binary patch literal 12293 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 literal 0 HcmV?d00001 diff --git a/dist/game-window.js b/dist/game-window.js index 5e2c876..76ada9a 100644 --- a/dist/game-window.js +++ b/dist/game-window.js @@ -1 +1 @@ -window.stars=function(t){var e={};function s(r){if(e[r])return e[r].exports;var i=e[r]={i:r,l:!1,exports:{}};return t[r].call(i.exports,i,i.exports,s),i.l=!0,i.exports}return s.m=t,s.c=e,s.d=function(t,e,r){s.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},s.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},s.t=function(t,e){if(1&e&&(t=s(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(s.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)s.d(r,i,function(e){return t[e]}.bind(null,i));return r},s.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return s.d(e,"a",e),e},s.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},s.p="",s(s.s=2)}([function(t,e){!function(t,e){for(var s in e)t[s]=e[s]}(e,function(t){var e={};function s(r){if(e[r])return e[r].exports;var i=e[r]={i:r,l:!1,exports:{}};return t[r].call(i.exports,i,i.exports,s),i.l=!0,i.exports}return s.m=t,s.c=e,s.d=function(t,e,r){s.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},s.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},s.t=function(t,e){if(1&e&&(t=s(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(s.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)s.d(r,i,function(e){return t[e]}.bind(null,i));return r},s.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return s.d(e,"a",e),e},s.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},s.p="",s(s.s=0)}([function(t,e,s){"use strict";s.r(e);class r{constructor(t=0,e=0){this.x=t,this.y=e}set({x:t,y:e}){return this.x=t||0,this.y=e||0,this}clear(){this.x=0,this.y=0}fix(){return!!this.check()||(this.x=Number(this.x),this.y=Number(this.y),!!this.check()||(this.x=0,this.y=0,!1))}add({x:t,y:e}){return this.x+=t||0,this.y+=e||0,this}subtract({x:t,y:e}){return this.x-=t||0,this.y-=e||0,this}multiply(t){return this.x*=t||1,this.y*=t||1,this}abs(){return this.x=Math.abs(this.x),this.y=Math.abs(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}reverse(){return this.multiply(-1)}normalize(){const t=this.getMagnitude();return 0===t?(this.x=0,this.y=0,this):(this.x=this.x/t,this.y=this.y/t,this)}setMagnitude(t){return this.normalize().multiply(t)}setTangent(){return this.set(this.y,this.x)}getDistance({x:t,y:e}){return Math.sqrt(Math.pow(this.x-t,2)+Math.pow(this.y-e,2))}getAbsoluteDistance(t={}){return Math.abs(this.getDistance(t))}getMagnitude(){return Math.sqrt(Math.pow(this.x,2)+Math.pow(this.y,2))}clone(){return new r(this.x,this.y)}getMultiply(t){return new r(this.x*t,this.y*t)}getDot({x:t,y:e}){return this.x*t+this.y*e}getUnitVector(t={}){const e=this.getAbsoluteDistance(t);if(0===e)return new r(0,0);const s=t.x-this.x,i=t.y-this.y;return new r(s/e,i/e)}getUnitVectorTangent(t={}){const e=this.getAbsoluteDistance(t);if(0===e)return new r(0,0);const s=(t.y-this.y)/e,i=(this.x-t.x)/e;return new r(s,i)}getPerpendicularVector(t=!1){return t?new r(-1*this.y,this.x):new r(this.y,-1*this.x)}getTangent(){return new r(this.y,this.x)}check(){return"number"==typeof this.x&&"number"==typeof this.y&&!isNaN(this.x)&&!isNaN(this.y)}isEqual({x:t,y:e}){return this.x===t&&this.y===e}isEqualInteger({x:t,y:e}){return Math.round(this.x)===Math.round(t)&&Math.round(this.y)===Math.round(e)}setByPolarCoords(t,e){return this.set({x:t*Math.cos(e),y:t*Math.sin(e)})}rotate(t,e){return this.subtract(e),this.setByPolarCoords(this.r,this.theta+t),this.add(e),this}getRadius(){return this.getDistance({x:0,y:0})}setRadius(t){return this.setByPolarCoords(t,this.getTheta()),this}getTheta(){return Math.atan2(this.y,this.x)}setTheta(t){this.setByPolarCoords(this.getRadius(),t)}getDegrees(){return this.getTheta()*(180/Math.PI)}equals(t={}){return this.isEqual(t)}copy(){return this.clone()}getCopy(){return this.clone()}getClone(){return this.clone()}}var i=r;e.default={Coords:i}}]).default)},,function(t,e,s){"use strict";s.r(e);class r{constructor(t){this.verts=t}static getRegularPolygonVerts(t=3,e=1,s=0){const r=[],i=2*Math.PI;for(let o=0;o[t[0]+s[0]/e,t[1]+s[1]/e],[0,0])}static getRadius([t,e]){return Math.sqrt(Math.pow(t,2)+Math.pow(e,2))}static getRadii(t){let e=1/0;const s=t.reduce((t,s)=>{const i=r.getRadius(s);return it?i:t},0);return{inner:e,outer:s}}}var i=r,o=s(0);function n(t,e){t.forEach(s=>{n.isPhysical(s)&&(s.collide&&s.collide(t),s.gravitate&&s.gravitate(e,t),s.move&&s.move(e))})}function a(){return new n.Coords}n.Coords=o.Coords,n.bigG=5,n.collidingVelocityMultiplier=.95,n.collidePushbackMultipler=.2,n.elasticity=.98,n.MIN_GRAVITY_RADIUS=1,n.isPhysical=t=>t.pos instanceof n.Coords&&t.vel instanceof n.Coords,n.getOrbitalVelocity=function(t,e,s=!1,r=n.bigG){const i=e.mass,o=t.pos.getDistance(e.pos),a=Math.sqrt(r*i/o);return t.pos.getUnitVector(e.pos).getPerpendicularVector(s).multiply(a)},n.canCollide=t=>({colliding:[],collideDetect(e){const s="number"==typeof t.innerRadius?t.innerRadius:0,r="number"==typeof e.innerRadius?e.innerRadius:0,i=t.pos.getDistance(e.pos)-s-r;return{isColliding:!(i>0),edgeToEdgeDistance:i}},collidePushback(e,s,r=n.collidePushbackMultipler){const i=s*r,o=t.mass>e.mass?t:e,a=o===t?e:t,c=a.pos.getUnitVector(o.pos).multiply(i);a.pos.add(c)},collideBounce(t,e=n.elasticity){var s=this;if(s.mass<=0||t.mass<=0)return!1;s.mass,s.vel.getMagnitude(),t.mass,t.vel.getMagnitude();var r=s.pos.getUnitVector(t.pos),i=2*(s.vel.getDot(r)-t.vel.getDot(r))/(s.mass+t.mass);return s.vel.add(r.getMultiply(-1*i*t.mass)),s.vel.multiply(e),t.vel.add(r.getMultiply(i*s.mass)),s.vel.multiply(e),!0},collideDamage(e){if(!t.damage)return;const s=t.vel.clone().add(e.vel).getMagnitude(),r=s<1?0:Math.ceil(Math.pow(s,1.4)/10);r&&t.damage(r,e)},collide(e){t.isColliding=!1,t.colliding.length=0,e.forEach(e=>{if(t===e||!n.isPhysical(e))return!1;const{isColliding:s,edgeToEdgeDistance:r}=t.collideDetect(e);return!!s&&(t.colliding.push(e),t.collidePushback(e,r),t.collideBounce(e),t.collideDamage(e),!0)}),t.isColliding=t.colliding.length>0,t.isColliding&&t.vel.multiply(n.collidingVelocityMultiplier)}}),n.canMove=t=>({lastPos:a(),pos:a(),force:a(),acc:a(),vel:a(),move(e){if(t.lastPos.set(t.pos),0!==t.mass){const e=new n.Coords(t.force.x/t.mass,t.force.y/t.mass);t.acc.add(e)}const s=t.acc.getMultiply(e);t.vel.add(s);const r=t.vel.getMultiply(e/2);t.pos.add(r),t.force.clear(),t.acc.clear()}}),n.canGravitate=(t,e=n.bigG)=>({gravitate(s,r){if(0===t.mass)return!1;const i=e*t.mass;r.forEach(e=>t.gravitateOne(e,i))},gravitateOne(e,s){if(e===t||0===e.mass||0===t.mass||t.isColliding||!t.gravitate||!n.isPhysical(e))return!1;const r=t.pos.getDistance(e.pos);if(r({rotation:0,rotVel:0,torque:0,momentOfInertia:0,inverseMomentOfInertia:0,rotate(e){t.rotation+=t.rotVel*e}}),n.physical=(t,{mass:e=1,bigG:s=n.bigG})=>(Object.assign(t,{mass:e},n.canCollide(t),n.canMove(t),n.canGravitate(t,s),n.canRotate(t)),t);var c=n;c.bigG=1e-6;var l=class extends i{constructor(t=[]){super([]);const e=()=>.2*Math.random()+.4,s=this;Object.assign(s,{baseVerts:t,baseColor:[e(),e(),e()],hitColor:[.7,0,0],boundingBox:[],hit:!1,verts:[],vc:null,r:0,innerRadius:0,children:[]}),c.physical(s,{mass:10}),s.alignToCenter(),s.calcRadii(),s.calcVerts(),s.calcMass(),s.Coords=c.Coords}alignToCenter(){const t=i.getCenter(this.baseVerts);this.baseVerts.forEach(e=>{[0,1].forEach(s=>e[s]=e[s]-t[s])})}calcRadii(){let t=1/0;this.r=this.baseVerts.reduce((e,s)=>{const r=s.r=i.getRadius(s);return re?r:e},0),this.innerRadius=t}calcMass(){this.mass=Math.PI*Math.pow((this.innerRadius+this.r)/2,2)*50}getVertColors(){return this.vc}getColor(){const t=this.baseColor;return[t[0]+(this.hit?.1:0),t[1]+(this.isColliding?.1:0),t[2]]}calcVerts(){let t=[];this.verts.length=0,this.baseVerts.forEach((e,s)=>{this.verts[s]=[e[0]+this.pos.x,e[1]+this.pos.y,0],t=t.concat(this.verts[s]).concat(this.getColor())}),this.vc=new Float32Array(t)}calcVertWithRotation(t,e,s){const r=Math.cos(this.rotation),i=Math.sin(this.rotation);return this.verts[s]=[r*e[0]-i*e[1]+this.pos.x,r*e[1]+i*e[0]+this.pos.y,0],t.concat(this.verts[s]).concat(this.getColor())}calcVertsWithRotation(){this.verts.length=0;let t=this.baseVerts.reduce((t,e,s)=>this.calcVertWithRotation(t,e,s),[]);this.vc=new Float32Array(t)}static rotate(t,e,s){let r=t[0]-s[0];r+=s[0]}setOrbitalVelocity(t){this.vel.set(c.getOrbitalVelocity(this,t))}};const h=[[.2,-.1,0],[.35,0,0],[.45,.1,0],[.4,.3,0],[.3,.4,0],[.2,.8,0],[.1,.4,0],[0,.3,0],[-.05,.1,0],[.05,0,0]];var u=class extends l{constructor(){super(h.map(t=>t.map(t=>1.5*t))),Object.assign(this,{shipScale:1.5,engaged:!1,facingRotationOffset:-Math.PI/2,thrustPowerUpMax:2,thrustPowerUpStart:.75,thrustPowerUp:.75,thrustPowerUpMultiplier:.5,thrustPowerDownMultiplier:2}),this.mass*=3,this.thrustMagnitude=100*this.mass,this.baseColor=[.6,1,.3]}setRotation(t){this.rotation=t+this.facingRotationOffset}getFacingUnitVector(){const t=this.rotation+this.facingRotationOffset,e=Math.cos(t),s=Math.sin(t);return new this.Coords(e,s)}ongoing(t){this.engaged?this.thrust(t):this.cooldownThrust(t)}engage(){this.engaged=!0,this.thrust(.02)}disengage(){this.engaged=!1}thrust(t){this.thrustPowerUp;this.thrustPowerUp+=t*this.thrustPowerUpMultiplier,this.thrustPowerUp=Math.min(this.thrustPowerUpMax,this.thrustPowerUp);const e=this.getFacingUnitVector().getMultiply(t*-this.thrustMagnitude*this.thrustPowerUp);this.force.add(e)}cooldownThrust(t){this.thrustPowerUp<=this.thrustPowerUpStart||(this.thrustPowerUp-=t*this.thrustPowerDownMultiplier,this.thrustPowerUp=Math.max(this.thrustPowerUpStart,this.thrustPowerUp))}fire(){return 22+2*Math.random()}};var d=class extends l{constructor(){const t=1.5+.5*Math.random()-.5*Math.random();super(l.getRegularPolygonVerts(3+Math.floor(7*Math.random()),t,.2*t))}};var g=class extends l{constructor(){super(l.getRegularPolygonVerts(40,40)),this.pos.set({x:0,y:0}),this.mass*=1e4,this.innerRadius*=.94}move(){}};let p=(t=1,e=.05,s=220,r=0,i=0,o=.1,n=0,a=1,c=0,l=0,h=0,u=0,d=0,g=0,p=0,v=0,M=0,b=1,w=0,x=0)=>{let P,R,C=2*Math.PI,V=c*=500*C/m**2,S=(0U?0:(Uu&&(s+=h,T+=h,D=0),!d||++_%d||(s=T,c=V,D=D||1);return(t=y.createBuffer(1,R,m)).getChannelData(0).set(O),(s=y.createBufferSource()).buffer=t,s.connect(y.destination),s.start(),s},f=.3,y=new(window.AudioContext||webkitAudioContext),m=44100;const v=[,,470,,,.13,4,1.78,-.3,,-50,.04,.02,.1,-.2,.4,,.51,.04,.01],M=[,,651,,.2,.88,4,1.22,.3,,,,,.6,,1,,.51,.01],b=[.6,,980,,.51,1.62,4,2.35,,,,,,.3,.7,.9,.13,.73,.06],w=[1.3,,117,.12,.27,1.21,4,2,.7,,,,,.8,,.9,.34,1.1,.04,.2],x=[,,452,,.08,.46,2,.73,2.4,,,,,,,,.04,.51];var P={gun(){p(...v)},explode(){p(...M)},thrust(){p(...b)},death(){p(...w)},jump(){p(...x)}};const R=new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]),C=(...t)=>console.log(...t);class V{constructor(t,e){Object.assign(this,{gl:t,p:e,i:0,aV:e.map(()=>({})),uV:e.map(()=>({}))})}use(t){return this.i=t,this.gl.useProgram(this.p[t]),this}v(t,e,s,r,i){const o=this,n=o[t][o.i][r]||o.gl[e](o.p[o.i],r);return o.gl[`${s}${i.length}f`](n,...i),o[t][this.i][r]=n}attr(t,...e){return this.v("aV","getAttribLocation","vertexAttrib",t,e)}unif(t,...e){return this.v("uV","getUniformLocation","uniform",t,e)}ua(t){t.forEach(t=>this.unif(...t))}buff(t,e,{size:s=2,type:r=this.gl.FLOAT,norm:i=!1,stride:o=0,offset:n=0}={}){const{gl:a,p:c}=this;a.bindBuffer(a.ARRAY_BUFFER,a.createBuffer()),a.bufferData(a.ARRAY_BUFFER,e,a.STATIC_DRAW);const l=e.BYTES_PER_ELEMENT,h=a.getAttribLocation(c[this.i],t);return a.vertexAttribPointer(h,s,r,i,o*l,n*l),a.enableVertexAttribArray(h),h}ba(t,e){e.forEach(e=>this.buff(e[0],t,e[1]))}clear(){this.gl.clearColor(0,0,0,1),this.gl.clear(this.gl.COLOR_BUFFER_BIT)}draw({uniforms:t=[],i:e=this.i,buffs:s=[],verts:r=R,vertSize:i=2,vertsToDraw:o,type:n=this.gl.TRIANGLES,clear:a=!0}){const c=this;return c.use(e),c.ua(t),c.ba(r,s),a&&c.clear(),void 0===o&&(o=r.length/i),c.gl.drawArrays(n,0,o),c}drawAll(t={}){this.p.forEach((e,s)=>this.draw(Object.assign({i:s,clear:!s},t)))}}const S={Glp:V,STV:R,STNPV:2,getRenderingContext:(t,e=!1)=>{const s=document.querySelector(t).getContext("webgl",{antialias:e});return s||alert("Unable to initialize WebGL. Your browser or machine may not support it."),s},loadText:t=>fetch(t).then(t=>t.text()),loadShaders:t=>Promise.all(t.map(t=>S.loadText(t))),compileShader:(t,e,s)=>{const r=t.createShader(e);return t.shaderSource(r,s),t.compileShader(r),r},fullscreen:(t,e=window)=>{t.canvas.width=e.innerWidth,t.canvas.height=e.innerHeight,S.setViewport(t)},setViewport:t=>{t.viewport(0,0,t.canvas.width,t.canvas.height)},compile:(t,e)=>{const s=t.createProgram(),r=[t.VERTEX_SHADER,t.FRAGMENT_SHADER],i=["vertex","fragment"];return e.map((e,o)=>{const n=S.compileShader(t,r[o],e);t.attachShader(s,n),C(i[o]+" shader:",t.getShaderInfoLog(n)||"OK")}),t.linkProgram(s),t.useProgram(s),C("program:",t.getProgramInfoLog(s)||"OK"),s},init:async(t,e,{fullscreen:s}={})=>{const r="string"==typeof t?S.getRenderingContext(t):t,i=e.map(t=>S.loadShaders(t).then(t=>S.compile(r,t))),o=await Promise.all(i);return s&&S.fullscreen(r),new V(r,o)}};var T=S;var O=class extends l{constructor(t,e,s=[1,.5,0],r=.2,i=8){super(l.getRegularPolygonVerts(i,r)),this.pos.set(t),this.vel.set(e),Object.assign(this,{mass:0,baseColor:s,baseR:r,maxR:10*r,r:r,explosionSpeed:6+3*Math.random()})}ongoing(t){this.r+=t*this.explosionSpeed,this.r>this.maxR&&(this.delete=!0),this.baseVerts=l.getRegularPolygonVerts(8,this.r),this.calcVerts()}};const A=()=>20*Math.random()*(Math.random()<.5?1:-1);var E=class extends l{constructor(t,e=2){const s=.75*t.r/e,r=Math.max(3,Math.round(t.verts.length*Math.random()));super(l.getRegularPolygonVerts(r,s,s)),this.baseColor=t.baseColor.map(t=>Math.max(0,t-.3)),this.pos.set(t.pos);const i={x:A(),y:A()};this.vel.set(t.vel).add(i)}};const U=[["v.glsl","stars-f.glsl"],["space-v.glsl","space-f.glsl"]];let D,_,I=20,j=404,L=!1,F=!1;const k=t=>document.getElementById(t),B=(t=1)=>Math.random()*t,G={},N=[],z=function(){const t=new g;return N.push(t),t}(),q=(function(t){for(let e=0;e<404;e++){const e=new d;st(e,t),e.damage=(s,r)=>{r===t&&st(e,t)},N.push(e)}}(z),function(t){const e=new u;return e.pos.set({x:120,y:0}),e.setOrbitalVelocity(t),e.damage=(e,s)=>{s===t&&$("sun")},N.push(e),e}(z)),W=()=>{const t=[["iResolution",D.gl.canvas.width,D.gl.canvas.height],["zoom",I],["viewerPosition",q.pos.x,q.pos.y,0],["iTime",0]];D.use(0).draw({uniforms:t,buffs:[["position"]]});const e=[["position",{size:3,stride:6}],["color",{size:3,stride:6,offset:3}]];D.use(1).draw({uniforms:t,buffs:e,verts:new Float32Array([]),vertSize:6,type:D.gl.TRIANGLE_FAN,clear:!1}),N.forEach(t=>{D.draw({buffs:e,verts:t.getVertColors(),vertSize:6,type:D.gl.TRIANGLE_FAN,clear:!1})})};function Y(t){if(G[t])return;G[t]=!0;const e=k("ach-"+t);e&&e.classList.add("unlocked"),Object.keys(G).length>=5&&k("intro").classList.add("closed")}function H(t,e){return t.pos.getDistance(z.pos)>e&&(st(t,z),!0)}const K=t=>{let e=0;const s=[];return N.forEach((r,i)=>{r.delete?s.push(i):(r.ongoing&&r.ongoing(t),r.rotate(t),r.calcVertsWithRotation(),!r.gravitate||r instanceof g||r.gravitate(t,[z]),r.move(t),r.collide(N),r instanceof d?(e++,H(r,250)):r instanceof u&&H(r,800)&&P.jump())}),((t=[])=>{for(let e=t.length-1;e>=0;e--){const s=t[e];N.splice(s,1)}})(s),{asteroidCount:e}};function X(t,e=8){t.decayTime=e,t.ongoing=e=>{t.decayTime-=e,t.decayTime<0&&(t.delete=!0)}}function $(t){F=!0,q.delete=!0,et(q),Q(q.pos,q.vel),P.death(),function(t="sun"){k("main").classList.remove("go"),F&&(k("intro").classList.add("closed"),k("dead").classList.remove("closed"),k(t).style.display="block")}(t)}const J=(t,e)=>{const s=new l([[0,.2,0],[-.1,-.1,0],[0,-.2,0],[.1,-.1,0]]);s.rotation=t.rotation;const r=t.getFacingUnitVector().multiply(-1);s.pos.set(t.pos).add(r.getMultiply(t.shipScale)),s.vel.set(t.vel).add(r.getMultiply(e)),s.mass*=.5,X(s,10),s.damage=(t,e)=>{var r;s.decayTime*=.5,e instanceof d?((r=e).delete=!0,et(r),Q(r.pos,r.vel),P.explode()):e instanceof u&&$("bullet")},s.gravitate=null,N.push(s)};function Q(t,e){const s=new O(t,e),r=new O(t,e,[1,1,0],.05,3);N.push(s),N.push(r)}function Z(){const t=.07+B(.05),e=l.getRegularPolygonVerts(3,t),s=new l(e);s.baseColor=[.5,.3,.5],s.rotation=B(2*Math.PI);const r=q.getFacingUnitVector();s.pos.set(q.pos).add(r.getMultiply(.5*q.shipScale)),s.vel.set(q.vel).add(r.getMultiply(14)),X(s,10),s.gravitate=null,N.push(s)}function tt(t,e){const s=new E(t,e);s.damage=(t,e)=>{e===z&&(s.delete=!0)},X(s,30),rt(s),N.push(s)}function et(t){const e=2+Math.floor(B(4));for(let s=0;s{let s=0;_=r=>{window.requestAnimationFrame(i=>{const o=void 0===r?(i-s)/1e3*1:r;t.engaged&&Z();const{asteroidCount:n}=K(o);var a;j!==(a=n)&&(e.innerHTML=a,j=a,0===a&&(k("win").style.display="block")),W(),s=i,_()})},K(0),W()};const ot=(t,e)=>{const s=[t.width,t.height],r=()=>{e.engage(),P.thrust(),Z(),Y("thrust")},i=()=>{const t=e.fire();J(e,t),P.gun(),Y("shoot")};window.addEventListener("wheel",t=>{const e=.001*Math.min(600,Math.abs(t.deltaY))*I,s=t.deltaY<0?-1:1;I=Math.max(.4,Math.min(5e3,I+s*e)),L||W(),Y("zoom")}),window.addEventListener("keydown",t=>{switch(t.key.toUpperCase()){case"W":r()}}),window.addEventListener("keyup",t=>{switch(t.key.toUpperCase()){case"W":e.disengage();break;case" ":i()}}),window.oncontextmenu=t=>t.preventDefault(),t.onmousedown=t.ontouchstart=t=>{F||3===t.which&&r()},t.onmouseup=t.ontouchend=t=>{F||(L?3!==t.which?i():e.disengage():L||(L=!0,k("main").classList.add("go"),Y("start"),_(0)))},t.onmousemove=t.ontouchmove=t=>{if(F)return;if(!L)return;const r=(t=>{const e=t.type.startsWith("touch")?t.targetTouches[0]:t;return[e.pageX,e.pageY]})(t).map((t,e)=>(t-s[e]/2)*(1===e?-1:1)),i=Math.atan2(r[1],r[0]);e.rotation=i-Math.PI/2,Y("rotate")}};document.addEventListener("DOMContentLoaded",async()=>(D=await T.init("#canvas",U,{fullscreen:!0}),window.z.glp=D,console.log(D),ot(D.gl.canvas,q),it(q,k("count")),D)),window.z={SpaceObject:l,glp:D,objects:N}}]).default; +window.stars=function(t){var e={};function s(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,s),o.l=!0,o.exports}return s.m=t,s.c=e,s.d=function(t,e,r){s.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},s.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},s.t=function(t,e){if(1&e&&(t=s(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(s.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)s.d(r,o,function(e){return t[e]}.bind(null,o));return r},s.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return s.d(e,"a",e),e},s.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},s.p="",s(s.s=1)}([function(t,e){!function(t,e){for(var s in e)t[s]=e[s]}(e,function(t){var e={};function s(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,s),o.l=!0,o.exports}return s.m=t,s.c=e,s.d=function(t,e,r){s.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},s.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},s.t=function(t,e){if(1&e&&(t=s(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(s.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)s.d(r,o,function(e){return t[e]}.bind(null,o));return r},s.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return s.d(e,"a",e),e},s.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},s.p="",s(s.s=0)}([function(t,e,s){"use strict";s.r(e);class r{constructor(t=0,e=0){this.x=t,this.y=e}set({x:t,y:e}){return this.x=t||0,this.y=e||0,this}clear(){this.x=0,this.y=0}fix(){return!!this.check()||(this.x=Number(this.x),this.y=Number(this.y),!!this.check()||(this.x=0,this.y=0,!1))}add({x:t,y:e}){return this.x+=t||0,this.y+=e||0,this}subtract({x:t,y:e}){return this.x-=t||0,this.y-=e||0,this}multiply(t){return this.x*=t||1,this.y*=t||1,this}abs(){return this.x=Math.abs(this.x),this.y=Math.abs(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}reverse(){return this.multiply(-1)}normalize(){const t=this.getMagnitude();return 0===t?(this.x=0,this.y=0,this):(this.x=this.x/t,this.y=this.y/t,this)}setMagnitude(t){return this.normalize().multiply(t)}setTangent(){return this.set(this.y,this.x)}getDistance({x:t,y:e}){return Math.sqrt(Math.pow(this.x-t,2)+Math.pow(this.y-e,2))}getAbsoluteDistance(t={}){return Math.abs(this.getDistance(t))}getMagnitude(){return Math.sqrt(Math.pow(this.x,2)+Math.pow(this.y,2))}clone(){return new r(this.x,this.y)}getMultiply(t){return new r(this.x*t,this.y*t)}getDot({x:t,y:e}){return this.x*t+this.y*e}getUnitVector(t={}){const e=this.getAbsoluteDistance(t);if(0===e)return new r(0,0);const s=t.x-this.x,o=t.y-this.y;return new r(s/e,o/e)}getUnitVectorTangent(t={}){const e=this.getAbsoluteDistance(t);if(0===e)return new r(0,0);const s=(t.y-this.y)/e,o=(this.x-t.x)/e;return new r(s,o)}getPerpendicularVector(t=!1){return t?new r(-1*this.y,this.x):new r(this.y,-1*this.x)}getTangent(){return new r(this.y,this.x)}check(){return"number"==typeof this.x&&"number"==typeof this.y&&!isNaN(this.x)&&!isNaN(this.y)}isEqual({x:t,y:e}){return this.x===t&&this.y===e}isEqualInteger({x:t,y:e}){return Math.round(this.x)===Math.round(t)&&Math.round(this.y)===Math.round(e)}setByPolarCoords(t,e){return this.set({x:t*Math.cos(e),y:t*Math.sin(e)})}rotate(t,e){return this.subtract(e),this.setByPolarCoords(this.r,this.theta+t),this.add(e),this}getRadius(){return this.getDistance({x:0,y:0})}setRadius(t){return this.setByPolarCoords(t,this.getTheta()),this}getTheta(){return Math.atan2(this.y,this.x)}setTheta(t){this.setByPolarCoords(this.getRadius(),t)}getDegrees(){return this.getTheta()*(180/Math.PI)}equals(t={}){return this.isEqual(t)}copy(){return this.clone()}getCopy(){return this.clone()}getClone(){return this.clone()}}var o=r;e.default={Coords:o}}]).default)},function(t,e,s){"use strict";s.r(e);class r{constructor(t){this.verts=t}static getRegularPolygonVerts(t=3,e=1,s=0){const r=[],o=2*Math.PI;for(let i=0;i[t[0]+s[0]/e,t[1]+s[1]/e],[0,0])}static getRadius([t,e]){return Math.sqrt(Math.pow(t,2)+Math.pow(e,2))}static getRadii(t){let e=1/0;const s=t.reduce((t,s)=>{const o=r.getRadius(s);return ot?o:t},0);return{inner:e,outer:s}}}var o=r,i=s(0);function n(t,e){t.forEach(s=>{n.isPhysical(s)&&(s.collide&&s.collide(t),s.gravitate&&s.gravitate(e,t),s.move&&s.move(e))})}function a(){return new n.Coords}n.Coords=i.Coords,n.bigG=5,n.collidingVelocityMultiplier=.95,n.collidePushbackMultipler=.2,n.elasticity=.98,n.MIN_GRAVITY_RADIUS=1,n.checkAabbCollision=(t,e)=>{const s=t.outerRadius||t.innerRadius,r=e.outerRadius||e.innerRadius,o=t.pos.x+s,i=t.pos.y+s,n=e.pos.x-r,a=e.pos.y-r;if(n>o||a>i)return!1;const c=t.pos.x-s,l=t.pos.y-s,h=e.pos.x+r,u=e.pos.y+r;return!(c>h||l>u)},n.checkRadiusCollision=(t,e)=>{const s="number"==typeof t.innerRadius?t.innerRadius:0,r="number"==typeof e.innerRadius?e.innerRadius:0,o=t.pos.getDistance(e.pos)-s-r;return{isColliding:!(o>0),edgeToEdgeDistance:o}},n.isPhysical=t=>t.pos instanceof n.Coords&&t.vel instanceof n.Coords,n.getOrbitalVelocity=function(t,e,s=!1,r=n.bigG){const o=e.mass,i=t.pos.getDistance(e.pos),a=Math.sqrt(r*o/i);return t.pos.getUnitVector(e.pos).getPerpendicularVector(s).multiply(a)},n.canCollide=t=>({colliding:[],collideDetect(t){return!!n.checkAabbCollision(this,t)&&n.checkRadiusCollision(this,t)},collidePushback(e,s,r=n.collidePushbackMultipler){const o=t.mass>e.mass?t:e,i=o===t?e:t,a=i.pos.getUnitVector(o.pos).multiply(s*r);return i.pos.add(a),{pusher:o,pushee:i,push:a}},collideBounce(t,e=n.elasticity){var s=this;if(s.mass<=0||t.mass<=0)return!1;s.mass,s.vel.getMagnitude(),t.mass,t.vel.getMagnitude();var r=s.pos.getUnitVector(t.pos),o=2*(s.vel.getDot(r)-t.vel.getDot(r))/(s.mass+t.mass);return s.vel.add(r.getMultiply(-1*o*t.mass)),s.vel.multiply(e),t.vel.add(r.getMultiply(o*s.mass)),s.vel.multiply(e),!0},collideDamage(e){if(!t.damage)return;const s=t.vel.clone().add(e.vel).getMagnitude(),r=s<1?0:Math.ceil(Math.pow(s,1.4)/10);r&&t.damage(r,e)},collide(e){t.isColliding=!1,t.colliding.length=0,e.forEach(e=>{if(t===e||!n.isPhysical(e))return!1;const{isColliding:s,edgeToEdgeDistance:r}=t.collideDetect(e);return!!s&&(t.colliding.push(e),t.collidePushback(e,r),t.collideBounce(e),t.collideDamage(e),!0)}),t.isColliding=t.colliding.length>0,t.isColliding&&t.vel.multiply(n.collidingVelocityMultiplier)}}),n.canMove=t=>({lastPos:a(),pos:a(),force:a(),acc:a(),vel:a(),move(e){if(t.lastPos.set(t.pos),0!==t.mass){const e=new n.Coords(t.force.x/t.mass,t.force.y/t.mass);t.acc.add(e)}const s=t.acc.getMultiply(e);t.vel.add(s);const r=t.vel.getMultiply(e/2);t.pos.add(r),t.force.clear(),t.acc.clear()}}),n.canGravitate=(t,e=n.bigG)=>({gravitate(s,r){if(0===t.mass)return!1;const o=e*t.mass;r.forEach(e=>t.gravitateOne(e,o))},gravitateOne(e,s){if(e===t||0===e.mass||0===t.mass||t.isColliding||!t.gravitate||!n.isPhysical(e))return!1;const r=t.pos.getDistance(e.pos);if(r({rotation:0,rotVel:0,torque:0,momentOfInertia:0,inverseMomentOfInertia:0,rotate(e){t.rotation+=t.rotVel*e}}),n.physical=(t,{mass:e=1,bigG:s=n.bigG})=>(Object.assign(t,{mass:e},n.canCollide(t),n.canMove(t),n.canGravitate(t,s),n.canRotate(t)),t);var c=n;c.bigG=1e-6;var l=class extends o{constructor(t=[]){super([]);const e=()=>.2*Math.random()+.4,s=this;Object.assign(s,{baseVerts:t,baseColor:[e(),e(),e()],hitColor:[.7,0,0],hit:!1,verts:[],vc:null,r:0,outerRadius:0,innerRadius:0,children:[]}),c.physical(s,{mass:10}),s.alignToCenter(),s.calcRadii(),s.calcVerts(),s.calcMass(),s.Coords=c.Coords}alignToCenter(){const t=o.getCenter(this.baseVerts);this.baseVerts.forEach(e=>{[0,1].forEach(s=>e[s]=e[s]-t[s])})}calcRadii(){let t=1/0;this.outerRadius=this.r=this.baseVerts.reduce((e,s)=>{const r=s.r=o.getRadius(s);return re?r:e},0),this.innerRadius=t}calcMass(){this.mass=Math.PI*Math.pow((this.innerRadius+this.r)/2,2)*50}getVertColors(){return this.vc}getColor(t,e,s){const r=this.baseColor;return[r[0]+(this.hit?.1:0),r[1]+(this.isColliding?.1:0),r[2]]}calcVerts(){let t=[];this.verts.length=0,this.baseVerts.forEach((e,s)=>{const r=this.verts[s]=[e[0]+this.pos.x,e[1]+this.pos.y,0];t=t.concat(r).concat(this.getColor(r,e,s))}),this.vc=new Float32Array(t)}calcVertWithRotation(t,e,s){const r=Math.cos(this.rotation),o=Math.sin(this.rotation);return this.verts[s]=[r*e[0]-o*e[1]+this.pos.x,r*e[1]+o*e[0]+this.pos.y,0],t.concat(this.verts[s]).concat(this.getColor())}calcVertsWithRotation(){this.verts.length=0;let t=this.baseVerts.reduce((t,e,s)=>this.calcVertWithRotation(t,e,s),[]);this.vc=new Float32Array(t)}static rotate(t,e,s){let r=t[0]-s[0];r+=s[0]}setOrbitalVelocity(t){this.vel.set(c.getOrbitalVelocity(this,t))}};const h=[[.2,-.1,0],[.35,0,0],[.45,.1,0],[.4,.3,0],[.3,.4,0],[.2,.8,0],[.1,.4,0],[0,.3,0],[-.05,.1,0],[.05,0,0]];var u=class extends l{constructor(){super(h.map(t=>t.map(t=>1.5*t))),Object.assign(this,{shipScale:1.5,engaged:!1,facingRotationOffset:-Math.PI/2,thrustPowerUpMax:2,thrustPowerUpStart:.75,thrustPowerUp:.75,thrustPowerUpMultiplier:.5,thrustPowerDownMultiplier:2}),this.mass*=3,this.thrustMagnitude=100*this.mass,this.baseColor=[.6,1,.3]}setRotation(t){this.rotation=t+this.facingRotationOffset}getFacingUnitVector(){const t=this.rotation+this.facingRotationOffset,e=Math.cos(t),s=Math.sin(t);return new this.Coords(e,s)}ongoing(t){this.engaged?this.thrust(t):this.cooldownThrust(t)}engage(){this.engaged=!0,this.thrust(.02)}disengage(){this.engaged=!1}thrust(t){this.thrustPowerUp;this.thrustPowerUp+=t*this.thrustPowerUpMultiplier,this.thrustPowerUp=Math.min(this.thrustPowerUpMax,this.thrustPowerUp);const e=this.getFacingUnitVector().getMultiply(t*-this.thrustMagnitude*this.thrustPowerUp);this.force.add(e)}cooldownThrust(t){this.thrustPowerUp<=this.thrustPowerUpStart||(this.thrustPowerUp-=t*this.thrustPowerDownMultiplier,this.thrustPowerUp=Math.max(this.thrustPowerUpStart,this.thrustPowerUp))}fire(){return 22+2*Math.random()}};var d=class extends l{constructor(){const t=1.5+.5*Math.random()-.5*Math.random();super(l.getRegularPolygonVerts(3+Math.floor(7*Math.random()),t,.2*t))}};var g=class extends l{constructor(){super(l.getRegularPolygonVerts(40,40)),this.pos.set({x:0,y:0}),this.mass*=1e4,this.innerRadius*=.94}move(){}};let p=(t=1,e=.05,s=220,r=0,o=0,i=.1,n=0,a=1,c=0,l=0,h=0,u=0,d=0,g=0,p=0,v=0,M=0,b=1,w=0,x=0)=>{let P,R,C=2*Math.PI,V=c*=500*C/m**2,S=(0U?0:(Uu&&(s+=h,T+=h,D=0),!d||++_%d||(s=T,c=V,D=D||1);return(t=y.createBuffer(1,R,m)).getChannelData(0).set(E),(s=y.createBufferSource()).buffer=t,s.connect(y.destination),s.start(),s},f=.3,y=new(window.AudioContext||webkitAudioContext),m=44100;const v=[,,470,,,.13,4,1.78,-.3,,-50,.04,.02,.1,-.2,.4,,.51,.04,.01],M=[,,651,,.2,.88,4,1.22,.3,,,,,.6,,1,,.51,.01],b=[.6,,980,,.51,1.62,4,2.35,,,,,,.3,.7,.9,.13,.73,.06],w=[1.3,,117,.12,.27,1.21,4,2,.7,,,,,.8,,.9,.34,1.1,.04,.2],x=[,,452,,.08,.46,2,.73,2.4,,,,,,,,.04,.51];var P={gun(){p(...v)},explode(){p(...M)},thrust(){p(...b)},death(){p(...w)},jump(){p(...x)}};const R=new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]),C=(...t)=>console.log(...t);class V{constructor(t,e){Object.assign(this,{gl:t,p:e,i:0,aV:e.map(()=>({})),uV:e.map(()=>({}))})}use(t){return this.i=t,this.gl.useProgram(this.p[t]),this}v(t,e,s,r,o){const i=this,n=i[t][i.i][r]||i.gl[e](i.p[i.i],r);return i.gl[`${s}${o.length}f`](n,...o),i[t][this.i][r]=n}attr(t,...e){return this.v("aV","getAttribLocation","vertexAttrib",t,e)}unif(t,...e){return this.v("uV","getUniformLocation","uniform",t,e)}ua(t){t.forEach(t=>this.unif(...t))}buff(t,e,{size:s=2,type:r=this.gl.FLOAT,norm:o=!1,stride:i=0,offset:n=0}={}){const{gl:a,p:c}=this;a.bindBuffer(a.ARRAY_BUFFER,a.createBuffer()),a.bufferData(a.ARRAY_BUFFER,e,a.STATIC_DRAW);const l=e.BYTES_PER_ELEMENT,h=a.getAttribLocation(c[this.i],t);return a.vertexAttribPointer(h,s,r,o,i*l,n*l),a.enableVertexAttribArray(h),h}ba(t,e){e.forEach(e=>this.buff(e[0],t,e[1]))}clear(){this.gl.clearColor(0,0,0,1),this.gl.clear(this.gl.COLOR_BUFFER_BIT)}draw({uniforms:t=[],i:e=this.i,buffs:s=[],verts:r=R,vertSize:o=2,vertsToDraw:i,type:n=this.gl.TRIANGLES,clear:a=!0}){const c=this;return c.use(e),c.ua(t),c.ba(r,s),a&&c.clear(),void 0===i&&(i=r.length/o),c.gl.drawArrays(n,0,i),c}drawAll(t={}){this.p.forEach((e,s)=>this.draw(Object.assign({i:s,clear:!s},t)))}}const S={Glp:V,STV:R,STNPV:2,getRenderingContext:(t,e=!1)=>{const s=document.querySelector(t).getContext("webgl",{antialias:e});return s||alert("Unable to initialize WebGL. Your browser or machine may not support it."),s},loadText:t=>fetch(t).then(t=>t.text()),loadShaders:t=>Promise.all(t.map(t=>S.loadText(t))),compileShader:(t,e,s)=>{const r=t.createShader(e);return t.shaderSource(r,s),t.compileShader(r),r},fullscreen:(t,e=window)=>{t.canvas.width=e.innerWidth,t.canvas.height=e.innerHeight,S.setViewport(t)},setViewport:t=>{t.viewport(0,0,t.canvas.width,t.canvas.height)},compile:(t,e)=>{const s=t.createProgram(),r=[t.VERTEX_SHADER,t.FRAGMENT_SHADER],o=["vertex","fragment"];return e.map((e,i)=>{const n=S.compileShader(t,r[i],e);t.attachShader(s,n),C(o[i]+" shader:",t.getShaderInfoLog(n)||"OK")}),t.linkProgram(s),t.useProgram(s),C("program:",t.getProgramInfoLog(s)||"OK"),s},init:async(t,e,{fullscreen:s}={})=>{const r="string"==typeof t?S.getRenderingContext(t):t,o=e.map(t=>S.loadShaders(t).then(t=>S.compile(r,t))),i=await Promise.all(o);return s&&S.fullscreen(r),new V(r,i)}};var T=S;var E=class extends l{constructor(t,e,s=[1,.5,0],r=.2,o=8){super(l.getRegularPolygonVerts(o,r)),this.pos.set(t),this.vel.set(e),Object.assign(this,{mass:0,baseColor:s,baseR:r,maxR:10*r,r:r,explosionSpeed:6+3*Math.random()})}ongoing(t){this.r+=t*this.explosionSpeed,this.r>this.maxR&&(this.delete=!0),this.baseVerts=l.getRegularPolygonVerts(8,this.r),this.calcVerts()}};const O=()=>20*Math.random()*(Math.random()<.5?1:-1);var A=class extends l{constructor(t,e=2){const s=.75*t.r/e,r=Math.max(3,Math.round(t.verts.length*Math.random()));super(l.getRegularPolygonVerts(r,s,s)),this.baseColor=t.baseColor.map(t=>Math.max(0,t-.3)),this.pos.set(t.pos);const o={x:O(),y:O()};this.vel.set(t.vel).add(o)}};const U=[["v.glsl","stars-f.glsl"],["space-v.glsl","space-f.glsl"]];let D,_,I=20,j=404,L=!1,k=!1;const F=t=>document.getElementById(t),B=(t=1)=>Math.random()*t,G={},N=[],z=[],q=function(){const t=new g,e=t.baseColor.map(t=>Math.max(0,t-.3)),s=1.1*t.r;return[8,8,4,4,4,3].forEach(t=>function(t,e,s){const r=l.getRegularPolygonVerts(t,e),o=new l(r);o.baseColor=s,o.mass=0,o.vel=null,o.move=()=>{},o.collide=()=>{},o.gravitate=null,ot(o,.1),z.push(o)}(t,s,e)),N.push(t),t}(),W=(function(t){for(let e=0;e<404;e++){const e=new d;rt(e,t),e.damage=(s,r)=>{r===t&&rt(e,t)},N.push(e)}}(q),function(t){const e=new u;return e.pos.set({x:120,y:0}),e.setOrbitalVelocity(t),e.damage=(e,s)=>{s===t&&J("sun")},N.push(e),e}(q)),Y=()=>{const t=[["iResolution",D.gl.canvas.width,D.gl.canvas.height],["zoom",I],["viewerPosition",W.pos.x,W.pos.y,0],["iTime",0]];D.use(0).draw({uniforms:t,buffs:[["position"]]});const e=[["position",{size:3,stride:6}],["color",{size:3,stride:6,offset:3}]];D.use(1).draw({uniforms:t,buffs:e,verts:new Float32Array([]),vertSize:6,type:D.gl.TRIANGLE_FAN,clear:!1}),z.concat(N).forEach(t=>{D.draw({buffs:e,verts:t.getVertColors(),vertSize:6,type:D.gl.TRIANGLE_FAN,clear:!1})})};function H(t){if(G[t])return;G[t]=!0;const e=F("ach-"+t);e&&e.classList.add("unlocked"),Object.keys(G).length>=5&&F("intro").classList.add("closed")}function K(t,e){return t.pos.getDistance(q.pos)>e&&(rt(t,q),!0)}const X=t=>{let e=0;const s=[];return N.forEach((r,o)=>{r.delete?s.push(o):(r.ongoing&&r.ongoing(t),r.rotate(t),r.calcVertsWithRotation(),!r.gravitate||r instanceof g||r.gravitate(t,[q]),r.move(t),r.collide(N),r instanceof d?(e++,K(r,250)):r instanceof u&&K(r,800)&&P.jump())}),z.forEach(e=>{e.rotate(t),e.calcVertsWithRotation()}),((t=[])=>{for(let e=t.length-1;e>=0;e--){const s=t[e];N.splice(s,1)}})(s),{asteroidCount:e}};function $(t,e=8){t.decayTime=e,t.ongoing=e=>{t.decayTime-=e,t.decayTime<0&&(t.delete=!0)}}function J(t){k=!0,W.delete=!0,st(W,10),Z(W.pos,W.vel,5),P.death(),function(t="sun"){F("main").classList.remove("go"),k&&(F("intro").classList.add("closed"),F("dead").classList.remove("closed"),F(t).style.display="block")}(t)}const Q=(t,e)=>{const s=new l([[0,.2,0],[-.1,-.1,0],[0,-.2,0],[.1,-.1,0]]);s.rotation=t.rotation;const r=t.getFacingUnitVector().multiply(-1);s.pos.set(t.pos).add(r.getMultiply(t.shipScale)),s.vel.set(t.vel).add(r.getMultiply(e)),s.mass*=.5,$(s,10),s.damage=(t,e)=>{var r;s.baseColor[0]=.9,s.decayTime*=.5,e instanceof d?((r=e).delete=!0,st(r),Z(r.pos,r.vel),P.explode()):e instanceof u&&J("bullet")},s.gravitate=null,N.push(s)};function Z(t,e,s=1){const r=new E(t,e,[1,.5,0],.2*s,8),o=new E(t,e,[1,1,0],.05*s,3);N.push(r),N.push(o)}function tt(){const t=.07+B(.05),e=l.getRegularPolygonVerts(3,t),s=new l(e);s.baseColor=[.5,.3,.5],s.rotation=B(2*Math.PI);const r=W.getFacingUnitVector();s.pos.set(W.pos).add(r.getMultiply(.5*W.shipScale)),s.vel.set(W.vel).add(r.getMultiply(14)),$(s,10),s.gravitate=null,N.push(s)}function et(t,e){const s=new A(t,e);s.damage=(t,e)=>{e===q&&(s.delete=!0)},$(s,30),ot(s),N.push(s)}function st(t,e=4){const s=2+Math.floor(B(e));for(let e=0;e{let s=0;_=r=>{window.requestAnimationFrame(o=>{const i=void 0===r?(o-s)/1e3*1:r;t.engaged&&tt();const{asteroidCount:n}=X(i);var a;j!==(a=n)&&(e.innerHTML=a,j=a,0===a&&(F("win").style.display="block")),Y(),s=o,_()})},X(0),Y()};const nt=(t,e)=>{const s=[t.width,t.height],r=()=>{e.engage(),P.thrust(),tt(),H("thrust")},o=()=>{const t=e.fire();Q(e,t),P.gun(),H("shoot")};window.addEventListener("wheel",t=>{const e=.001*Math.min(600,Math.abs(t.deltaY))*I,s=t.deltaY<0?-1:1;I=Math.max(.4,Math.min(5e3,I+s*e)),L||Y(),H("zoom")}),window.addEventListener("keydown",t=>{switch(t.key.toUpperCase()){case"W":r()}}),window.addEventListener("keyup",t=>{switch(t.key.toUpperCase()){case"W":e.disengage();break;case" ":o()}}),window.oncontextmenu=t=>t.preventDefault(),t.onmousedown=t.ontouchstart=t=>{k||3===t.which&&r()},t.onmouseup=t.ontouchend=t=>{k||(L?3!==t.which?o():e.disengage():L||(L=!0,F("main").classList.add("go"),H("start"),_(0)))},t.onmousemove=t.ontouchmove=t=>{if(k)return;if(!L)return;const r=(t=>{const e=t.type.startsWith("touch")?t.targetTouches[0]:t;return[e.pageX,e.pageY]})(t).map((t,e)=>(t-s[e]/2)*(1===e?-1:1)),o=Math.atan2(r[1],r[0]);e.rotation=o-Math.PI/2,H("rotate")},document.addEventListener("click",t=>{console.log(t.target,t),"restart"===t.target.id&&location.reload()})};document.addEventListener("DOMContentLoaded",async()=>(D=await T.init("#canvas",U,{fullscreen:!0}),window.z.glp=D,console.log(D),nt(D.gl.canvas,W),it(W,F("count")),D)),window.z={SpaceObject:l,glp:D,objects:N}}]).default; diff --git a/dist/index.html b/dist/index.html index 19aa856..21d3c0e 100644 --- a/dist/index.html +++ b/dist/index.html @@ -3,9 +3,9 @@ 404 Orbiting Asteroids - A js13k game for 2020 - + - + @@ -137,7 +146,8 @@ You died.

The sun is hot! 🌞+🚀=💀

Ricochet! 🚀+🔫=💀

-

🔄 Refresh the page (F5) to start over.

+

Click below or 🔄 Refresh the page (F5) to start over.

+ diff --git a/package-lock.json b/package-lock.json index 3791759..fecd014 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2979,8 +2979,8 @@ "from": "git+https://github.com/rocket-boots/coords.git#v0.6.0" }, "rocket-boots-physics": { - "version": "git+https://github.com/rocket-boots/physics.git#a37264bc8c08e418d397e244b917b3d2189f2762", - "from": "git+https://github.com/rocket-boots/physics.git#v0.4.0", + "version": "git+https://github.com/rocket-boots/physics.git#6d514a8ee641dbc4f35e9a23d8864e2f831f4f10", + "from": "git+https://github.com/rocket-boots/physics.git#v0.5.0", "requires": { "rocket-boots-coords": "git+https://github.com/rocket-boots/Coords.git#v0.6.0" }, diff --git a/package.json b/package.json index af22047..54b2734 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ }, "dependencies": { "rocket-boots-coords": "git+https://github.com/rocket-boots/coords.git#v0.6.0", - "rocket-boots-physics": "git+https://github.com/rocket-boots/physics.git#v0.4.0", + "rocket-boots-physics": "git+https://github.com/rocket-boots/physics.git#v0.5.0", "webglp": "git+https://github.com/rocket-boots/webglp.git#v0.1.0" } } diff --git a/src/SpaceObject.js b/src/SpaceObject.js index 73ec4ce..fe854f1 100644 --- a/src/SpaceObject.js +++ b/src/SpaceObject.js @@ -1,10 +1,10 @@ import Polygon from './Polygon.js'; // import physics from '../../../rocket-boots-repos/physics/src/physics.js'; -// import { physics } from 'rocket-boots-physics'; import physics from '../node_modules/rocket-boots-physics/src/physics.js'; -// import { Coords } from 'rocket-boots-coords'; +// import { Coords } from 'rocket-boots-coords'; // physics.Coords = Coords; + physics.bigG = .000001; class SpaceObject extends Polygon { @@ -22,7 +22,7 @@ class SpaceObject extends Polygon { c(), ], hitColor: [.7, 0., 0.], - boundingBox: [], + // boundingBox: [], hit: false, verts: [], // set in calc vc: null, // set in calc @@ -32,6 +32,7 @@ class SpaceObject extends Polygon { // acc: new Coords(), // vel: new Coords(), r: 0, + outerRadius: 0, innerRadius: 0, children: [], } @@ -61,7 +62,7 @@ class SpaceObject extends Polygon { calcRadii() { let inner = Infinity; // Outer/largest radius - this.r = this.baseVerts.reduce((n, v) => { + this.outerRadius = this.r = this.baseVerts.reduce((n, v) => { // Store radius on each base vertex for quicker computation later const r = v.r = Polygon.getRadius(v); if (r < inner) { inner = r; } @@ -79,7 +80,7 @@ class SpaceObject extends Polygon { return this.vc; } - getColor() { + getColor(v, bv, i) { const bc = this.baseColor; return [ bc[0] + (this.hit ? .1 : 0.), @@ -92,8 +93,8 @@ class SpaceObject extends Polygon { let vc = []; this.verts.length = 0; this.baseVerts.forEach((bv, i) => { - this.verts[i] = [bv[0] + this.pos.x, bv[1] + this.pos.y, 0]; // bv[2] + this.pos.z]; - vc = vc.concat(this.verts[i]).concat(this.getColor()); + const v = this.verts[i] = [bv[0] + this.pos.x, bv[1] + this.pos.y, 0]; // bv[2] + this.pos.z]; + vc = vc.concat(v).concat(this.getColor(v, bv, i)); }); this.vc = new Float32Array(vc); } diff --git a/src/game.js b/src/game.js index f35a1dd..dd8f38c 100644 --- a/src/game.js +++ b/src/game.js @@ -41,6 +41,7 @@ const rand = (n = 1) => Math.random() * n; const achievements = {}; const objects = []; +const effects = []; const sun = setupSun(); const asteroids = setupAsteroids(sun); const ship = setupShip(sun) @@ -58,7 +59,7 @@ const draw = () => { // Draw stars background glp.use(0).draw({ uniforms, buffs: [['position']] }); - // Draw galaxy + // Draw "space" galaxy const buffs = [ ['position', { size: 3, stride: 6 }], ['color', { size: 3, stride: 6, offset: 3 }], @@ -72,7 +73,7 @@ const draw = () => { clear: false, }); - objects.forEach((o) => { + effects.concat(objects).forEach((o) => { // glp.unif('translation', 0, 0, 0); // o.x, o.y, o.z); glp.draw({ // uniforms: [], @@ -99,7 +100,7 @@ function achieve(what) { } } -//--------------- OBJECTS +//--------------- OBJECT MANAGEMENT const removeDeletedObjects = (deleteIndices = []) => { for(let d = deleteIndices.length - 1; d >= 0; d--) { @@ -145,10 +146,16 @@ const objectLoop = (t) => { } } }); + effects.forEach((o) => { + o.rotate(t); + o.calcVertsWithRotation(); + }); removeDeletedObjects(deleteIndices); return { asteroidCount }; }; +//-------------------- OBJECT CREATION + function makeDecay(o, n = 8) { o.decayTime = n; o.ongoing = (t) => { @@ -160,8 +167,8 @@ function makeDecay(o, n = 8) { function die(reason) { isDead = true; ship.delete = true; - makeFragments(ship); - makeBlast(ship.pos, ship.vel); + makeFragments(ship, 10); + makeBlast(ship.pos, ship.vel, 5); sounds.death(); endGame(reason); } @@ -188,6 +195,7 @@ const makeBullet = (ship, bulletPower) => { b.mass *= 0.5; makeDecay(b, 10); b.damage = (dmg, objHit) => { + b.baseColor[0] = .9; // red-ify the richoceting bullets // console.log(dmg / 10); b.decayTime *= 0.5; if (objHit instanceof Asteroid) { @@ -200,9 +208,9 @@ const makeBullet = (ship, bulletPower) => { objects.push(b); }; -function makeBlast(pos, vel) { - const b = new Blast(pos, vel); - const b2 = new Blast(pos, vel, [1., 1., 0.], 0.05, 3); +function makeBlast(pos, vel, scale = 1) { + const b = new Blast(pos, vel, [1., 0.5, 0.], .2 * scale, 8); + const b2 = new Blast(pos, vel, [1., 1., 0.], 0.05 * scale, 3); objects.push(b); objects.push(b2); } @@ -233,8 +241,8 @@ function makeFragment(o, n) { objects.push(f); } -function makeFragments(o) { - const n = 2 + Math.floor(rand(4)); +function makeFragments(o, extra = 4) { + const n = 2 + Math.floor(rand(extra)); for(let i = 0; i < n; i++) { makeFragment(o, n); } } @@ -288,23 +296,24 @@ function setupAsteroids(sun) { } }; -// function makeOuterSun(s, r, color) { -// const baseVerts = SpaceObject.getRegularPolygonVerts(s, r); -// const outerSun = new SpaceObject(baseVerts); -// outerSun.baseColor = color; -// outerSun.mass = 0; -// outerSun.vel = null; -// outerSun.move = () => {}; -// outerSun.collide = () => {}; -// outerSun.gravitate = null; -// giveSpin(outerSun, .1); -// objects.push(outerSun); -// } +function makeOuterSun(s, r, color) { + const baseVerts = SpaceObject.getRegularPolygonVerts(s, r); + const outerSun = new SpaceObject(baseVerts); + outerSun.baseColor = color; + outerSun.mass = 0; + outerSun.vel = null; + outerSun.move = () => {}; + outerSun.collide = () => {}; + outerSun.gravitate = null; + giveSpin(outerSun, .1); + effects.push(outerSun); +} function setupSun() { const sun = new Sun(); - // const color = sun.baseColor.map((c) => Math.max(0, c - 0.2)); - // const r = sun.r * 1.05; + const color = sun.baseColor.map((c) => Math.max(0, c - 0.3)); + const r = sun.r * 1.1; + [8,8,4,4,4,3].forEach((s) => makeOuterSun(s, r, color)); // makeOuterSun(8, r, color); // makeOuterSun(8, r, color); // makeOuterSun(3, r, color); @@ -429,6 +438,12 @@ const setupInput = (canvas, ship) => { ship.rotation = theta - Math.PI/2; achieve('rotate'); }; + document.addEventListener('click', (e) => { + console.log(e.target, e); + if (e.target.id === 'restart') { + location.reload(); + } + }); }; // Create glp