From 491f532750da38f17e2891042bcb03f095ec4d92 Mon Sep 17 00:00:00 2001 From: Logan Hunt Date: Mon, 11 Apr 2022 16:55:16 -0600 Subject: [PATCH] Move particle stuff to a system to simplify spawning particles --- src/.game.js.swp | Bin 0 -> 12288 bytes src/bootstrap.js | 4 +- src/components/particles.js | 1 + src/entities/.borderParticles.js.swp | Bin 0 -> 12288 bytes src/entities/borderParticles.js | 74 +++++++++++---------------- src/game.js | 3 +- src/systems/.collision.js.swp | Bin 0 -> 12288 bytes src/systems/.particle.js.swp | Bin 0 -> 12288 bytes src/systems/.render.js.swp | Bin 0 -> 12288 bytes src/systems/collision.js | 18 ++----- src/systems/keyboardInput.js | 2 +- src/systems/particle.js | 57 +++++++++++++++++++++ src/systems/render.js | 11 ++-- styles/style.css | 4 +- 14 files changed, 107 insertions(+), 67 deletions(-) create mode 100644 src/.game.js.swp create mode 100644 src/components/particles.js create mode 100644 src/entities/.borderParticles.js.swp create mode 100644 src/systems/.collision.js.swp create mode 100644 src/systems/.particle.js.swp create mode 100644 src/systems/.render.js.swp create mode 100644 src/systems/particle.js diff --git a/src/.game.js.swp b/src/.game.js.swp new file mode 100644 index 0000000000000000000000000000000000000000..4383ff4576f019989e628cef28c902bc1fff5a48 GIT binary patch literal 12288 zcmeI2&2Jk;7{({%#76+}aYCS}d)bxZbtxPwMMY|wQlhqMMOqG+9LBq2d&um}vNN01 zjY1{h*i)tc0nj@qt{gz(LxMy95$+s$X4g*ab%9(9ucaqz&%W_=PI z`T67=!|P?nPJMf8@ZE#oR_^u~({?1xxH3MR`-j)H5a+rZ!pUsI+TBFkROsb|&yNcB zKCrpmx8-i{ipXVmQ|?J^i(DGt8>rDhS5mo&t$MCZdm}_7pStC8G(rT3z)1;Ie%L*~ z%HBEm_SukfrgNIV`pWH-W>XvyAOb{y2oM1xKm>>Y5g-Ep0Rp~QVfV0(Q`5D?)8k6( zIQ>WmB0vO)01+SpM1Tko0U|&IhyW2F0z}{`Bp@=zzJHdn!{=Zg|No!;{{Q18#vVgo zLtjB(LSH}wXah>1KVM|*cj#y6C+HDmp&QT^bQ#)&IP@0uCiD#S<0@l6Ko6kTq1T{q zUSRA#^a=C^^!Rzk9zq{OtI)6T_Y3q0x(C&MpF-YbnFtU8B0vO)01+Sp|7!w=jPp`{ zR!QeC8kGyLta-o0^PW-t(5JSxh}RLLh4Z&mF1NkN3x0tYvK-nn7bca7vHKCev~pgj zxQX*JcS#{iuTm`$JU5=)oDMhjQ(^XmOHymRyyNSc=7L?aD<=ah%52LNm2XwLI)APy zH=DaMnO!axMq4#*W2i~RgRjaf>8_M2TTU&d$z<6|{;(cw(nqBz#wvBosj1akIbhwc z!L({znw>p~ixIp%u}Uy~k^;qe;$X7n;bt=$#cQn|BJO}6hW5`jp00p5k)b-@ZJ-G@BDqRk^B5QQscPpV6TTy%6Ld-d@$k1Yvsam!JW!vR}P0V#iQAr z_iI2iw`&cr#^TP5wzeX>79O*17NEmh*MD~h6V}J=*uDp { 'src/components/position.js', 'src/components/momentum.js', 'src/components/gridPosition.js', 'src/components/appearence.js', 'src/components/controllable.js', 'src/components/pushable.js', 'src/components/loadPriority.js', 'src/components/stop.js', 'src/components/alive.js', - 'src/components/sprite.js' + 'src/components/sprite.js', 'src/components/particles.js' ], id: 'components' }, @@ -34,7 +34,7 @@ game.bootstrap = (() => { { src: [ 'src/systems/render.js', 'src/systems/grid.js', 'src/systems/physics.js', 'src/systems/keyboardInput.js', - 'src/systems/collision.js', 'src/systems/undo.js' + 'src/systems/collision.js', 'src/systems/undo.js', 'src/systems/particle.js' ], id: 'systems' }, { src: ['src/game.js'], id: 'game' }, diff --git a/src/components/particles.js b/src/components/particles.js new file mode 100644 index 0000000..8120ff1 --- /dev/null +++ b/src/components/particles.js @@ -0,0 +1 @@ +game.components.Particles = (spec) => game.Component('particles', {spec}); diff --git a/src/entities/.borderParticles.js.swp b/src/entities/.borderParticles.js.swp new file mode 100644 index 0000000000000000000000000000000000000000..c55b9593b181addef5a43ab7d38dbd2a162a83c4 GIT binary patch literal 12288 zcmeI2&u`pB6vro=fHtK9aYP+9Lh@FL*WM(}c2N-tKU&nZiW)$wD2K5SRcN3j^`rZvfCo3^DNPt{)KFTMD|{XEG=3XlS%04YEU zkOHItDL@L40#B&|X*9vUz}TJ{j?WmD6MM?xEfu5yDL@L40;B*bKnjooqyQ;E3XlS% z04eZ4R6ux){qQ_vR}Z1{`2WB7{r~F=jNJp*z(sHtG{8Sc82cOi2EGH=!Dk=@7r-mv z2w>pPNyhGiJKz?$0=B@LU=ADu-yde|Yj6{M2_kR_oCZxW4PFC3qknh6S3vi50G7bN z==-<82aDikFbV#8j}^W3+N&RNC8rS6d(njJ_WWJ=dnzC zamb_M?A+_H?cA8c^WIY3NQF3RXRP5sp6M31iMblZekzTvBrDHXwN`E4u6p!n9YFWm zyf%6ku(n;VSC44i{7=Mh+(sU(c2!GN_EOHwBX=vE%UU_}dzV4sQ?`c` zfw6^gWwkc9v9okz!vYoD=&LLGi(Q4Y!EHWoO|#6#yM9<0o260om;DYl?W|SW{4lrK zyKJI=L3n;If#h)|DxhhOjKC;lzm66G;^HXo^ l@-62%dso0a`|5s2AD15(kS6~o$HGbF(&*87-SV)t{{W`6^GyH% literal 0 HcmV?d00001 diff --git a/src/entities/borderParticles.js b/src/entities/borderParticles.js index 34512bc..260071d 100644 --- a/src/entities/borderParticles.js +++ b/src/entities/borderParticles.js @@ -1,56 +1,40 @@ -game.createBorderParticles = ({colors, maxAmount, minAmount, minLife, maxLife, minRadius, maxRadius, maxSpeed}) => { - const particles = game.Entity(); - let particleSpecs = Array(randomInRange(minAmount, maxAmount)).fill(0).map(() => { - const particle = { - x: Math.random(), - y: Math.random(), - dx: Math.random() * maxSpeed - maxSpeed / 2, - dy: Math.random() * maxSpeed - maxSpeed / 2, - radius: randomInRange(minRadius, maxRadius), - color: colors[randomInRange(0, colors.length-1)], - lifetime: randomInRange(minLife, maxLife), - elapsed: 0, - }; +game.createBorderParticles = () => { + const particleSpawner = game.Entity(); + const spawnFunction = (particleSpec) => { switch (Math.floor(Math.random() * 4)) { case 0: - particle.y = 0; - particle.dy = -Math.abs(particle.dy); + particleSpec.y = 0; + particleSpec.dy = -Math.abs(particleSpec.dy); break; case 1: - particle.x = 1; - particle.dx = Math.abs(particle.dx); + particleSpec.x = 1; + particleSpec.dx = Math.abs(particleSpec.dx); break; case 2: - particle.y = 1; - particle.dy = Math.abs(particle.dy); + particleSpec.y = 1; + particleSpec.dy = Math.abs(particleSpec.dy); break; case 3: - particle.x = 0; - particle.dx = -Math.abs(particle.dx); + particleSpec.x = 0; + particleSpec.dx = -Math.abs(particleSpec.dx); break; } - return particle; - }); - game.sprites.borderParticle = game.graphics.Sprite({ - drawFunction: (elapsedTime, {x, y, width, height}, context) => { - particleSpecs.map((spec) => spec.elapsed += elapsedTime); - particleSpecs = particleSpecs.filter((spec) => spec.lifetime > spec.elapsed); - if (particleSpecs.length === 0) { - particles.removeComponent("alive"); - } - particleSpecs.map((spec) => { - const position = {x: (spec.x * width) + x + spec.dx * spec.elapsed, y: (spec.y * height) + y + spec.dy * spec.elapsed}; - const fill = context.fillStyle; - context.fillStyle = spec.color; - context.beginPath(); - context.arc(position.x, position.y, spec.radius, 0, 2 * Math.PI); - context.fill(); - context.fillStyle = fill; - }); + return particleSpec; + }; + particleSpawner.addComponent(game.components.Particles({ + spec: { + spawnFunction, + colors: ["#16f7c9", "#0d6e5a", "#2fa18a", "#48cfb4", "#58877d", "#178054", "#2cdb92"], + maxSpeed: 0.20, + minRadius: 1, + maxRadius: 3, + minLife: 100, + maxLife: 300, + minAmount: 20, + maxAmount: 50, } - }) - particles.addComponent(game.components.LoadPriority({priority: 1})); - particles.addComponent(game.components.Alive()); - particles.addComponent(game.components.Sprite({spriteName: "borderParticle"})) - return particles; -} \ No newline at end of file + })); + particleSpawner.addComponent(game.components.LoadPriority({priority: 1})); + particleSpawner.addComponent(game.components.Alive()); + return particleSpawner; +} diff --git a/src/game.js b/src/game.js index 753d028..705d3e0 100644 --- a/src/game.js +++ b/src/game.js @@ -26,7 +26,7 @@ game.initialize = () => { // Maintained by gridSystem as a side-effect game.entitiesGrid = Array(game.config.yDim).fill(null).map(() => Array(game.config.xDim).fill(null).map(() => new Map())); - game.systemOrder = ["gridSystem", "collisionSystem", "physics", "keyboardInput", "undo", "render"]; + game.systemOrder = ["gridSystem", "collisionSystem", "physics", "keyboardInput", "undo", "particle", "render"]; game.systems = { }; game.systems.physics = game.system.Physics(), game.systems.gridSystem = game.system.Grid(game.entitiesGrid); @@ -34,6 +34,7 @@ game.initialize = () => { game.systems.render = game.system.Render(game.graphics); game.systems.undo = game.system.Undo(game.entitiesGrid); game.systems.keyboardInput = game.system.KeyboardInput(game.systems.undo); + game.systems.particle = game.system.Particle(game.canvas.context); lastTimeStamp = performance.now() requestAnimationFrame(game.loop); diff --git a/src/systems/.collision.js.swp b/src/systems/.collision.js.swp new file mode 100644 index 0000000000000000000000000000000000000000..40fcae86cc8495ac94d6310eb4b4bdd3602b38b7 GIT binary patch literal 12288 zcmeI2&u`pB6vrnVfC2>s5*GxT2C4Fv&1_So614=WNu&~q(nt+lLJqU**1LA87_$L*dDL#q~Xw0(OCMf?V0D9_df5&^OT6 zPy~h0W#|la^dup_LO($FphIXIT7fP=FGDXue?39SZ_xM9chHy66dFO-puf)$@(FbG zI3Zs^pF{6M??4;S8_;FwMd$@+0m|ci2=nAzb_5&&N5Bzq1RjjQ;Z;IuDs+~{w0?a+ zv&83G6peXLWv9o1S|9UxB>YWZnE@z0%zx+S`W3D_g_W^1hhW_I*JYH*7+?8$BYgJ9 z2KH958~7eD)>-5oFvg3_@`$;geXTEbw>f zDm}5U>CuTMr+axVNd!-MJP_W&B=Gh43M~TR@jh29Z=$`jO~%7u#HJfT)TLt)jK;cY zU9`2#XD~5Lzl3+-^2@k^#MyQQB83&>8 zhBAx&nlYtGDiN~q*^IurO6`EmpVj$RM$@Lz^y++yW^K3cD9xt^DxGGcKDMdb78X-> zUM!}%;VGpiG}Fw+T-7KTbKVcdV#ma6#V-n*qfj}l!rhG5MHsSuj*od!D2v)%di zbhnX~R(!<5Xs75H924R>aVHDlpfC&C&epA}W;WAyVR5nQ#YY)@!fRlyMbQPTk(<^q_)%M^K zpxb?eVKLMe%(P2q|M>_OS?!To`35mg81M5;)pA!jW!EH}%3|zTcZFB(2Q|m6Q3b~& zuQY3}77VIWd?#M47<&G^4YO%hk94tfUo$)JyymNFFJ?FOezSjD3^dylGgbJ6S5v3h z`~pAU{cKV1;MG(WQ4xOgy$T4in9y577aMC~Q@)i~5pu{A>}K0RB)Zj7>C!>c@U8DpASaKvQmw=E7VZA%PTfAS|ne*Lo z7)t1&f`We#DMF&5MnVb&p@4!4QBYBa28r;@e%$QG;V4xEnw6j1xtaH4-e=x<$ChVr z{f(_l^hJAv;CY&m^yZbltDoOmdA~(KEJLcJza=d%d;mo@j#|L&0yH3zn z_;6vc_j(+%Nt_<^UUNd$eT5yeAWlLSiQb+++zZCc=d*a+Z{z&#mQB`<88U6*3dcTUq&&s@Eyh8EBaXa+O`ngPv#WL@|Nj5=DMEe#ZUQ%eF7VrvgnS3w06qh*180CctAu<5d;$pI0N4Re0DnIL zJ>VDMXW%E`3*ZCbEnp3}`#2$A0`CH+fFBu)ZDpo5T{GS;vx$fk+<0RH~BIs=**{^)Tnuy zBASWsiIGXy=oF}pdUCkd!vZJ4y+e!6nwDk|9Wj4664KPHWlD}OGgTy8w0its>Kota2N)a-z2SDwNbmrR&on?!nr_)JaCZ%k4oTyNzl}DUB?M>Xh378AUv9 znO@v3^|{Su{g59OvSgN>E=2}O%Z17^DOp$_IlPj;r8e)FN*Xl*1tOQnG^-rsMDNEb zHRK}s9`&PzKyD$|E>44fgZ|Q%MX$RfCmJ$u%i{&>*oyh~Q&qhB3drB+Nsr1 zOm}YE3*MxHMbW_}J7rGP%fO;?NRn!Dijjp3>Oo$*Hc`Ye;ruCg&L&Nr$cw|R=(3E> z2>oaqo64f0GnEZfsbsZz6M2Uc&3Ef+I3DtTJFgktv*tCWnI9rcTwN|s7dXqC6?YyA zZFbz`o(vOZ6msB)d9WWBIbd7R#A-Mx;e+>2tK0 p0HRqs2QEX+a;r1ujB=6suIQYjBr7cW9eR7G_zeQGShnoU`Ui?zJxTxo literal 0 HcmV?d00001 diff --git a/src/systems/.render.js.swp b/src/systems/.render.js.swp new file mode 100644 index 0000000000000000000000000000000000000000..741856ad7eaad92da8fef728b8ad5fafbfd02426 GIT binary patch literal 12288 zcmeI2&2G~`5XZNGxIh8H4J4Qbsd7-VDMg@)Dn%3ut@x^F;Zjv-ZEq4cw%6L-P=zY= z3petWcjo2F6PV+(46k#Hb-%8= zA3uGcc++4kRBaJ=da+GoW3I<(KT}^6M*53Nb$O^f5gtr@u5hNgd#&%CJcKkFJkN^KKfB*kD%h+esd(=DB0_p_n z%NfR&QP)rv)D-IHB(|d-p)RAoq1Ol0D(V4h0d)&?6Lkf333U>cjd=u_QOQJr2oM1x zKm>>Y5g-CY;0O~K%rgKjZBNIr1HHr-RzlV|z`!sR%WYVb)~U|3ta*SBX&4~yHu?mB zhj|0r=ZVlZ@Itwk=)g+uYq9OfP$YO(cs+<@4bqmiM0(YEV5vuX4M2uQLeK)Iu;~bM zPeqA}@!hGErlwM@!Vb%FvOjG+PRvad6g`)-acXlQ(BA^A|FRd^~k zb~r6)!Vc&BU@eIc@>%q$TnlJx7NjX;v!P4^#E*~u-RKj0P6Y;~q zTJK&v5LRBi+^y>D<36-V`R&QaPDd?`aBIgj;MiKz)4pn z&m8H9iO<|E=~>>DeUtM { entity.removeComponent("momentum"); } else { entitiesToPush.map((e) => { -// const particles = game.createBorderParticles({ -// colors: ["#16f7c9", "#0d6e5a", "#2fa18a", "#48cfb4", "#58877d", "#178054", "#2cdb92"], -// maxSpeed: 0.20, -// minRadius: 1, -// maxRadius: 3, -// minLife: 100, -// maxLife: 300, -// minAmount: 20, -// maxAmount: 50, -// }); -// particles.addComponent(game.components.Position(e.components.position)); -// particles.addComponent(game.components.Appearance({width: game.canvas.width / game.config.xDim, height: game.canvas.height / game.config.yDim})); -// game.entities[particles.id] = particles; + const pushedParticleSpawner = game.createBorderParticles(); + pushedParticleSpawner.addComponent(game.components.Position(e.components.position)); + pushedParticleSpawner.addComponent(game.components.Appearance({width: game.canvas.width / game.config.xDim, height: game.canvas.height / game.config.yDim})); + game.entities[pushedParticleSpawner.id] = pushedParticleSpawner; + e.addComponent(game.components.Momentum({...momentum})) }); } diff --git a/src/systems/keyboardInput.js b/src/systems/keyboardInput.js index 50afda1..80feeef 100644 --- a/src/systems/keyboardInput.js +++ b/src/systems/keyboardInput.js @@ -33,4 +33,4 @@ game.system.KeyboardInput = (undoSystem) => { }; window.addEventListener("keydown", keyPress); return { keys, update }; -} \ No newline at end of file +} diff --git a/src/systems/particle.js b/src/systems/particle.js new file mode 100644 index 0000000..e58c0a0 --- /dev/null +++ b/src/systems/particle.js @@ -0,0 +1,57 @@ +game.system.Particle = () => { + "use strict"; + const particleSpawners = {}; + + const particleSpawner = ({colors, maxAmount, minAmount, minLife, maxLife, minRadius, maxRadius, maxSpeed, spawnFunction}) => { + return Array(randomInRange(minAmount, maxAmount)).fill(0).map(() => { + let particleSpec = { + x: Math.random(), + y: Math.random(), + dx: Math.random() * maxSpeed - maxSpeed / 2, + dy: Math.random() * maxSpeed - maxSpeed / 2, + radius: randomInRange(minRadius, maxRadius), + color: colors[randomInRange(0, colors.length-1)], + lifetime: randomInRange(minLife, maxLife), + elapsed: 0, + }; + if (spawnFunction) { + particleSpec = {...particleSpec, ...spawnFunction(particleSpec)}; + } + return particleSpec; + }); + } + + const update = (elapsedTime, entities, _changedIds) => { + for (let id in entities) { + const entity = entities[id]; + if (entity.hasComponent("particles")) { + if (!particleSpawners[entity.id]) { + particleSpawners[entity.id] = particleSpawner(entity.components.particles.spec.spec); + entities[id].particleSprite = game.graphics.Sprite({ + drawFunction: (elapsedTime, {x, y, width, height}, context) => { + let particleSpawner = particleSpawners[entity.id]; + particleSpawner.map((particleSpec) => particleSpec.elapsed += elapsedTime); + particleSpawners[id] = particleSpawner.filter((particleSpec) => particleSpec.lifetime > particleSpec.elapsed); + particleSpawner = particleSpawners[id]; + if (particleSpawner.length === 0) { + entities[id].removeComponent("alive"); + } + particleSpawner.map((particleSpec) => { + const position = {x: (particleSpec.x * width) + x + particleSpec.dx * particleSpec.elapsed, y: (particleSpec.y * height) + y + particleSpec.dy * particleSpec.elapsed}; + const fill = context.fillStyle; + context.fillStyle = particleSpec.color; + context.beginPath(); + context.arc(position.x, position.y, particleSpec.radius, 0, 2 * Math.PI); + context.fill(); + context.fillStyle = fill; + }); + } + }); + } + } + } + return new Set(); + }; + + return { update }; +}; diff --git a/src/systems/render.js b/src/systems/render.js index d3bacb8..adc8355 100644 --- a/src/systems/render.js +++ b/src/systems/render.js @@ -10,12 +10,17 @@ game.system.Render = (graphics) => { }); sortedEntities.forEach((entity) => { - if (entity.hasComponent("position") && entity.hasComponent("appearance") && entity.hasComponent("sprite")) { - game.sprites[entity.components.sprite.spriteName].draw(elapsedTime, {...entity.components.position, ...entity.components.appearance}); + if (entity.hasComponent("position") && entity.hasComponent("appearance")) { + const drawSpec = {...entity.components.position, ...entity.components.appearance}; + if (entity.hasComponent("sprite")) { + game.sprites[entity.components.sprite.spriteName].draw(elapsedTime, drawSpec); + } else if (entity.hasComponent("particles")) { + entity.particleSprite.draw(elapsedTime, drawSpec); + } } }); return new Set(); } return { update }; -}; \ No newline at end of file +}; diff --git a/styles/style.css b/styles/style.css index 7cfa5c7..500b365 100644 --- a/styles/style.css +++ b/styles/style.css @@ -19,7 +19,7 @@ body { border: 3px solid grey; border-radius: 5px; max-width: 100%; - background-color: rgba(0, 0, 0, 0.95); + background-color: rgba(0, 0, 25, 0.9); } .game-hud { @@ -69,4 +69,4 @@ body { .menu-button:hover { background-color: #d0d0d0; -} \ No newline at end of file +}