From 688f548ef30f7a5f7b9c7113b8a6f60ae2a17164 Mon Sep 17 00:00:00 2001 From: Pabloader Date: Thu, 27 Jun 2024 22:33:06 +0000 Subject: [PATCH] Working animations --- src/game/graphics.ts | 2 +- src/game/renderer.ts | 28 +++++++++++----------- src/game/world.ts | 55 +++++++++++++++++++++++++------------------- 3 files changed, 47 insertions(+), 38 deletions(-) diff --git a/src/game/graphics.ts b/src/game/graphics.ts index 73274ef..6d0730a 100644 --- a/src/game/graphics.ts +++ b/src/game/graphics.ts @@ -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'; diff --git a/src/game/renderer.ts b/src/game/renderer.ts index 5612ca9..8c5a7d1 100644 --- a/src/game/renderer.ts +++ b/src/game/renderer.ts @@ -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; } diff --git a/src/game/world.ts b/src/game/world.ts index 42a327e..b765a77 100644 --- a/src/game/world.ts +++ b/src/game/world.ts @@ -23,16 +23,17 @@ interface TileLimit { } export const LIMITS: Record = { + [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>; type Inventory = Partial>; +type AnimationTimers = Map; 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(); + 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()) + .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; } } }