From 558e91a4420bb52e9b8dad624cff3859ec64ea43 Mon Sep 17 00:00:00 2001 From: Logan Hunt Date: Tue, 5 Apr 2022 19:45:09 -0600 Subject: [PATCH] Added collision system, added changedId's which doesn't do anything rn --- src/bootstrap.js | 2 +- src/game.js | 22 ++++--- src/systems/collision.js | 49 ++++++++++++++ src/systems/grid.js | 111 +++++++++++++++++++++++++++++++ src/systems/gridSystem.js | 122 ----------------------------------- src/systems/keyboardInput.js | 4 +- src/systems/physics.js | 8 ++- src/systems/render.js | 4 +- 8 files changed, 184 insertions(+), 138 deletions(-) create mode 100644 src/systems/collision.js create mode 100644 src/systems/grid.js delete mode 100644 src/systems/gridSystem.js diff --git a/src/bootstrap.js b/src/bootstrap.js index 7a7d809..24e9c4c 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -32,7 +32,7 @@ game.bootstrap = (() => { { src: ['src/systems/system.js'], id: 'system' }, { src: [ - 'src/systems/render.js', 'src/systems/gridSystem.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', ], id: 'systems' }, { src: ['src/game.js'], id: 'game' }, diff --git a/src/game.js b/src/game.js index 60d2a27..f649ba5 100644 --- a/src/game.js +++ b/src/game.js @@ -4,8 +4,11 @@ game.loop = (timeStamp) => { lastTimeStamp = timeStamp; + const changedIds = new Set(); game.systemOrder.map((i) => { - game.systems[i].update(elapsedTime, game.entities); + game.systems[i] + .update(elapsedTime, game.entities, changedIds) + .forEach((id) => changedIds.add(id)); }); for (let id in game.entities) { @@ -14,23 +17,22 @@ game.loop = (timeStamp) => { } } - if (game.nextLevel) { - game.loadLevel(game.nextLevel); - game.nextLevel = false; - } - requestAnimationFrame(game.loop); } game.initialize = () => { [game.entities, game.config] = game.loadLevel(game.levels[0]); - game.systemOrder = ["render", "physics", "gridSystem", "keyboardInput"]; + // 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", "render"]; game.systems = { - render: game.system.Render(game.graphics), - physics: game.system.Physics(), - gridSystem: game.system.GridSystem({...game.config}), + physics: game.system.Physics(game.entitiesGrid), + gridSystem: game.system.Grid(game.entitiesGrid), + collisionSystem: game.system.Collision(game.entitiesGrid), keyboardInput: game.system.KeyboardInput(), + render: game.system.Render(game.graphics), }; lastTimeStamp = performance.now() diff --git a/src/systems/collision.js b/src/systems/collision.js new file mode 100644 index 0000000..7739bae --- /dev/null +++ b/src/systems/collision.js @@ -0,0 +1,49 @@ +game.system.Collision = (entitiesGrid) => { + const update = (elapsedTime, entities, changedIds) => { + 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")) { + console.log("WALL FOUND") + 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) { + console.log("WALL") + entity.removeComponent("momentum"); + } else { + entitiesToPush.map((e) => e.addComponent(game.components.Momentum({...momentum}))); + } + } + } + return new Set(); + }; + return { update }; +}; diff --git a/src/systems/grid.js b/src/systems/grid.js new file mode 100644 index 0000000..4082793 --- /dev/null +++ b/src/systems/grid.js @@ -0,0 +1,111 @@ +game.system.Grid = (entitiesGrid) => { + let gridWidth = game.canvas.width / game.config.xDim; + let gridHeight = game.canvas.height / game.config.yDim; + + const gameCoordsToGrid = ({ x, y }) => { + return { x: Math.floor((x+gridWidth/2) / game.canvas.width * game.config.yDim), y: Math.floor((y+gridHeight/2) / game.canvas.height * game.config.yDim) }; + }; + + const gridCoordsToGame = ({ x, y }) => { + return { x: x * gridWidth, y: y * gridHeight }; + }; + + const rebuildGrid = (entities) => { + let changedIds = new Set(); + entities.map(entity => { + const { x, y } = entity.components.gridPosition; + if (!entitiesGrid[y][x].has(entity.id)) { + changedIds.add(entity.id); + } + }); + entitiesGrid.forEach((row) => row.forEach((entitiesInCell) => { + for (let id of entitiesInCell.keys()) { + if (changedIds.has(id)) { + entitiesInCell.delete(id); + } + } + })); + changedIds.forEach(id => { + const entity = entities[id]; + const { x, y } = entity.components.gridPosition; + entitiesGrid[y][x].set(entity.id, entity); + }); + } + + const update = (_elapsedTime, entities, changedIds) => { + gridEntities = Object.keys(entities).filter((x) => entities[x].hasComponent("gridPosition")).map((x) => entities[x]); + const thisChangedIds = new Set(); + gridEntities.map((entity) => { + if (entity.hasComponent("appearance")) { + entity.components.appearance.width = gridWidth; + entity.components.appearance.height = gridHeight; + } + if (entity.hasComponent("gridPosition")) { + const oldGridCoords = entity.components.gridPosition; + if (entity.hasComponent("position")) { + const gameCoords = gridCoordsToGame(entity.components.gridPosition); + if (Math.abs(entity.components.position.x - gameCoords.x) >= gridWidth/2 || Math.abs(entity.components.position.y - gameCoords.y) >= gridHeight/2) { + entity.components.gridPosition = gameCoordsToGrid(entity.components.position); + if (entity.hasComponent("momentum")) { + entity.removeComponent("momentum"); + } + } + } + if (!entity.hasComponent("position") || !equivalence(entity.components.gridPosition, oldGridCoords)) { + entity.components.position = { + ...entity.components.position, + ...gridCoordsToGame(entity.components.gridPosition) + }; + thisChangedIds.add(entity.id); + } + } + }); + rebuildGrid(gridEntities); + return thisChangedIds; + }; + + + return { gameCoordsToGrid, gridCoordsToGame, update, gridWidth, gridHeight }; +}; + +// +// +// +// const proposed = {...newGridCoords}; +// let wall = false; +// let entitiesToPush = []; +// if (entity.hasComponent("controllable")) { +// let found = false; + +// +// if (entity.hasComponent("controllable")) { +// if (!wall) { +// entity.components.gridPosition = {...entity.components.gridPosition, ...newGridCoords}; +// entitiesToPush.map((e) => e.addComponent(game.components.Momentum({...momentumVector}))); +// } +// const particles = game.createBorderParticles({ +// 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}; +// } +// +// +// +// +// +// } +// } else { +// entity.addComponent(game.components.Position({...gridCoordsToGame(entity.components.gridPosition)})); +// }; +// }); \ No newline at end of file diff --git a/src/systems/gridSystem.js b/src/systems/gridSystem.js deleted file mode 100644 index d9c8a6b..0000000 --- a/src/systems/gridSystem.js +++ /dev/null @@ -1,122 +0,0 @@ -game.system.GridSystem = ({ xDim, yDim }) => { - const entitiesGrid = Array(yDim).fill(null).map(() => Array(xDim).fill(null).map(() => new Map())); - - let gridWidth = game.canvas.width / xDim; - let gridHeight = game.canvas.height / yDim; - - const gameCoordsToGrid = ({ x, y }) => { - return { x: Math.floor((x+gridWidth/2) / game.canvas.width * xDim), y: Math.floor((y+gridHeight/2) / game.canvas.height * yDim) }; - }; - - const gridCoordsToGame = ({ x, y }) => { - return { x: x * gridWidth, y: y * gridHeight }; - }; - - const rebuildGrid = (entities) => { - let changedIds = new Set(); - entities.map(entity => { - const { x, y } = entity.components.gridPosition; - if (!entitiesGrid[y][x].has(entity.id)) { - changedIds.add(entity.id); - } - }); - entitiesGrid.forEach((row) => row.forEach((entitiesInCell) => { - for (let id of entitiesInCell.keys()) { - if (changedIds.has(id)) { - entitiesInCell.delete(id); - } - } - })); - changedIds.forEach(id => { - const entity = entities[id]; - const { x, y } = entity.components.gridPosition; - entitiesGrid[y][x].set(entity.id, entity); - }); - } - - const update = (_elapsedTime, entities) => { - const gridEntities = Object.keys(entities).filter((x) => entities[x].hasComponent("gridPosition")).map((x) => entities[x]); - rebuildGrid(gridEntities); - gridEntities.map((entity) => { - if (entity.hasComponent("appearance")) { - entity.components.appearance.width = gridWidth; - entity.components.appearance.height = gridHeight; - } - if (entity.hasComponent("position")) { - let newGridCoords = gameCoordsToGrid(entity.components.position); - const oldGridCoords = entity.components.gridPosition; - if (!equivalence(newGridCoords, oldGridCoords)) { - const momentumVector = unitize({ - dx: newGridCoords.x - oldGridCoords.x, - dy: newGridCoords.y - oldGridCoords.y, - }); - - const proposed = {...newGridCoords}; - let wall = false; - let entitiesToPush = []; - if (entity.hasComponent("controllable")) { - let found = false; - do { - found = false; - const entitiesInCell = entitiesGrid[proposed.y][proposed.x]; - for (let entity of entitiesInCell.values()) { - if (entity.hasComponent("pushable")) { - found = true; - entitiesToPush.push(entity); - } - if (entity.hasComponent("stop")) { - wall = true; - found = false; - break; - } - } - proposed.x += momentumVector.dx; - proposed.y += momentumVector.dy; - const proposedClampedInBounds = clamp(proposed, xDim-1, yDim-1); - if (!equivalence(proposedClampedInBounds, proposed)) { - found = false; - } - } while (found); - } - - if (entity.hasComponent("controllable")) { - if (!wall) { - entity.components.gridPosition = {...entity.components.gridPosition, ...newGridCoords}; - entitiesToPush.map((e) => e.addComponent(game.components.Momentum({...momentumVector}))); - } - const particles = game.createBorderParticles({ - 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.position = { - ...entity.components.position, - ...gridCoordsToGame(entity.components.gridPosition) - }; - - if (entity.hasComponent("momentum")) { - entity.components.momentum.dx = 0; - entity.components.momentum.dy = 0; - } - } - } else { - entity.addComponent(game.components.Position({...gridCoordsToGame(entity.components.gridPosition)})); - }; - }); - }; - - return { entitiesGrid, gameCoordsToGrid, gridCoordsToGame, update, gridWidth, gridHeight }; -}; diff --git a/src/systems/keyboardInput.js b/src/systems/keyboardInput.js index 24fd076..60a62a1 100644 --- a/src/systems/keyboardInput.js +++ b/src/systems/keyboardInput.js @@ -6,7 +6,7 @@ game.system.KeyboardInput = () => { keys[event.key] = true; } }; - const update = (elapsedTime, entities) => { + const update = (elapsedTime, entities, changedIds) => { for (let id in entities) { const entity = entities[id]; if (entity.hasComponent('controllable')) { @@ -24,6 +24,8 @@ game.system.KeyboardInput = () => { } } Object.keys(keys).map((key) => delete keys[key]); + + return new Set(); }; window.addEventListener("keydown", keyPress); return { keys, update }; diff --git a/src/systems/physics.js b/src/systems/physics.js index a49edca..d72b1a0 100644 --- a/src/systems/physics.js +++ b/src/systems/physics.js @@ -1,7 +1,7 @@ game.system.Physics = () => { - const update = (elapsedTime) => { - for (let id in game.entities) { - const entity = game.entities[id]; + const update = (elapsedTime, entities, changedIds) => { + for (let id in entities) { + const entity = entities[id]; if (entity.hasComponent("momentum") && entity.hasComponent("appearance")) { const {dx, dy} = entity.components.momentum; entity.components.position.x += dx * elapsedTime; @@ -9,6 +9,8 @@ game.system.Physics = () => { entity.components.position = clamp(entity.components.position, game.canvas.width - entity.components.appearance.width, game.canvas.height - entity.components.appearance.height); } } + + return new Set(); } return { update }; } \ No newline at end of file diff --git a/src/systems/render.js b/src/systems/render.js index 4ec67c7..adf3e86 100644 --- a/src/systems/render.js +++ b/src/systems/render.js @@ -1,5 +1,5 @@ game.system.Render = (graphics) => { - const update = (elapsedTime, entities) => { + const update = (elapsedTime, entities, _changedIds) => { graphics.clear(); const entitiesArray = Object.keys(entities).map(key => entities[key]); @@ -14,6 +14,8 @@ game.system.Render = (graphics) => { entity.sprite.draw(elapsedTime, {...entity.components.position, ...entity.components.appearance}); } }); + + return new Set(); } return { update }; }; \ No newline at end of file