Checkpoint with particles

This commit is contained in:
Logan Hunt 2022-04-05 17:33:25 -06:00
parent 545e129c74
commit 69596ba244
Signed by untrusted user who does not match committer: simponic
GPG Key ID: 52B3774857EB24B1
30 changed files with 129 additions and 16 deletions

View File

@ -9,9 +9,11 @@
<div style="text-align:center"> <div style="text-align:center">
<div class="canvas-holder"> <div class="canvas-holder">
<canvas id="game-canvas" width="1000" height="1000"></canvas> <canvas id="game-canvas" width="1000" height="1000"></canvas>
<!--
<div class="game-hud" id="hud"> <div class="game-hud" id="hud">
<p>Hello, world!</p> <p>Hello, world!</p>
</div> </div>
-->
<div class="menu" style="display: none" id="menu"> <div class="menu" style="display: none" id="menu">
</div> </div>
</div> </div>

View File

@ -29,8 +29,8 @@ hhhhhhhhhhhhhhhhhhhh
wwwwwwwwwwww wwwwwwwwwwww
r r
b r f r f
r b r
wwwwwwwwwwww wwwwwwwwwwww
BIY FIX BIY FIX

13
src/bootstrap.js vendored
View File

@ -1,13 +1,19 @@
game.bootstrap = (() => { game.bootstrap = (() => {
const scripts = [ const scripts = [
{ src: ['src/utils/objectEquivalence.js', 'src/utils/unitizeVector.js', 'src/utils/clamp.js', 'src/utils/loadLevel.js'], id: 'utils'}, {
src: [
'src/utils/objectEquivalence.js', 'src/utils/unitizeVector.js', 'src/utils/clamp.js', 'src/utils/loadLevel.js',
'src/utils/randInRange.js'
],
id: 'utils'
},
{ src: ['src/render/graphics.js', 'src/render/sprites.js'], id: 'graphics' }, { src: ['src/render/graphics.js', 'src/render/sprites.js'], id: 'graphics' },
{ src: ['src/components/component.js'], id: 'component' }, { src: ['src/components/component.js'], id: 'component' },
{ {
src: [ src: [
'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/loadPriority.js', 'src/components/stop.js', 'src/components/alive.js',
], ],
id: 'components' id: 'components'
}, },
@ -18,7 +24,8 @@ game.bootstrap = (() => {
'src/entities/liquid.js', 'src/entities/rock.js', 'src/entities/wall.js', 'src/entities/wordBigBlue.js', 'src/entities/liquid.js', 'src/entities/rock.js', 'src/entities/wall.js', 'src/entities/wordBigBlue.js',
'src/entities/wordFlag.js', 'src/entities/wordIs.js', 'src/entities/wordKill.js', 'src/entities/wordLava.js', 'src/entities/wordFlag.js', 'src/entities/wordIs.js', 'src/entities/wordKill.js', 'src/entities/wordLava.js',
'src/entities/wordPush.js', 'src/entities/wordRock.js', 'src/entities/wordSink.js', 'src/entities/wordStop.js', 'src/entities/wordPush.js', 'src/entities/wordRock.js', 'src/entities/wordSink.js', 'src/entities/wordStop.js',
'src/entities/wordWall.js', 'src/entities/wordWater.js', 'src/entities/wordWin.js', 'src/entities/wordYou.js' 'src/entities/wordWall.js', 'src/entities/wordWater.js', 'src/entities/wordWin.js', 'src/entities/wordYou.js',
'src/entities/borderParticles.js'
], ],
id: 'entities' id: 'entities'
}, },

1
src/components/alive.js Normal file
View File

@ -0,0 +1 @@
game.components.Alive = () => game.Component('alive');

View File

@ -2,6 +2,7 @@ game.createBigBlue = () => {
const bigBlue = game.Entity(); const bigBlue = game.Entity();
bigBlue.addComponent(game.components.LoadPriority({priority: 1})); bigBlue.addComponent(game.components.LoadPriority({priority: 1}));
bigBlue.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); bigBlue.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
bigBlue.addComponent(game.components.Alive());
bigBlue.sprite = game.sprites.bigBlue; bigBlue.sprite = game.sprites.bigBlue;
// TODO: Remove this // TODO: Remove this

View File

@ -0,0 +1,55 @@
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,
};
switch (Math.floor(Math.random() * 4)) {
case 0:
particle.y = 0;
particle.dy = -Math.abs(particle.dy);
break;
case 1:
particle.x = 1;
particle.dx = Math.abs(particle.dx);
break;
case 2:
particle.y = 1;
particle.dy = Math.abs(particle.dy);
break;
case 3:
particle.x = 0;
particle.dx = -Math.abs(particle.dx);
break;
}
return particle;
});
particles.addComponent(game.components.LoadPriority({priority: 1}));
particles.addComponent(game.components.Alive());
particles.sprite = 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 particles;
}

View File

@ -13,7 +13,6 @@ game.Entity = (id=game.nextId++) => {
} }
}; };
return { return {
id, id,
components, components,

View File

@ -2,6 +2,7 @@ game.createFlag = () => {
const flag = game.Entity(); const flag = game.Entity();
flag.addComponent(game.components.LoadPriority({priority: 2})); flag.addComponent(game.components.LoadPriority({priority: 2}));
flag.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); flag.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
flag.addComponent(game.components.Alive());
flag.sprite = game.sprites.flag; flag.sprite = game.sprites.flag;
return flag; return flag;
} }

View File

@ -2,6 +2,7 @@ game.createFloor = () => {
const floor = game.Entity(); const floor = game.Entity();
floor.addComponent(game.components.LoadPriority({priority: 5})); floor.addComponent(game.components.LoadPriority({priority: 5}));
floor.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); floor.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
floor.addComponent(game.components.Alive());
floor.sprite = game.sprites.floor; floor.sprite = game.sprites.floor;
return floor; return floor;
} }

View File

@ -2,6 +2,7 @@ game.createGrass = () => {
const grass = game.Entity(); const grass = game.Entity();
grass.addComponent(game.components.LoadPriority({priority: 6})); grass.addComponent(game.components.LoadPriority({priority: 6}));
grass.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); grass.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
grass.addComponent(game.components.Alive());
grass.sprite = game.sprites.grass; grass.sprite = game.sprites.grass;
return grass; return grass;
} }

View File

@ -3,6 +3,7 @@ game.createHedge = () => {
hedge.addComponent(game.components.LoadPriority({priority: 6})); hedge.addComponent(game.components.LoadPriority({priority: 6}));
hedge.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); hedge.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
hedge.addComponent(game.components.Stop({stop: true})); hedge.addComponent(game.components.Stop({stop: true}));
hedge.addComponent(game.components.Alive());
hedge.sprite = game.sprites.hedge; hedge.sprite = game.sprites.hedge;
return hedge; return hedge;
} }

View File

@ -4,6 +4,7 @@ game.createLiquid = () => {
liquid.addComponent(game.components.LoadPriority({priority: 5})); liquid.addComponent(game.components.LoadPriority({priority: 5}));
liquid.addComponent(game.components.Position({x: 0, y: 0})); liquid.addComponent(game.components.Position({x: 0, y: 0}));
liquid.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); liquid.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
liquid.addComponent(game.components.Alive());
liquid.sprite = game.graphics.Sprite({ liquid.sprite = game.graphics.Sprite({
image: game.assets.liquid, image: game.assets.liquid,
spriteHeight: 24, spriteHeight: 24,

View File

@ -2,6 +2,7 @@ game.createRock = () => {
const rock = game.Entity(); const rock = game.Entity();
rock.addComponent(game.components.LoadPriority({priority: 2})); rock.addComponent(game.components.LoadPriority({priority: 2}));
rock.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); rock.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
rock.addComponent(game.components.Alive());
rock.sprite = game.sprites.rock; rock.sprite = game.sprites.rock;
//TODO: Remove this //TODO: Remove this

View File

@ -3,6 +3,7 @@ game.createWall = () => {
wall.addComponent(game.components.LoadPriority({priority: 3})); wall.addComponent(game.components.LoadPriority({priority: 3}));
wall.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wall.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
wall.addComponent(game.components.Stop({stop: true})); wall.addComponent(game.components.Stop({stop: true}));
wall.addComponent(game.components.Alive());
wall.sprite = game.sprites.wall; wall.sprite = game.sprites.wall;
return wall; return wall;
} }

View File

@ -3,6 +3,7 @@ game.createWordBigBlue = () => {
wordBigBlue.addComponent(game.components.LoadPriority({priority: 3})); wordBigBlue.addComponent(game.components.LoadPriority({priority: 3}));
wordBigBlue.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordBigBlue.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
wordBigBlue.addComponent(game.components.Pushable({pushable: true})); wordBigBlue.addComponent(game.components.Pushable({pushable: true}));
wordBigBlue.addComponent(game.components.Alive());
wordBigBlue.sprite = game.sprites.wordBigBlue; wordBigBlue.sprite = game.sprites.wordBigBlue;
return wordBigBlue; return wordBigBlue;
} }

View File

@ -3,6 +3,7 @@ game.createWordFlag = () => {
wordFlag.addComponent(game.components.LoadPriority({priority: 3})); wordFlag.addComponent(game.components.LoadPriority({priority: 3}));
wordFlag.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordFlag.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
wordFlag.addComponent(game.components.Pushable({pushable: true})); wordFlag.addComponent(game.components.Pushable({pushable: true}));
wordFlag.addComponent(game.components.Alive());
wordFlag.sprite = game.sprites.wordFlag; wordFlag.sprite = game.sprites.wordFlag;
return wordFlag; return wordFlag;
} }

View File

@ -3,6 +3,7 @@ game.createWordIs = () => {
wordIs.addComponent(game.components.LoadPriority({priority: 3})); wordIs.addComponent(game.components.LoadPriority({priority: 3}));
wordIs.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordIs.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
wordIs.addComponent(game.components.Stop({stop: true})); wordIs.addComponent(game.components.Stop({stop: true}));
wordIs.addComponent(game.components.Alive());
wordIs.sprite = game.sprites.wordIs; wordIs.sprite = game.sprites.wordIs;
return wordIs; return wordIs;
} }

View File

@ -3,6 +3,7 @@ game.createWordKill = () => {
wordKill.addComponent(game.components.LoadPriority({priority: 3})); wordKill.addComponent(game.components.LoadPriority({priority: 3}));
wordKill.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordKill.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
wordKill.addComponent(game.components.Pushable({pushable: true})); wordKill.addComponent(game.components.Pushable({pushable: true}));
wordKill.addComponent(game.components.Alive());
wordKill.sprite = game.sprites.wordKill; wordKill.sprite = game.sprites.wordKill;
return wordKill; return wordKill;
} }

View File

@ -3,6 +3,7 @@ game.createWordLava = () => {
wordLava.addComponent(game.components.LoadPriority({priority: 3})); wordLava.addComponent(game.components.LoadPriority({priority: 3}));
wordLava.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordLava.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
wordLava.addComponent(game.components.Pushable({pushable: true})); wordLava.addComponent(game.components.Pushable({pushable: true}));
wordLava.addComponent(game.components.Alive());
wordLava.sprite = game.sprites.wordLava; wordLava.sprite = game.sprites.wordLava;
return wordLava; return wordLava;

View File

@ -3,6 +3,7 @@ game.createWordPush = () => {
wordPush.addComponent(game.components.LoadPriority({priority: 3})); wordPush.addComponent(game.components.LoadPriority({priority: 3}));
wordPush.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordPush.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
wordPush.addComponent(game.components.Pushable({pushable: true})); wordPush.addComponent(game.components.Pushable({pushable: true}));
wordPush.addComponent(game.components.Alive());
wordPush.sprite = game.sprites.wordPush; wordPush.sprite = game.sprites.wordPush;
return wordPush; return wordPush;
} }

View File

@ -3,6 +3,7 @@ game.createWordRock = () => {
wordRock.addComponent(game.components.LoadPriority({priority: 3})); wordRock.addComponent(game.components.LoadPriority({priority: 3}));
wordRock.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordRock.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
wordRock.addComponent(game.components.Pushable({pushable: true})); wordRock.addComponent(game.components.Pushable({pushable: true}));
wordRock.addComponent(game.components.Alive());
wordRock.sprite = game.sprites.wordRock; wordRock.sprite = game.sprites.wordRock;
return wordRock; return wordRock;
} }

View File

@ -3,6 +3,7 @@ game.createWordSink = () => {
wordSink.addComponent(game.components.LoadPriority({priority: 3})); wordSink.addComponent(game.components.LoadPriority({priority: 3}));
wordSink.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordSink.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
wordSink.addComponent(game.components.Pushable({pushable: true})); wordSink.addComponent(game.components.Pushable({pushable: true}));
wordSink.addComponent(game.components.Alive());
wordSink.sprite = game.sprites.wordSink; wordSink.sprite = game.sprites.wordSink;
return wordSink; return wordSink;
} }

View File

@ -3,6 +3,7 @@ game.createWordStop = () => {
wordStop.addComponent(game.components.LoadPriority({priority: 3})); wordStop.addComponent(game.components.LoadPriority({priority: 3}));
wordStop.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordStop.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
wordStop.addComponent(game.components.Pushable({pushable: true})); wordStop.addComponent(game.components.Pushable({pushable: true}));
wordStop.addComponent(game.components.Alive());
wordStop.sprite = game.sprites.wordStop; wordStop.sprite = game.sprites.wordStop;
return wordStop; return wordStop;
} }

View File

@ -3,6 +3,7 @@ game.createWordWall = () => {
wordWall.addComponent(game.components.LoadPriority({priority: 3})); wordWall.addComponent(game.components.LoadPriority({priority: 3}));
wordWall.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordWall.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
wordWall.addComponent(game.components.Pushable({pushable: true})); wordWall.addComponent(game.components.Pushable({pushable: true}));
wordWall.addComponent(game.components.Alive());
wordWall.sprite = game.sprites.wordWall; wordWall.sprite = game.sprites.wordWall;
return wordWall; return wordWall;
} }

View File

@ -3,6 +3,7 @@ game.createWordWater = () => {
wordWater.addComponent(game.components.LoadPriority({priority: 3})); wordWater.addComponent(game.components.LoadPriority({priority: 3}));
wordWater.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordWater.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
wordWater.addComponent(game.components.Pushable({pushable: true})); wordWater.addComponent(game.components.Pushable({pushable: true}));
wordWater.addComponent(game.components.Alive());
wordWater.sprite = game.sprites.wordWater; wordWater.sprite = game.sprites.wordWater;
return wordWater; return wordWater;
} }

View File

@ -3,6 +3,7 @@ game.createWordWin = () => {
wordWin.addComponent(game.components.LoadPriority({priority: 3})); wordWin.addComponent(game.components.LoadPriority({priority: 3}));
wordWin.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordWin.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
wordWin.addComponent(game.components.Pushable({pushable: true})); wordWin.addComponent(game.components.Pushable({pushable: true}));
wordWin.addComponent(game.components.Alive());
wordWin.sprite = game.sprites.wordWin; wordWin.sprite = game.sprites.wordWin;
return wordWin; return wordWin;
} }

View File

@ -3,6 +3,7 @@ game.createWordYou = () => {
wordYou.addComponent(game.components.LoadPriority({priority: 3})); wordYou.addComponent(game.components.LoadPriority({priority: 3}));
wordYou.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordYou.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100}));
wordYou.addComponent(game.components.Pushable({pushable: true})); wordYou.addComponent(game.components.Pushable({pushable: true}));
wordYou.addComponent(game.components.Alive());
wordYou.sprite = game.sprites.wordYou; wordYou.sprite = game.sprites.wordYou;
return wordYou; return wordYou;
} }

View File

@ -3,10 +3,17 @@ game.loop = (timeStamp) => {
let elapsedTime = timeStamp - lastTimeStamp; let elapsedTime = timeStamp - lastTimeStamp;
lastTimeStamp = timeStamp; lastTimeStamp = timeStamp;
game.systemOrder.map((i) => { game.systemOrder.map((i) => {
game.systems[i].update(elapsedTime, game.entities); game.systems[i].update(elapsedTime, game.entities);
}); });
for (let id in game.entities) {
if (!game.entities[id].hasComponent("alive")) {
delete game.entities[id];
}
}
if (game.nextLevel) { if (game.nextLevel) {
game.loadLevel(game.nextLevel); game.loadLevel(game.nextLevel);
game.nextLevel = false; game.nextLevel = false;
@ -26,7 +33,6 @@ game.initialize = () => {
keyboardInput: game.system.KeyboardInput(), keyboardInput: game.system.KeyboardInput(),
}; };
lastTimeStamp = performance.now() lastTimeStamp = performance.now()
requestAnimationFrame(game.loop); requestAnimationFrame(game.loop);
} }

View File

@ -52,6 +52,8 @@ game.system.GridSystem = ({ xDim, yDim }) => {
}); });
const proposed = {...newGridCoords}; const proposed = {...newGridCoords};
let wall = false;
let entitiesToPush = [];
if (entity.hasComponent("controllable")) { if (entity.hasComponent("controllable")) {
let found = false; let found = false;
do { do {
@ -60,7 +62,12 @@ game.system.GridSystem = ({ xDim, yDim }) => {
for (let entity of entitiesInCell.values()) { for (let entity of entitiesInCell.values()) {
if (entity.hasComponent("pushable")) { if (entity.hasComponent("pushable")) {
found = true; found = true;
entity.addComponent(game.components.Momentum({...momentumVector})); entitiesToPush.push(entity);
}
if (entity.hasComponent("stop")) {
wall = true;
found = false;
break;
} }
} }
proposed.x += momentumVector.dx; proposed.x += momentumVector.dx;
@ -72,17 +79,28 @@ game.system.GridSystem = ({ xDim, yDim }) => {
} while (found); } while (found);
} }
if (entity.hasComponent("pushable") || entity.hasComponent("controllable")) { if (entity.hasComponent("controllable")) {
for (let e of entitiesGrid[newGridCoords.y][newGridCoords.x].values()) { if (!wall) {
if (e.hasComponent("stop")) { entity.components.gridPosition = {...entity.components.gridPosition, ...newGridCoords};
newGridCoords = oldGridCoords; entitiesToPush.map((e) => e.addComponent(game.components.Momentum({...momentumVector})));
break;
} }
} const particles = game.createBorderParticles({
entity.addComponent(game.components.Momentum({...momentumVector})); colors: ["#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF"],
maxAmount: 100,
minAmount: 25,
minLife: 100,
maxLife: 300,
minRadius: 1,
maxRadius: 3,
maxSpeed: 0.15,
});
particles.addComponent(game.components.Position(gridCoordsToGame(oldGridCoords)));
particles.addComponent(game.components.Appearance({width: 50, height: 50}));
game.entities[particles.id] = particles;
} else {
entity.components.gridPosition = {...entity.components.gridPosition, ...newGridCoords};
} }
entity.components.gridPosition = {...entity.components.gridPosition, ...newGridCoords};
entity.components.position = { entity.components.position = {
...entity.components.position, ...entity.components.position,

4
src/utils/randInRange.js Normal file
View File

@ -0,0 +1,4 @@
const randomInRange = (min, max) => {
// min <= random number <= max
return Math.floor(Math.random() * (max - min + 1)) + min;
}