From 1e4be0ff2cbe6bb89fb4e4b36ff81f76fcb3f7da Mon Sep 17 00:00:00 2001 From: Pabloader Date: Fri, 27 Jun 2025 12:51:16 +0000 Subject: [PATCH] Add moving animation --- src/common/utils.ts | 1 + src/games/zombies/character.ts | 37 +++++++++++++++++++++++++++------- src/games/zombies/tilemap.ts | 17 ++++++++++------ 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/common/utils.ts b/src/common/utils.ts index 7bac6a0..3b9dd08 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -48,6 +48,7 @@ export function* zip(...args: Iterable[]) { export const range = (size: number | string) => Object.keys((new Array(+size)).fill(0)).map(k => +k); export const clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value)); +export const lerp = (start: number, end: number, t: number) => (start + (end - start) * t); export const prevent = (e: Event) => (e.preventDefault(), false); diff --git a/src/games/zombies/character.ts b/src/games/zombies/character.ts index 028e545..b84deae 100644 --- a/src/games/zombies/character.ts +++ b/src/games/zombies/character.ts @@ -1,27 +1,50 @@ +import { lerp } from "@common/utils"; import Item from "./item"; import Tile from "./tile"; -const MOVE_DURATION = 0.5; +const MOVE_DURATION = .1; export default class Character extends Item { public tile = new Tile([0, 0], 1); - public path: Tile[] = []; + private path: Tile[] = []; private pathProgress = 0; - public get displayPosition() { - if (this.path.length > 0) { - // TODO calc + public get displayPosition(): [number, number] { + if (this.path.length > 1) { + const numTransitions = this.path.length - 1; + const progress = this.pathProgress * numTransitions; + const currentTileIdx = Math.floor(progress); + + const currentTile = this.path[currentTileIdx]; + const nextTile = this.path[currentTileIdx + 1]; + + if (!nextTile) { + return [currentTile.centerX, currentTile.centerY]; + } + + const transitionFraction = progress - currentTileIdx; + + return [ + lerp(currentTile.centerX, nextTile.centerX, transitionFraction), + lerp(currentTile.centerY, nextTile.centerY, transitionFraction), + ] } return [this.tile.centerX, this.tile.centerY]; } + public moveTo(tile: Tile, path: Tile[]) { + this.pathProgress = 0; + this.tile = tile; + this.path = path; + } + public update(dt: number) { - if (this.path.length > 0) { + if (this.path.length > 1) { if (this.pathProgress >= 1) { this.path = []; this.pathProgress = 0; } else { - this.pathProgress += MOVE_DURATION * dt; + this.pathProgress += dt / (MOVE_DURATION * (this.path.length - 1)); } } } diff --git a/src/games/zombies/tilemap.ts b/src/games/zombies/tilemap.ts index 54ed2d5..70f057c 100644 --- a/src/games/zombies/tilemap.ts +++ b/src/games/zombies/tilemap.ts @@ -199,7 +199,7 @@ export default class TileMap extends Entity { get activeTiles() { return this.tiles.filter(tile => ( - tile.items.length > 0 + tile.items.length > 0 || tile.type === TileType.LOCKED_DOOR || tile.hovered || (this.state === GameState.NORMAL && this.availableTiles.includes(tile)) @@ -219,7 +219,7 @@ export default class TileMap extends Entity { const path = Pathfinding.findPath(this.player.tile, tile); if (path.length > 1) { this.player.lastDoor = path.find(t => t.type === TileType.DOOR); - this.player.tile = tile; + this.player.moveTo(tile, path); tile.open(); for (const item of tile.items.slice()) { // iterate remaining items if (item.isPickable) { @@ -316,7 +316,7 @@ export default class TileMap extends Entity { private killEnemy() { this.player.tile.killEnemy(); - this.player.tile.items.forEach((item) => { + this.player.tile.items.slice().forEach((item) => { if (item.isPickable) { this.player.inventory.push(item); this.player.tile.removeItem(item); @@ -339,9 +339,10 @@ export default class TileMap extends Entity { } const w = this.tileSize * 0.8; - [...this.players, this.player].forEach(c => - ctx.drawImage(c.type, c.tile.centerX - w / 2, c.tile.centerY - w / 2, w, w) - ); + [...this.players, this.player].forEach((player) => { + const [x, y] = player.displayPosition; + ctx.drawImage(player.type, x - w / 2, y - w / 2, w, w); + }); this.activeTiles.forEach(t => t.render(ctx)); @@ -350,4 +351,8 @@ export default class TileMap extends Entity { ctx.strokeRect(this.player.tile.centerX - w / 2, this.player.tile.centerY - w / 2, w, w); } + + public update(dt: number) { + this.players.forEach((player) => player.update(dt)); + } } \ No newline at end of file