1
0
Fork 0

Working animations

This commit is contained in:
Pabloader 2024-06-27 22:33:06 +00:00
parent aa0e84de69
commit 688f548ef3
3 changed files with 47 additions and 38 deletions

View File

@ -15,7 +15,7 @@ export default class Graphics {
constructor(private canvas: HTMLCanvasElement) {
this.context = canvas.getContext('2d')!;
this.context.imageSmoothingEnabled = false;
this.context.font = 'bold 0.4px sans-serif';
this.context.font = 'bold 0.3px sans-serif';
this.context.textRendering = 'optimizeSpeed';
this.context.textAlign = 'center';

View File

@ -1,4 +1,4 @@
import { type Tile, TileType, getPortDirections, PortDirection, LIMITS, type Resource } from "./world";
import { type Tile, TileType, getPortDirections, PortDirection, LIMITS, type Resource, getTileOutput } from "./world";
import { ALL_DIRECTIONS, Direction, makeImage, movePoint } from "./utils";
@ -21,29 +21,31 @@ const notImage = makeImage(notSrc);
const andImage = makeImage(andSrc);
const orImage = makeImage(orSrc);
const px = 1 / 32;
export const renderResource = (ctx: CanvasRenderingContext2D, tile: Tile, resource?: Resource) => {
const resources: [Direction, Resource | undefined][] = resource
let resources: [Direction, Resource | undefined][] = resource
? [[Direction.NONE, resource]]
: [...ALL_DIRECTIONS, Direction.NONE].map((d) => [d, tile.inv[d]]);
const oldStyle = ctx.fillStyle;
const px = 1 / 32;
const [output] = getTileOutput(tile);
if (output && (tile.timer ?? 0) <= 0) {
resources = [[Direction.NONE, output]];
}
let wasOtherDrawn = false;
for (const [direction, res] of resources) {
if (direction === Direction.NONE && wasOtherDrawn) continue;
if (res) {
const str = res.toString(2);
const amount = (tile.animationTimer ?? 0) / LIMITS[tile.type].cooldown;
const str = res.value.toString(2);
const [timer, timerMax] = tile.inputAnimations?.get(direction) ?? [0, 1];
const amount = timer / timerMax;
const [x, y] = movePoint([0.5, 0.65], direction, amount);
const [x, y] = movePoint([0.5, 0.62], direction, amount);
ctx.fillStyle = 'white';
ctx.fillText(str, x - px, y - px);
ctx.fillText(str, x - px, y + px);
ctx.fillText(str, x + px, y - px);
ctx.fillText(str, x + px, y + px);
ctx.fillStyle = oldStyle;
ctx.strokeStyle = 'white';
ctx.lineWidth = px * 2;
ctx.miterLimit = 2;
ctx.strokeText(str, x, y);
ctx.fillText(str, x, y);
wasOtherDrawn = true;
}

View File

@ -23,16 +23,17 @@ interface TileLimit {
}
export const LIMITS: Record<TileType, TileLimit> = {
[TileType.CONVEYOR]: { cooldown: 300, resourcesRequired: 1, capacity: 1, maxOutputs: 4 },
[TileType.DESTINATION]: { cooldown: 0, resourcesRequired: 1, capacity: 4, maxOutputs: 0 },
[TileType.SOURCE]: { cooldown: 10000, resourcesRequired: 0, capacity: 0, maxOutputs: 0 },
[TileType.EXTRACTOR]: { cooldown: 5000, resourcesRequired: 0, capacity: 0, maxOutputs: 4 },
[TileType.CONVEYOR]: { cooldown: 3000, resourcesRequired: 1, capacity: 1, maxOutputs: 4 },
[TileType.EXTRACTOR]: { cooldown: 600, resourcesRequired: 0, capacity: 0, maxOutputs: 4 },
[TileType.NOT]: { cooldown: 3000, resourcesRequired: 1, capacity: 1, maxOutputs: 1 },
[TileType.AND]: { cooldown: 3000, resourcesRequired: 2, capacity: 2, maxOutputs: 1 },
[TileType.AND]: { cooldown: 6000, resourcesRequired: 2, capacity: 2, maxOutputs: 1 },
[TileType.OR]: { cooldown: 3000, resourcesRequired: 2, capacity: 2, maxOutputs: 1 },
};
export type Resource = number;
export type Resource = { readonly value: number };
interface Port {
direction: PortDirection;
@ -40,16 +41,17 @@ interface Port {
type Ports = Partial<Record<Direction, Port>>;
type Inventory = Partial<Record<Direction, Resource>>;
type AnimationTimers = Map<Direction, [number, number]>;
interface BaseTile {
ports: Ports;
inv: Inventory;
inputAnimations?: AnimationTimers;
bufferedDirections?: Direction[];
nextInput?: Direction;
nextOutput?: Direction;
timer?: number;
animationTimer?: number;
}
interface TileDestination extends BaseTile {
@ -105,7 +107,7 @@ export const getTileOutput = (tile: Tile): [Resource | undefined, Direction[]] =
if (inputDirection) {
let resource = tile.inv[inputDirection];
if (tile.type === TileType.NOT && resource) {
resource = ~(resource) & 0xF;
resource = { value: ~(resource.value) & 0xF };
}
inputDirections = [inputDirection];
bufferedResource = resource;
@ -115,10 +117,10 @@ export const getTileOutput = (tile: Tile): [Resource | undefined, Direction[]] =
const [x, y] = inputDirections.map(d => tile.inv[d]!);
switch (tile.type) {
case TileType.AND:
bufferedResource = (x & y) & 0xF;
bufferedResource = { value: (x.value & y.value) & 0xF };
break;
case TileType.OR:
bufferedResource = (x | y) & 0xF;
bufferedResource = { value: (x.value | y.value) & 0xF };
break;
}
}
@ -296,7 +298,7 @@ export default class World {
const tile = this.world.get(pid);
if (tile) return tile;
if (Math.abs(x) >= 5 && Math.abs(y) >= 5) {
if (Math.abs(x) >= 3 && Math.abs(y) >= 3) {
return this.genTile(trunc(position));
}
@ -307,8 +309,8 @@ export default class World {
const hash = cyrb32(this.seed, ...position);
if ((hash & 0xFF) === 42) {
const resource = (hash >> 12) & 0xF || 1;
const newTile: Tile = { type: TileType.SOURCE, resource, ports: {}, inv: {} };
const value = (hash >> 12) & 0xF || 1;
const newTile: Tile = { type: TileType.SOURCE, resource: { value }, ports: {}, inv: {} };
return newTile;
}
@ -332,19 +334,20 @@ export default class World {
update(dt: number) {
for (const [pid, tile] of this.tiles) {
if (!tile.nextInput) {
if (!tile.nextInput) {
tile.nextInput = findNextPort(tile.ports, PortDirection.INPUT, tile.nextInput);
}
if (!tile.nextOutput) {
if (!tile.nextOutput) {
tile.nextOutput = findNextPort(tile.ports, PortDirection.OUTPUT, tile.nextOutput);
}
const position = deid(pid);
if (tile.timer && tile.timer > 0) {
tile.timer -= dt;
}
if (tile.animationTimer && tile.animationTimer > 0) {
tile.animationTimer -= dt;
tile.timer = Math.max(0, (tile.timer ?? 0) - dt);
const animationTimers: AnimationTimers = tile.inputAnimations ?? new Map<Direction, [number, number]>();
for (const [direction, [timer, timerMax]] of animationTimers) {
animationTimers.set(direction, [Math.max(0, timer - dt), timerMax]);
}
tile.inputAnimations = animationTimers;
if (!tile.timer || tile.timer <= 0) {
switch (tile.type) {
@ -362,28 +365,32 @@ export default class World {
const [neighbour, inputDirection, neighbourPosition] = this.getNeighbour(position, tile.nextOutput);
if (neighbour) {
const [priorityPusher,] = this.getNeighbour(neighbourPosition, neighbour.nextInput);
const limits = LIMITS[neighbour.type];
const neighbourLimits = LIMITS[neighbour.type];
const limits = LIMITS[tile.type];
if (
neighbour.ports[inputDirection]?.direction === PortDirection.INPUT
&& neighbour.inv[inputDirection] == null
&& getTileInputs(neighbour).length < limits.capacity
&& getTileInputs(neighbour).length < neighbourLimits.capacity
&& (
neighbour.nextInput == null
|| neighbour.nextInput === inputDirection
|| !priorityPusher
|| getTileOutput(priorityPusher)[0] == null
|| limits.resourcesRequired > 1
|| neighbourLimits.resourcesRequired > 1
)
) {
neighbour.inv[inputDirection] = resource;
if (getTileInputs(neighbour).length >= limits.capacity) {
neighbour.timer = limits.cooldown;
neighbour.inputAnimations =
(neighbour.inputAnimations ?? new Map<Direction, [number, number]>())
.set(inputDirection, [LIMITS[TileType.CONVEYOR].cooldown, LIMITS[TileType.CONVEYOR].cooldown]);
if (getTileInputs(neighbour).length >= neighbourLimits.capacity) {
neighbour.timer = neighbourLimits.cooldown;
neighbour.nextInput = findNextPort(neighbour.ports, PortDirection.INPUT, neighbour.nextInput);
}
inputDirections.forEach(inputDirection => delete tile.inv[inputDirection]);
tile.timer = LIMITS[tile.type].cooldown;
tile.timer = limits.cooldown;
}
}
}