Move particle stuff to a system to simplify spawning particles

This commit is contained in:
Logan Hunt 2022-04-11 16:55:16 -06:00
parent ec7b01918c
commit 491f532750
Signed by untrusted user who does not match committer: simponic
GPG Key ID: 52B3774857EB24B1
14 changed files with 107 additions and 67 deletions

BIN
src/.game.js.swp Normal file

Binary file not shown.

4
src/bootstrap.js vendored
View File

@ -14,7 +14,7 @@ game.bootstrap = (() => {
'src/components/position.js', 'src/components/momentum.js', 'src/components/gridPosition.js', '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/appearence.js', 'src/components/controllable.js', 'src/components/pushable.js',
'src/components/loadPriority.js', 'src/components/stop.js', 'src/components/alive.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' id: 'components'
}, },
@ -34,7 +34,7 @@ game.bootstrap = (() => {
{ {
src: [ src: [
'src/systems/render.js', 'src/systems/grid.js', 'src/systems/physics.js', 'src/systems/keyboardInput.js', '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' }, id: 'systems' },
{ src: ['src/game.js'], id: 'game' }, { src: ['src/game.js'], id: 'game' },

View File

@ -0,0 +1 @@
game.components.Particles = (spec) => game.Component('particles', {spec});

Binary file not shown.

View File

@ -1,56 +1,40 @@
game.createBorderParticles = ({colors, maxAmount, minAmount, minLife, maxLife, minRadius, maxRadius, maxSpeed}) => { game.createBorderParticles = () => {
const particles = game.Entity(); const particleSpawner = game.Entity();
let particleSpecs = Array(randomInRange(minAmount, maxAmount)).fill(0).map(() => { const spawnFunction = (particleSpec) => {
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,
};
switch (Math.floor(Math.random() * 4)) { switch (Math.floor(Math.random() * 4)) {
case 0: case 0:
particle.y = 0; particleSpec.y = 0;
particle.dy = -Math.abs(particle.dy); particleSpec.dy = -Math.abs(particleSpec.dy);
break; break;
case 1: case 1:
particle.x = 1; particleSpec.x = 1;
particle.dx = Math.abs(particle.dx); particleSpec.dx = Math.abs(particleSpec.dx);
break; break;
case 2: case 2:
particle.y = 1; particleSpec.y = 1;
particle.dy = Math.abs(particle.dy); particleSpec.dy = Math.abs(particleSpec.dy);
break; break;
case 3: case 3:
particle.x = 0; particleSpec.x = 0;
particle.dx = -Math.abs(particle.dx); particleSpec.dx = -Math.abs(particleSpec.dx);
break; break;
} }
return particle; return particleSpec;
}); };
game.sprites.borderParticle = game.graphics.Sprite({ particleSpawner.addComponent(game.components.Particles({
drawFunction: (elapsedTime, {x, y, width, height}, context) => { spec: {
particleSpecs.map((spec) => spec.elapsed += elapsedTime); spawnFunction,
particleSpecs = particleSpecs.filter((spec) => spec.lifetime > spec.elapsed); colors: ["#16f7c9", "#0d6e5a", "#2fa18a", "#48cfb4", "#58877d", "#178054", "#2cdb92"],
if (particleSpecs.length === 0) { maxSpeed: 0.20,
particles.removeComponent("alive"); minRadius: 1,
} maxRadius: 3,
particleSpecs.map((spec) => { minLife: 100,
const position = {x: (spec.x * width) + x + spec.dx * spec.elapsed, y: (spec.y * height) + y + spec.dy * spec.elapsed}; maxLife: 300,
const fill = context.fillStyle; minAmount: 20,
context.fillStyle = spec.color; maxAmount: 50,
context.beginPath();
context.arc(position.x, position.y, spec.radius, 0, 2 * Math.PI);
context.fill();
context.fillStyle = fill;
});
} }
}) }));
particles.addComponent(game.components.LoadPriority({priority: 1})); particleSpawner.addComponent(game.components.LoadPriority({priority: 1}));
particles.addComponent(game.components.Alive()); particleSpawner.addComponent(game.components.Alive());
particles.addComponent(game.components.Sprite({spriteName: "borderParticle"})) return particleSpawner;
return particles;
} }

View File

@ -26,7 +26,7 @@ game.initialize = () => {
// Maintained by gridSystem as a side-effect // 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.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 = { };
game.systems.physics = game.system.Physics(), game.systems.physics = game.system.Physics(),
game.systems.gridSystem = game.system.Grid(game.entitiesGrid); game.systems.gridSystem = game.system.Grid(game.entitiesGrid);
@ -34,6 +34,7 @@ game.initialize = () => {
game.systems.render = game.system.Render(game.graphics); game.systems.render = game.system.Render(game.graphics);
game.systems.undo = game.system.Undo(game.entitiesGrid); game.systems.undo = game.system.Undo(game.entitiesGrid);
game.systems.keyboardInput = game.system.KeyboardInput(game.systems.undo); game.systems.keyboardInput = game.system.KeyboardInput(game.systems.undo);
game.systems.particle = game.system.Particle(game.canvas.context);
lastTimeStamp = performance.now() lastTimeStamp = performance.now()
requestAnimationFrame(game.loop); requestAnimationFrame(game.loop);

Binary file not shown.

Binary file not shown.

BIN
src/systems/.render.js.swp Normal file

Binary file not shown.

View File

@ -39,19 +39,11 @@ game.system.Collision = (entitiesGrid) => {
entity.removeComponent("momentum"); entity.removeComponent("momentum");
} else { } else {
entitiesToPush.map((e) => { entitiesToPush.map((e) => {
// const particles = game.createBorderParticles({ const pushedParticleSpawner = game.createBorderParticles();
// colors: ["#16f7c9", "#0d6e5a", "#2fa18a", "#48cfb4", "#58877d", "#178054", "#2cdb92"], pushedParticleSpawner.addComponent(game.components.Position(e.components.position));
// maxSpeed: 0.20, pushedParticleSpawner.addComponent(game.components.Appearance({width: game.canvas.width / game.config.xDim, height: game.canvas.height / game.config.yDim}));
// minRadius: 1, game.entities[pushedParticleSpawner.id] = pushedParticleSpawner;
// 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;
e.addComponent(game.components.Momentum({...momentum})) e.addComponent(game.components.Momentum({...momentum}))
}); });
} }

57
src/systems/particle.js Normal file
View File

@ -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 };
};

View File

@ -10,8 +10,13 @@ game.system.Render = (graphics) => {
}); });
sortedEntities.forEach((entity) => { sortedEntities.forEach((entity) => {
if (entity.hasComponent("position") && entity.hasComponent("appearance") && entity.hasComponent("sprite")) { if (entity.hasComponent("position") && entity.hasComponent("appearance")) {
game.sprites[entity.components.sprite.spriteName].draw(elapsedTime, {...entity.components.position, ...entity.components.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);
}
} }
}); });

View File

@ -19,7 +19,7 @@ body {
border: 3px solid grey; border: 3px solid grey;
border-radius: 5px; border-radius: 5px;
max-width: 100%; max-width: 100%;
background-color: rgba(0, 0, 0, 0.95); background-color: rgba(0, 0, 25, 0.9);
} }
.game-hud { .game-hud {