Added collision system, added changedId's which doesn't do anything rn

This commit is contained in:
Logan Hunt 2022-04-05 19:45:09 -06:00
parent 69596ba244
commit 558e91a442
Signed by untrusted user who does not match committer: simponic
GPG Key ID: 52B3774857EB24B1
8 changed files with 184 additions and 138 deletions

2
src/bootstrap.js vendored
View File

@ -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' },

View File

@ -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()

49
src/systems/collision.js Normal file
View 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
View 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)}));
// };
// });

View File

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

View File

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

View File

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

View File

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