move to the nearest tile if possible
This commit is contained in:
parent
67cd0dfb29
commit
1c4e803dd7
@ -31,7 +31,7 @@ export class GameSceneUserInputHandler implements UserInputHandlerInterface {
|
|||||||
.getTileIndexAt(this.gameScene.CurrentPlayer.x, this.gameScene.CurrentPlayer.y);
|
.getTileIndexAt(this.gameScene.CurrentPlayer.x, this.gameScene.CurrentPlayer.y);
|
||||||
this.gameScene
|
this.gameScene
|
||||||
.getPathfindingManager()
|
.getPathfindingManager()
|
||||||
.findPath(startTile, index)
|
.findPath(startTile, index, true)
|
||||||
.then((path) => {
|
.then((path) => {
|
||||||
const tileDimensions = this.gameScene.getGameMap().getTileDimensions();
|
const tileDimensions = this.gameScene.getGameMap().getTileDimensions();
|
||||||
const pixelPath = path.map((step) => {
|
const pixelPath = path.map((step) => {
|
||||||
|
@ -22,4 +22,13 @@ export class MathUtils {
|
|||||||
public static isBetween(value: number, min: number, max: number): boolean {
|
public static isBetween(value: number, min: number, max: number): boolean {
|
||||||
return value >= min && value <= max;
|
return value >= min && value <= max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static distanceBetween(
|
||||||
|
p1: { x: number; y: number },
|
||||||
|
p2: { x: number; y: number },
|
||||||
|
squared: boolean = true
|
||||||
|
): number {
|
||||||
|
const distance = Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2);
|
||||||
|
return squared ? Math.sqrt(distance) : distance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import * as EasyStar from "easystarjs";
|
import * as EasyStar from "easystarjs";
|
||||||
|
import { MathUtils } from "./MathUtils";
|
||||||
|
|
||||||
export class PathfindingManager {
|
export class PathfindingManager {
|
||||||
private scene: Phaser.Scene;
|
private scene: Phaser.Scene;
|
||||||
|
|
||||||
private easyStar;
|
private easyStar;
|
||||||
|
private grid: number[][];
|
||||||
|
|
||||||
constructor(scene: Phaser.Scene, collisionsGrid: number[][]) {
|
constructor(scene: Phaser.Scene, collisionsGrid: number[][]) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
@ -11,17 +13,79 @@ export class PathfindingManager {
|
|||||||
this.easyStar = new EasyStar.js();
|
this.easyStar = new EasyStar.js();
|
||||||
this.easyStar.enableDiagonals();
|
this.easyStar.enableDiagonals();
|
||||||
|
|
||||||
this.setGrid(collisionsGrid);
|
this.grid = collisionsGrid;
|
||||||
|
this.setEasyStarGrid(collisionsGrid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async findPath(
|
public async findPath(
|
||||||
|
start: { x: number; y: number },
|
||||||
|
end: { x: number; y: number },
|
||||||
|
tryFindingNearestAvailable: boolean = false
|
||||||
|
): Promise<{ x: number; y: number }[]> {
|
||||||
|
let endPoints: { x: number; y: number }[] = [end];
|
||||||
|
if (tryFindingNearestAvailable) {
|
||||||
|
endPoints = [
|
||||||
|
end,
|
||||||
|
...this.getNeighbouringTiles(end).sort((a, b) => {
|
||||||
|
const aDist = MathUtils.distanceBetween(a, start, false);
|
||||||
|
const bDist = MathUtils.distanceBetween(b, start, false);
|
||||||
|
if (aDist > bDist) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (aDist < bDist) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
let path: { x: number; y: number }[] = [];
|
||||||
|
while (endPoints.length > 0) {
|
||||||
|
const endPoint = endPoints.shift();
|
||||||
|
if (!endPoint) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
// rejected Promise will return undefined for path
|
||||||
|
path = await this.getPath(start, endPoint).catch();
|
||||||
|
if (path && path.length > 0) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private getNeighbouringTiles(tile: { x: number; y: number }): { x: number; y: number }[] {
|
||||||
|
const xOffsets = [-1, 0, 1, 1, 1, 0, -1, -1];
|
||||||
|
const yOffsets = [-1, -1, -1, 0, 1, 1, 1, 0];
|
||||||
|
|
||||||
|
const neighbours: { x: number; y: number }[] = [];
|
||||||
|
for (let i = 0; i < 8; i += 1) {
|
||||||
|
const tileToCheck = { x: tile.x + xOffsets[i], y: tile.y + yOffsets[i] };
|
||||||
|
if (this.isTileWithinMap(tileToCheck)) {
|
||||||
|
neighbours.push(tileToCheck);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return neighbours;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isTileWithinMap(tile: { x: number; y: number }): boolean {
|
||||||
|
const mapHeight = this.grid.length ?? 0;
|
||||||
|
const mapWidth = this.grid[0]?.length ?? 0;
|
||||||
|
|
||||||
|
return MathUtils.isBetween(tile.x, 0, mapWidth) && MathUtils.isBetween(tile.y, 0, mapHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns empty array if path was not found
|
||||||
|
*/
|
||||||
|
private async getPath(
|
||||||
start: { x: number; y: number },
|
start: { x: number; y: number },
|
||||||
end: { x: number; y: number }
|
end: { x: number; y: number }
|
||||||
): Promise<{ x: number; y: number }[]> {
|
): Promise<{ x: number; y: number }[]> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.easyStar.findPath(start.x, start.y, end.x, end.y, (path) => {
|
this.easyStar.findPath(start.x, start.y, end.x, end.y, (path) => {
|
||||||
if (path === null) {
|
if (path === null) {
|
||||||
reject("Path was not found");
|
resolve([]);
|
||||||
} else {
|
} else {
|
||||||
resolve(path);
|
resolve(path);
|
||||||
}
|
}
|
||||||
@ -30,7 +94,7 @@ export class PathfindingManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private setGrid(grid: number[][]): void {
|
private setEasyStarGrid(grid: number[][]): void {
|
||||||
this.easyStar.setGrid(grid);
|
this.easyStar.setGrid(grid);
|
||||||
this.easyStar.setAcceptableTiles([0]); // zeroes are walkable
|
this.easyStar.setAcceptableTiles([0]); // zeroes are walkable
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user