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) { constructor(private canvas: HTMLCanvasElement) {
this.context = canvas.getContext('2d')!; this.context = canvas.getContext('2d')!;
this.context.imageSmoothingEnabled = false; 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.textRendering = 'optimizeSpeed';
this.context.textAlign = 'center'; 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"; import { ALL_DIRECTIONS, Direction, makeImage, movePoint } from "./utils";
@ -21,29 +21,31 @@ const notImage = makeImage(notSrc);
const andImage = makeImage(andSrc); const andImage = makeImage(andSrc);
const orImage = makeImage(orSrc); const orImage = makeImage(orSrc);
const px = 1 / 32;
export const renderResource = (ctx: CanvasRenderingContext2D, tile: Tile, resource?: Resource) => { export const renderResource = (ctx: CanvasRenderingContext2D, tile: Tile, resource?: Resource) => {
const resources: [Direction, Resource | undefined][] = resource let resources: [Direction, Resource | undefined][] = resource
? [[Direction.NONE, resource]] ? [[Direction.NONE, resource]]
: [...ALL_DIRECTIONS, Direction.NONE].map((d) => [d, tile.inv[d]]); : [...ALL_DIRECTIONS, Direction.NONE].map((d) => [d, tile.inv[d]]);
const oldStyle = ctx.fillStyle; const [output] = getTileOutput(tile);
const px = 1 / 32; if (output && (tile.timer ?? 0) <= 0) {
resources = [[Direction.NONE, output]];
}
let wasOtherDrawn = false; let wasOtherDrawn = false;
for (const [direction, res] of resources) { for (const [direction, res] of resources) {
if (direction === Direction.NONE && wasOtherDrawn) continue; if (direction === Direction.NONE && wasOtherDrawn) continue;
if (res) { if (res) {
const str = res.toString(2); const str = res.value.toString(2);
const amount = (tile.animationTimer ?? 0) / LIMITS[tile.type].cooldown; 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.strokeStyle = 'white';
ctx.fillText(str, x - px, y - px); ctx.lineWidth = px * 2;
ctx.fillText(str, x - px, y + px); ctx.miterLimit = 2;
ctx.fillText(str, x + px, y - px); ctx.strokeText(str, x, y);
ctx.fillText(str, x + px, y + px);
ctx.fillStyle = oldStyle;
ctx.fillText(str, x, y); ctx.fillText(str, x, y);
wasOtherDrawn = true; wasOtherDrawn = true;
} }

View File

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