Added collision system, added changedId's which doesn't do anything rn
This commit is contained in:
parent
69596ba244
commit
558e91a442
2
src/bootstrap.js
vendored
2
src/bootstrap.js
vendored
@ -32,7 +32,7 @@ game.bootstrap = (() => {
|
|||||||
{ src: ['src/systems/system.js'], id: 'system' },
|
{ src: ['src/systems/system.js'], id: 'system' },
|
||||||
{
|
{
|
||||||
src: [
|
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' },
|
id: 'systems' },
|
||||||
{ src: ['src/game.js'], id: 'game' },
|
{ src: ['src/game.js'], id: 'game' },
|
||||||
|
22
src/game.js
22
src/game.js
@ -4,8 +4,11 @@ game.loop = (timeStamp) => {
|
|||||||
lastTimeStamp = timeStamp;
|
lastTimeStamp = timeStamp;
|
||||||
|
|
||||||
|
|
||||||
|
const changedIds = new Set();
|
||||||
game.systemOrder.map((i) => {
|
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) {
|
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);
|
requestAnimationFrame(game.loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
game.initialize = () => {
|
game.initialize = () => {
|
||||||
[game.entities, game.config] = game.loadLevel(game.levels[0]);
|
[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 = {
|
game.systems = {
|
||||||
render: game.system.Render(game.graphics),
|
physics: game.system.Physics(game.entitiesGrid),
|
||||||
physics: game.system.Physics(),
|
gridSystem: game.system.Grid(game.entitiesGrid),
|
||||||
gridSystem: game.system.GridSystem({...game.config}),
|
collisionSystem: game.system.Collision(game.entitiesGrid),
|
||||||
keyboardInput: game.system.KeyboardInput(),
|
keyboardInput: game.system.KeyboardInput(),
|
||||||
|
render: game.system.Render(game.graphics),
|
||||||
};
|
};
|
||||||
|
|
||||||
lastTimeStamp = performance.now()
|
lastTimeStamp = performance.now()
|
||||||
|
49
src/systems/collision.js
Normal file
49
src/systems/collision.js
Normal file
@ -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 };
|
||||||
|
};
|
111
src/systems/grid.js
Normal file
111
src/systems/grid.js
Normal file
@ -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)}));
|
||||||
|
// };
|
||||||
|
// });
|
@ -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 };
|
|
||||||
};
|
|
@ -6,7 +6,7 @@ game.system.KeyboardInput = () => {
|
|||||||
keys[event.key] = true;
|
keys[event.key] = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const update = (elapsedTime, entities) => {
|
const update = (elapsedTime, entities, changedIds) => {
|
||||||
for (let id in entities) {
|
for (let id in entities) {
|
||||||
const entity = entities[id];
|
const entity = entities[id];
|
||||||
if (entity.hasComponent('controllable')) {
|
if (entity.hasComponent('controllable')) {
|
||||||
@ -24,6 +24,8 @@ game.system.KeyboardInput = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Object.keys(keys).map((key) => delete keys[key]);
|
Object.keys(keys).map((key) => delete keys[key]);
|
||||||
|
|
||||||
|
return new Set();
|
||||||
};
|
};
|
||||||
window.addEventListener("keydown", keyPress);
|
window.addEventListener("keydown", keyPress);
|
||||||
return { keys, update };
|
return { keys, update };
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
game.system.Physics = () => {
|
game.system.Physics = () => {
|
||||||
const update = (elapsedTime) => {
|
const update = (elapsedTime, entities, changedIds) => {
|
||||||
for (let id in game.entities) {
|
for (let id in entities) {
|
||||||
const entity = game.entities[id];
|
const entity = entities[id];
|
||||||
if (entity.hasComponent("momentum") && entity.hasComponent("appearance")) {
|
if (entity.hasComponent("momentum") && entity.hasComponent("appearance")) {
|
||||||
const {dx, dy} = entity.components.momentum;
|
const {dx, dy} = entity.components.momentum;
|
||||||
entity.components.position.x += dx * elapsedTime;
|
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);
|
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 };
|
return { update };
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
game.system.Render = (graphics) => {
|
game.system.Render = (graphics) => {
|
||||||
const update = (elapsedTime, entities) => {
|
const update = (elapsedTime, entities, _changedIds) => {
|
||||||
graphics.clear();
|
graphics.clear();
|
||||||
|
|
||||||
const entitiesArray = Object.keys(entities).map(key => entities[key]);
|
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});
|
entity.sprite.draw(elapsedTime, {...entity.components.position, ...entity.components.appearance});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return new Set();
|
||||||
}
|
}
|
||||||
return { update };
|
return { update };
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user