Pathfinding and walking the path

This commit is contained in:
Ian Gulliver
2021-05-22 04:14:59 +00:00
parent 1d8cd414f6
commit 13f2964279
6 changed files with 164 additions and 69 deletions

View File

@@ -3,26 +3,32 @@ import { Mask } from './mask.js';
import { Tile } from './tile.js';
import { TileFactory } from './tile_factory.js';
type Point = [number, number]
export class Grid {
prnt: HTMLElement;
width: number;
height: number;
layers: Map<string, Layer> = new Map<string, Layer>();
masks: Map<string, Mask> = new Map<string, Mask>();
constructor(prnt: HTMLElement, width: number, height: number, tileset: string, layers: string[], masks: string[]) {
this.prnt = prnt;
this.width = width;
this.height = height;
this.prnt.style.display = 'grid';
this.prnt.style.gridTemplateColumns = `repeat(${width}, 1fr)`;
this.prnt.style.gridTemplateRows = `repeat(${height}, 1fr)`;
this.prnt.style.gridTemplateColumns = `repeat(${this.width}, 1fr)`;
this.prnt.style.gridTemplateRows = `repeat(${this.height}, 1fr)`;
this.prnt.style.backgroundImage = `url("images/${tileset}/land.svg")`;
for (let i = 0; i <= layers.length; i++) {
const name = layers[i];
this.layers.set(name, new Layer(i * height, tileset));
this.layers.set(name, new Layer(i * this.height, tileset));
}
for (const name of masks) {
this.masks.set(name, new Mask(width, height));
this.masks.set(name, new Mask(this.width, this.height));
}
}
@@ -40,4 +46,62 @@ export class Grid {
return tile;
}
add_debug_tile(x: number, y: number, color: string) {
const div = document.createElement('div');
this.prnt.appendChild(div);
div.style.gridColumnStart = `${x + 1}`;
div.style.gridRowStart = `${y + 1}`;
div.style.gridColumnEnd = 'span 1';
div.style.gridRowEnd = 'span 1';
div.style.backgroundColor = color;
div.style.opacity = '0.3';
div.style.zIndex = '1000000';
}
get_path(mask_name: string, src: Point, dst: Point): Point[] {
const mask = this.masks.get(mask_name)!;
const next = [];
for (let x = 0; x < this.width; x++) {
next.push(Array(this.height).fill(undefined));
}
// BFS
const queue: Point[] = [dst];
while (queue.length) {
const point = queue.shift()!;
// Horizontal / vertical has to come before diagonal
for (const [dx, dy] of [[-1,0], [1,0], [0,-1], [0,1], [-1,-1], [-1,1], [1,-1], [1,1]]) {
const check: Point = [point[0] + dx, point[1] + dy];
if (next[check[0]][check[1]]) {
// Already visited
continue;
}
if (!mask.mask[check[0]][check[1]]) {
// Not allowed
continue;
}
next[check[0]][check[1]] = point;
if (check[0] == src[0] && check[1] == src[1]) {
const path: Point[] = [];
let cur = src;
while (cur[0] != dst[0] || cur[1] != dst[1]) {
path.push(cur);
cur = next[cur[0]][cur[1]];
}
path.push(dst);
return path;
}
queue.push(check);
}
}
// No valid path
return [];
}
}

View File

@@ -85,33 +85,6 @@ export function main() {
grid.add_tile(tiles.BRIDGE_LR, 92, 36);
grid.add_tile(tiles.BRIDGE_LR, 92, 20);
function add_debug_tile(x: number, y: number, color: string) {
const div = document.createElement('div');
real.appendChild(div);
div.style.gridColumnStart = `${x + 1}`;
div.style.gridRowStart = `${y + 1}`;
div.style.gridColumnEnd = 'span 1';
div.style.gridRowEnd = 'span 1';
div.style.backgroundColor = color;
div.style.opacity = '0.3';
div.style.zIndex = '1000000';
}
{
const m = grid.masks.get('walkable')!.mask;
for (let x = 0; x < m.length; x++) {
for (let y = 0; y < m[x].length; y++) {
if (m[x][y]) {
add_debug_tile(x, y, 'orange');
continue;
}
}
}
}
add_debug_tile(118, 23, 'blue');
add_debug_tile(44, 94, 'red');
function rand(min: number, max: number): number {
return Math.round(Math.random() * (max - min) + min);
}
@@ -128,15 +101,31 @@ export function main() {
}, factory.duration);
}, 3250);
const greenaxe = grid.add_tile(tiles.GREENAXE, 60, 32);
const path = grid.get_path('walkable', [118, 23], [44, 94]);
const greenaxe = grid.add_tile(tiles.GREENAXE, 115, 18);
greenaxe.play('walk');
greenaxe.elem.style.transitionProperty = 'top,left';
greenaxe.elem.style.transitionDuration = '25s';
greenaxe.elem.style.transitionDuration = '0.5s';
greenaxe.elem.style.transitionTimingFunction = 'linear';
greenaxe.elem.style.top = '0';
greenaxe.elem.style.left = '0';
greenaxe.elem.style.transform = 'scaleX(-1)';
setTimeout(() => greenaxe.elem.style.left = '-500%', 100);
let prev = [118, 23];
setInterval(() => {
const next = path.shift();
if (!next) {
return;
}
if (next[0] - prev[0] < 0) {
greenaxe.elem.style.transform = 'scaleX(-1)';
} else if (next[0] - prev[0] > 0) {
greenaxe.elem.style.transform = 'scaleX(1)';
}
prev = next;
greenaxe.elem.style.left = `${(next[0] - 118) / 6 * 100}%`;
greenaxe.elem.style.top = `${(next[1] - 23) / 6 * 100}%`;
}, 500);
};
main();