diff --git a/src/.game.js.swp b/src/.game.js.swp new file mode 100644 index 0000000..4383ff4 Binary files /dev/null and b/src/.game.js.swp differ diff --git a/src/bootstrap.js b/src/bootstrap.js index 64a79ac..164a28b 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -14,7 +14,7 @@ game.bootstrap = (() => { '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 0000000..c55b959 Binary files /dev/null and b/src/entities/.borderParticles.js.swp differ 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 0000000..40fcae8 Binary files /dev/null and b/src/systems/.collision.js.swp differ diff --git a/src/systems/.particle.js.swp b/src/systems/.particle.js.swp new file mode 100644 index 0000000..ab5d138 Binary files /dev/null and b/src/systems/.particle.js.swp differ diff --git a/src/systems/.render.js.swp b/src/systems/.render.js.swp new file mode 100644 index 0000000..741856a Binary files /dev/null and b/src/systems/.render.js.swp differ diff --git a/src/systems/collision.js b/src/systems/collision.js index 08a1d91..0070ee7 100644 --- a/src/systems/collision.js +++ b/src/systems/collision.js @@ -39,19 +39,11 @@ game.system.Collision = (entitiesGrid) => { 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 +}