1
0
Fork 0

Working conveyors

This commit is contained in:
Pabloader 2024-06-26 20:59:07 +00:00
parent 12136bacf6
commit d46e98dda0
4 changed files with 95 additions and 21 deletions

View File

@ -10,6 +10,7 @@ export default class Game {
private world; private world;
private ui; private ui;
private prevWorldPos: Point | null = null; private prevWorldPos: Point | null = null;
private prevFrame: number = performance.now();
constructor(private canvas: HTMLCanvasElement, controls: HTMLElement) { constructor(private canvas: HTMLCanvasElement, controls: HTMLElement) {
window.addEventListener('resize', this.onResize); window.addEventListener('resize', this.onResize);
@ -108,7 +109,11 @@ export default class Game {
} }
private loop = () => { private loop = () => {
this.world.update(); const now = performance.now();
const dt = now - this.prevFrame;
this.prevFrame = now;
this.world.update(dt);
this.graphics.clear(); this.graphics.clear();

View File

@ -52,5 +52,9 @@ export const renderers: Renderers = {
ctx.fillRect(0.8, 0.2, 0.2, 0.6); ctx.fillRect(0.8, 0.2, 0.2, 0.6);
} }
} }
if (tile.resource) {
ctx.fillStyle = 'blue';
ctx.fillText(tile.resource.toString(2), 0.5, 0.65);
}
} }
}; };

View File

@ -141,6 +141,13 @@ export const DIRECTION_VECTORS: Record<Direction, Point> = {
[Direction.WEST]: [-1, 0], [Direction.WEST]: [-1, 0],
[Direction.EAST]: [1, 0], [Direction.EAST]: [1, 0],
}; };
export const NEXT_DIRECTION: Record<Direction, Direction> = {
[Direction.NONE]: Direction.NONE,
[Direction.NORTH]: Direction.EAST,
[Direction.SOUTH]: Direction.WEST,
[Direction.WEST]: Direction.NORTH,
[Direction.EAST]: Direction.SOUTH,
};
export const ALL_DIRECTIONS = [Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST]; export const ALL_DIRECTIONS = [Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST];
export const movePoint = (point: Point, direction: Direction): Point => [ export const movePoint = (point: Point, direction: Direction): Point => [
point[0] + DIRECTION_VECTORS[direction][0], point[0] + DIRECTION_VECTORS[direction][0],

View File

@ -1,4 +1,4 @@
import { ALL_DIRECTIONS, Direction, cyrb32, exp, getDirection, getOppositeDirection, movePoint, pointsEquals, trunc } from "./utils"; import { ALL_DIRECTIONS, Direction, NEXT_DIRECTION, cyrb32, exp, getDirection, getOppositeDirection, movePoint, pointsEquals, trunc } from "./utils";
export enum TileType { export enum TileType {
DESTINATION, DESTINATION,
@ -16,13 +16,15 @@ type Resource = number;
interface Port { interface Port {
direction: PortDirection; direction: PortDirection;
buffer?: Resource;
} }
type Ports = Partial<Record<Direction, Port>>; type Ports = Partial<Record<Direction, Port>>;
interface BaseTile { interface BaseTile {
ports: Ports; ports: Ports;
nextOutput?: Direction;
resource?: Resource;
timer?: number;
} }
interface TileDestination extends BaseTile { interface TileDestination extends BaseTile {
@ -47,8 +49,25 @@ interface TileConveyor extends BaseTile {
export type Tile = TileDestination | TileSource | TileExtractor | TileConveyor; export type Tile = TileDestination | TileSource | TileExtractor | TileConveyor;
const id = (point: Point) => ((Math.floor(point[0]) & 0xFFFF) << 16) | Math.floor(point[1]) & 0xFFFF; const id = (point: Point) => ((Math.floor(point[0]) & 0xFFFF) << 16) | Math.floor(point[1]) & 0xFFFF;
const deid = (pid: number): Point => [(pid >> 16) & 0xFFFF, pid & 0xFFFF];
export const getPortDirections = (ports: Partial<Record<Direction, any>>) => Object.keys(ports).map(k => +k as Direction); export const getPortDirections = (ports: Ports) => Object.keys(ports).map(k => +k as Direction);
const findNextOutput = (ports: Ports, prevDirection?: Direction): Direction => {
const outputs = getPortDirections(ports).filter(d => d && ports[d]?.direction === PortDirection.OUTPUT);
if (outputs.length === 0) return Direction.NONE;
if (prevDirection) {
let nextDirection = NEXT_DIRECTION[prevDirection];
while (nextDirection !== prevDirection) {
if (outputs.includes(nextDirection)) break;
nextDirection = NEXT_DIRECTION[nextDirection]
}
return nextDirection;
} else {
return outputs[0];
}
}
export default class World { export default class World {
private world = new Map<number, Tile>(); private world = new Map<number, Tile>();
@ -108,11 +127,11 @@ export default class World {
if (existingTile?.type === TileType.SOURCE) { if (existingTile?.type === TileType.SOURCE) {
const ports: Ports = {}; const ports: Ports = {};
for (const direction of ALL_DIRECTIONS) { for (const direction of ALL_DIRECTIONS) {
const oppositeDirection = getOppositeDirection(direction); const [neighbour, oppositeDirection] = this.getNeighbour(position, direction);
const neighbourPos = movePoint(position, direction); if (neighbour) {
const neighbour = this.getTile(neighbourPos); if (!neighbour.ports[oppositeDirection]) {
if (neighbour && !neighbour.ports[oppositeDirection]) { neighbour.ports[oppositeDirection] = { direction: PortDirection.INPUT };
neighbour.ports[oppositeDirection] = { direction: PortDirection.INPUT }; }
ports[direction] = { direction: PortDirection.OUTPUT }; ports[direction] = { direction: PortDirection.OUTPUT };
} }
} }
@ -141,22 +160,16 @@ export default class World {
const pid = id(position); const pid = id(position);
const existingTile = this.world.get(pid); const existingTile = this.world.get(pid);
const type = existingTile?.type; const type = existingTile?.type;
if (type === TileType.DESTINATION || type === TileType.SOURCE) { if (type === TileType.DESTINATION) {
return; return;
} }
if (existingTile) { if (existingTile) {
for (const direction of getPortDirections(existingTile.ports)) { for (const direction of getPortDirections(existingTile.ports)) {
const oppositeDirection = getOppositeDirection(direction); const [neighbour, oppositeDirection] = this.getNeighbour(position, direction);
const neighbourPos = movePoint(position, direction);
const neighbour = this.getTile(neighbourPos);
if (neighbour) { if (neighbour) {
delete neighbour.ports[oppositeDirection]; delete neighbour.ports[oppositeDirection];
} }
} }
}
if (existingTile?.type === TileType.EXTRACTOR) {
this.world.set(pid, existingTile.source);
} else if (existingTile) {
this.world.delete(pid); this.world.delete(pid);
} }
} }
@ -175,20 +188,65 @@ export default class World {
} }
private genTile(position: Point): Tile | null { private genTile(position: Point): Tile | null {
const pid = id(position);
const hash = cyrb32(this.seed, ...position); const hash = cyrb32(this.seed, ...position);
if ((hash & 0xFF) === 42) { if ((hash & 0xFF) === 42) {
const resource = (hash >> 12) & 0xF || 1; const resource = (hash >> 12) & 0xF || 1;
const newTile: Tile = { type: TileType.SOURCE, resource, ports: {} }; const newTile: Tile = { type: TileType.SOURCE, resource, ports: {} };
this.world.set(pid, newTile);
return newTile; return newTile;
} }
return null; return null;
} }
update() { private get tiles() {
return this.world.entries();
}
private getNeighbour(position: Point, direction: Direction): [Tile | null, Direction] {
const neighbourPosition = movePoint(position, direction);
const neighbour = this.getTile(neighbourPosition);
const oppositeDirection = getOppositeDirection(direction);
return [neighbour, oppositeDirection];
}
update(dt: number) {
for (const [pid, tile] of this.tiles) {
const position = deid(pid);
if (tile.timer && tile.timer > 0) {
tile.timer -= dt;
}
if (!tile.timer || tile.timer <= 0) {
switch (tile.type) {
case TileType.EXTRACTOR:
case TileType.CONVEYOR:
if (tile.resource) {
tile.nextOutput = findNextOutput(tile.ports, tile.nextOutput);
if (tile.nextOutput) {
const [neighbour, oppositeDirection] = this.getNeighbour(position, tile.nextOutput);
if (neighbour?.ports[oppositeDirection]?.direction === PortDirection.INPUT && !neighbour.resource) {
neighbour.resource = tile.resource;
neighbour.timer = 300; // TODO remove hardcode
tile.resource = undefined;
tile.timer = 500;
} else {
tile.timer = 100;
}
}
}
if (tile.type === TileType.EXTRACTOR && !tile.resource) {
tile.resource = tile.source.resource;
}
break;
case TileType.DESTINATION:
// TODO count gathered
tile.resource = undefined;
break;
}
}
}
} }
} }