diff --git a/src/bootstrap.js b/src/bootstrap.js index c15bf53..4519ed2 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -18,7 +18,9 @@ game.bootstrap = (() => { '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/particles.js', 'src/components/noun.js', - 'src/components/name.js', 'src/components/verb.js', + 'src/components/name.js', 'src/components/verb.js', 'src/components/burn.js', + 'src/components/burnable.js', 'src/components/sink.js', 'src/components/sinkable.js', + 'src/components/win.js', ], id: 'components' }, diff --git a/src/components/burn.js b/src/components/burn.js new file mode 100644 index 0000000..f138e9d --- /dev/null +++ b/src/components/burn.js @@ -0,0 +1 @@ +game.components.Burn = () => game.Component('burn', {}); \ No newline at end of file diff --git a/src/components/burnable.js b/src/components/burnable.js new file mode 100644 index 0000000..d5767e7 --- /dev/null +++ b/src/components/burnable.js @@ -0,0 +1 @@ +game.components.Burnable = () => game.Component('burnable', {}); \ No newline at end of file diff --git a/src/components/sink.js b/src/components/sink.js new file mode 100644 index 0000000..3a4d9dc --- /dev/null +++ b/src/components/sink.js @@ -0,0 +1 @@ +game.components.Sink = () => game.Component('sink', {}); \ No newline at end of file diff --git a/src/components/sinkable.js b/src/components/sinkable.js new file mode 100644 index 0000000..1fcb132 --- /dev/null +++ b/src/components/sinkable.js @@ -0,0 +1 @@ +game.components.Sinkable = () => game.Component('sinkable', {}); \ No newline at end of file diff --git a/src/components/win.js b/src/components/win.js new file mode 100644 index 0000000..ea905fc --- /dev/null +++ b/src/components/win.js @@ -0,0 +1 @@ +game.components.Win = () => game.Component('win', {}); \ No newline at end of file diff --git a/src/entities/bigblue.js b/src/entities/bigblue.js index bcf80d5..45fbc90 100644 --- a/src/entities/bigblue.js +++ b/src/entities/bigblue.js @@ -4,9 +4,10 @@ game.createBigBlue = () => { bigBlue.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); bigBlue.addComponent(game.components.Alive()); bigBlue.addComponent(game.components.Sprite({spriteName: "bigBlue"})); - // bigBlue.addComponent(game.components.Controllable({controls: ['left', 'right', 'up', 'down']})); bigBlue.addComponent(game.components.Name({selector: "bigblue"})); + bigBlue.addComponent(game.components.Burnable()); + bigBlue.addComponent(game.components.Sinkable()); return bigBlue; }; diff --git a/src/entities/borderParticles.js b/src/entities/borderParticles.js index 260071d..e1a7e98 100644 --- a/src/entities/borderParticles.js +++ b/src/entities/borderParticles.js @@ -1,4 +1,4 @@ -game.createBorderParticles = () => { +game.createBorderParticles = (spawnerSpec) => { const particleSpawner = game.Entity(); const spawnFunction = (particleSpec) => { switch (Math.floor(Math.random() * 4)) { @@ -24,7 +24,7 @@ game.createBorderParticles = () => { particleSpawner.addComponent(game.components.Particles({ spec: { spawnFunction, - colors: ["#16f7c9", "#0d6e5a", "#2fa18a", "#48cfb4", "#58877d", "#178054", "#2cdb92"], + colors: ["#666666", "#777777", "#888888", "#999999"], maxSpeed: 0.20, minRadius: 1, maxRadius: 3, @@ -32,6 +32,7 @@ game.createBorderParticles = () => { maxLife: 300, minAmount: 20, maxAmount: 50, + ...spawnerSpec, } })); particleSpawner.addComponent(game.components.LoadPriority({priority: 1})); diff --git a/src/entities/flag.js b/src/entities/flag.js index e13d2a2..831922f 100644 --- a/src/entities/flag.js +++ b/src/entities/flag.js @@ -4,5 +4,6 @@ game.createFlag = () => { flag.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); flag.addComponent(game.components.Alive()); flag.addComponent(game.components.Sprite({spriteName: "flag"})) + flag.addComponent(game.components.Name({selector: "flag"})); return flag; } diff --git a/src/entities/lava.js b/src/entities/lava.js index 4a88f69..e529812 100644 --- a/src/entities/lava.js +++ b/src/entities/lava.js @@ -4,6 +4,6 @@ game.createLava = () => { lava.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); lava.addComponent(game.components.Alive()); lava.addComponent(game.components.Sprite({spriteName: "lava"})) - + lava.addComponent(game.components.Name({selector: "lava"})); return lava; } diff --git a/src/entities/rock.js b/src/entities/rock.js index 6a28f6e..a87710a 100644 --- a/src/entities/rock.js +++ b/src/entities/rock.js @@ -8,6 +8,7 @@ game.createRock = () => { // rock.addComponent(game.components.Pushable()); rock.addComponent(game.components.Name({selector: "rock"})); + rock.addComponent(game.components.Sinkable()); return rock; }; diff --git a/src/entities/water.js b/src/entities/water.js index 7c160b0..11522b1 100644 --- a/src/entities/water.js +++ b/src/entities/water.js @@ -4,5 +4,6 @@ game.createWater = () => { water.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); water.addComponent(game.components.Alive()); water.addComponent(game.components.Sprite({spriteName: "water"})) + water.addComponent(game.components.Name({selector: "water"})) return water; } diff --git a/src/entities/wordFlag.js b/src/entities/wordFlag.js index bc2d782..79617ea 100644 --- a/src/entities/wordFlag.js +++ b/src/entities/wordFlag.js @@ -4,6 +4,7 @@ game.createWordFlag = () => { wordFlag.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordFlag.addComponent(game.components.Pushable({pushable: true})); wordFlag.addComponent(game.components.Alive()); - wordFlag.addComponent(game.components.Sprite({spriteName: "wordFlag"})) + wordFlag.addComponent(game.components.Sprite({spriteName: "wordFlag"})); + wordFlag.addComponent(game.components.Noun({select: "flag"})); return wordFlag; } diff --git a/src/entities/wordKill.js b/src/entities/wordKill.js index 8ea04d9..6906e9c 100644 --- a/src/entities/wordKill.js +++ b/src/entities/wordKill.js @@ -5,5 +5,6 @@ game.createWordKill = () => { wordKill.addComponent(game.components.Pushable({pushable: true})); wordKill.addComponent(game.components.Alive()); wordKill.addComponent(game.components.Sprite({spriteName: "wordKill"})) + wordKill.addComponent(game.components.Verb({action: "burn"})); return wordKill; } diff --git a/src/entities/wordLava.js b/src/entities/wordLava.js index bb7a005..cf31286 100644 --- a/src/entities/wordLava.js +++ b/src/entities/wordLava.js @@ -6,5 +6,6 @@ game.createWordLava = () => { wordLava.addComponent(game.components.Alive()); wordLava.addComponent(game.components.Sprite({spriteName: "wordLava"})) + wordLava.addComponent(game.components.Noun({select: "lava"})); return wordLava; } diff --git a/src/entities/wordSink.js b/src/entities/wordSink.js index decd480..369f922 100644 --- a/src/entities/wordSink.js +++ b/src/entities/wordSink.js @@ -4,6 +4,7 @@ game.createWordSink = () => { wordSink.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordSink.addComponent(game.components.Pushable({pushable: true})); wordSink.addComponent(game.components.Alive()); - wordSink.addComponent(game.components.Sprite({spriteName: "wordSink"})) + wordSink.addComponent(game.components.Sprite({spriteName: "wordSink"})); + wordSink.addComponent(game.components.Verb({action: "sink"})); return wordSink; } diff --git a/src/entities/wordWater.js b/src/entities/wordWater.js index c6404bf..eb0c1be 100644 --- a/src/entities/wordWater.js +++ b/src/entities/wordWater.js @@ -4,6 +4,7 @@ game.createWordWater = () => { wordWater.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordWater.addComponent(game.components.Pushable({pushable: true})); wordWater.addComponent(game.components.Alive()); - wordWater.addComponent(game.components.Sprite({spriteName: "wordWater"})) + wordWater.addComponent(game.components.Sprite({spriteName: "wordWater"})); + wordWater.addComponent(game.components.Noun({select: "water"})); return wordWater; } diff --git a/src/entities/wordWin.js b/src/entities/wordWin.js index ed837d0..e8948ee 100644 --- a/src/entities/wordWin.js +++ b/src/entities/wordWin.js @@ -4,6 +4,7 @@ game.createWordWin = () => { wordWin.addComponent(game.components.Appearance({rot: 0, width: 100, height: 100})); wordWin.addComponent(game.components.Pushable({pushable: true})); wordWin.addComponent(game.components.Alive()); - wordWin.addComponent(game.components.Sprite({spriteName: "wordWin"})) + wordWin.addComponent(game.components.Sprite({spriteName: "wordWin"})); + wordWin.addComponent(game.components.Verb({action: "win"})); return wordWin; } diff --git a/src/systems/collision.js b/src/systems/collision.js index d769636..013ae1e 100644 --- a/src/systems/collision.js +++ b/src/systems/collision.js @@ -2,50 +2,83 @@ game.system.Collision = (entitiesGrid) => { const update = (elapsedTime, entities, changedIds) => { const thisChangedIds = new Set(); for (let entity of Object.keys(entities).map((id) => entities[id])) { - if (entity.hasComponent("controllable") && entity.hasComponent("gridPosition") && entity.hasComponent("momentum")) { - const momentum = unitize(entity.components.momentum); - - let found; - const proposed = {x: entity.components.gridPosition.x + momentum.dx, y: entity.components.gridPosition.y + momentum.dy}; - const entitiesToPush = []; - let wall = false; - do { - const proposedClampedInBounds = clamp(proposed, game.config.xDim-1, game.config.yDim-1); - if (!equivalence(proposed, proposedClampedInBounds)) { - break; - } - - found = false; - - const entitiesInCell = entitiesGrid[proposed.y][proposed.x]; - - for (let next of entitiesInCell.values()) { - if (next.hasComponent("stop")) { - wall = next; - found = false; + if (entity.hasComponent("position") && entity.hasComponent("gridPosition") && (entity.hasComponent("burnable") || entity.hasComponent("sinkable")) && entity.hasComponent("alive")) { + for (let collided of entitiesGrid[entity.components.gridPosition.y][entity.components.gridPosition.x].values()) { + if (!equivalence(entity, collided) && collided.hasComponent("alive")){ + if (entity.hasComponent("burnable") && collided.hasComponent("burn")) { + const burnedParticleSpawner = game.createBorderParticles({colors: ["#f58d42", "#d6600b", "#c7a312", "#f2b844"]}); + burnedParticleSpawner.addComponent(game.components.Position(collided.components.position)); + burnedParticleSpawner.addComponent(game.components.Appearance({width: game.canvas.width / game.config.xDim, height: game.canvas.height / game.config.yDim})); + game.entities[burnedParticleSpawner.id] = burnedParticleSpawner; + entity.removeComponent("alive"); + break; + } else if (entity.hasComponent("sinkable") && collided.hasComponent("sink")) { + const sunkParticleSpawner = game.createBorderParticles({colors: ["#16f7c9", "#0d6e5a", "#2fa18a", "#48cfb4", "#58877d", "#178054", "#2cdb92"]}); + sunkParticleSpawner.addComponent(game.components.Position(collided.components.position)); + sunkParticleSpawner.addComponent(game.components.Appearance({width: game.canvas.width / game.config.xDim, height: game.canvas.height / game.config.yDim})); + game.entities[sunkParticleSpawner.id] = sunkParticleSpawner; + entity.removeComponent("alive"); + collided.removeComponent("alive"); break; } - if (next.hasComponent("pushable")) { - entitiesToPush.push(next); - found = true; - } } + } + } + if (entity.hasComponent("controllable") && entity.hasComponent("gridPosition")) { + for (let collided of entitiesGrid[entity.components.gridPosition.y][entity.components.gridPosition.x].values()) { + if (collided.hasComponent("win")) { + game.systems.menu.bringUpMenu(); + game.systems.menu.setState("levelSelect"); + } + } - proposed.x += momentum.dx; - proposed.y += momentum.dy; - } while(found); + if (entity.hasComponent("momentum")) { + const momentum = unitize(entity.components.momentum); - if (wall) { - entity.removeComponent("momentum"); - } else { - entitiesToPush.map((e) => { - 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; + let found; + const proposed = {x: entity.components.gridPosition.x + momentum.dx, y: entity.components.gridPosition.y + momentum.dy}; + const entitiesToPush = []; + let wall = false; + do { + const proposedClampedInBounds = clamp(proposed, game.config.xDim-1, game.config.yDim-1); + if (!equivalence(proposed, proposedClampedInBounds)) { + break; + } - e.addComponent(game.components.Momentum({...momentum})); - }); + found = false; + + const entitiesInCell = entitiesGrid[proposed.y][proposed.x]; + + for (let next of entitiesInCell.values()) { + if (next.hasComponent("alive")) { + if (next.hasComponent("stop")) { + wall = next; + found = false; + break; + } + if (next.hasComponent("pushable")) { + entitiesToPush.push(next); + found = true; + } + } + } + + proposed.x += momentum.dx; + proposed.y += momentum.dy; + } while(found); + + if (wall) { + entity.removeComponent("momentum"); + } else { + entitiesToPush.map((e) => { + const pushedParticleSpawner = game.createBorderParticles({maxSpeed: 0.1, minAmount: 10, maxAmount: 15}); + 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 06a73c9..1b399ca 100644 --- a/src/systems/keyboardInput.js +++ b/src/systems/keyboardInput.js @@ -12,7 +12,7 @@ game.system.KeyboardInput = () => { const update = (elapsedTime, entities, changedIds) => { for (let id in entities) { const entity = entities[id]; - if (entity.hasComponent('controllable')) { + if (entity.hasComponent('controllable') && entity.hasComponent('alive')) { const controls = entity.components.controllable.controls; if (!changedIds.has(entity.id)) { if (controls.includes('left') && keys[game.controls.left]) { diff --git a/src/systems/logic.js b/src/systems/logic.js index 8e3bbc0..207fbc8 100644 --- a/src/systems/logic.js +++ b/src/systems/logic.js @@ -1,6 +1,7 @@ game.system.Logic = (entitiesGrid) => { "use strict"; let currentVerbRules = []; + let previousControllableIds = new Set(); const isWord = (entity) => entity.hasComponent("gridPosition") && (entity.hasComponent("verb") || entity.hasComponent("noun")); const getFirstWordEntity = (gridPosition) => { @@ -19,12 +20,16 @@ game.system.Logic = (entitiesGrid) => { "stop": game.components.Stop(), "push": game.components.Pushable(), "you": game.components.Controllable({controls: ['left', 'right', 'up', 'down']}), - + "burn": game.components.Burn(), + "sink": game.components.Sink(), + "win": game.components.Win(), }; const nounsToEntityCreators = { "rock": game.createRock, "wall": game.createWall, + "bigblue": game.createBigBlue, + "flag": game.createFlag, }; const doOnRule = (rule, entities, direction) => { @@ -38,26 +43,42 @@ game.system.Logic = (entitiesGrid) => { currentVerbRules.push(rule); } for (let id in entities) { - if (entities[id].hasComponent("name") && entities[id].components.name.selector == entityName) { + const entity = entities[id]; + if (entity.hasComponent("alive") && entity.hasComponent("name") && entity.components.name.selector == entityName) { changedEntityIds.push(id); const component = verbActionsToComponent[verb]; if (component) { if (direction == "apply") { - entities[id].addComponent(component); + if (verb == "you") { + if (!previousControllableIds.has(id)) { + const newYouParticleSpawner = game.createBorderParticles({colors: ["#ffc0cb", "#ffb6c1", "#ffc1cc", "#ffbcd9", "#ff1493"], minAmount: 80, maxAmount: 150, maxSpeed: 0.5}); + newYouParticleSpawner.addComponent(game.components.Position(entity.components.position)); + newYouParticleSpawner.addComponent(game.components.Appearance({width: game.canvas.width / game.config.xDim, height: game.canvas.height / game.config.yDim})); + game.entities[newYouParticleSpawner.id] = newYouParticleSpawner; + } + } + entity.addComponent(component); } else if (direction == "deapply") { - entities[id].removeComponent(component.name); + if (entity.hasComponent("controllable")) { + previousControllableIds.add(id); + } + entity.removeComponent(component.name); } } } } + if (direction == "apply" && changedEntityIds.some((id) => previousControllableIds.has(id))) { + previousControllableIds = new Set(); + } } if (application.hasComponent("noun")) { const applicationEntityName = application.components.noun.select; for (let id in entities) { - if (entities[id].hasComponent("name") && entities[id].components.name.selector == entityName) { + const entity = entities[id]; + if (entity.hasComponent("name") && entity.components.name.selector == entityName) { const e = nounsToEntityCreators[applicationEntityName](); - entities[id].components.name = e.components.name; - entities[id].components.sprite = e.components.sprite; + entity.components.name = e.components.name; + entity.components.sprite = e.components.sprite; } } } diff --git a/src/systems/render.js b/src/systems/render.js index 8a3e633..e0db7e3 100644 --- a/src/systems/render.js +++ b/src/systems/render.js @@ -14,7 +14,7 @@ game.system.Render = (graphics) => { 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")) { + } else if (entity.hasComponent("particles") && entity.particleSprite) { entity.particleSprite.draw(elapsedTime, drawSpec); } }