for pathfinding we are now taking into consideration all tiles, looking for 'collides' property

This commit is contained in:
Hanusiak Piotr 2022-01-18 10:26:40 +01:00
parent 7576cea7e0
commit 391fe7eed3
3 changed files with 167 additions and 146 deletions

View File

@ -115,15 +115,11 @@ export class GameMap {
}
public getCollisionsGrid(): number[][] {
const collisionsLayer = this.findPhaserLayer("collisions");
if (!collisionsLayer) {
return [];
}
const grid: number[][] = [];
for (let y = 0; y < collisionsLayer.height; y += 1) {
for (let y = 0; y < this.map.height; y += 1) {
const row: number[] = [];
for (let x = 0; x < collisionsLayer.width; x += 1) {
row.push(collisionsLayer.getTileAt(x, y) ? 1 : 0);
for (let x = 0; x < this.map.width; x += 1) {
row.push(this.isCollidingAt(x, y) ? 1 : 0);
}
grid.push(row);
}
@ -138,10 +134,6 @@ export class GameMap {
return { x: Math.floor(x / this.map.tilewidth), y: Math.floor(y / this.map.tileheight) };
}
private getLayersByKey(key: number): Array<ITiledMapLayer> {
return this.flatLayers.filter((flatLayer) => flatLayer.type === "tilelayer" && flatLayer.data[key] !== 0);
}
/**
* Sets the position of the current player (in pixels)
* This will trigger events if properties are changing.
@ -167,6 +159,151 @@ export class GameMap {
this.triggerLayersChange();
}
public getCurrentProperties(): Map<string, string | boolean | number> {
return this.lastProperties;
}
public getMap(): ITiledMap {
return this.map;
}
/**
* Registers a callback called when the user moves to a tile where the property propName is different from the last tile the user was on.
*/
public onPropertyChange(propName: string, callback: PropertyChangeCallback) {
let callbacksArray = this.propertiesChangeCallbacks.get(propName);
if (callbacksArray === undefined) {
callbacksArray = new Array<PropertyChangeCallback>();
this.propertiesChangeCallbacks.set(propName, callbacksArray);
}
callbacksArray.push(callback);
}
/**
* Registers a callback called when the user moves inside another layer.
*/
public onEnterLayer(callback: layerChangeCallback) {
this.enterLayerCallbacks.push(callback);
}
/**
* Registers a callback called when the user moves outside another layer.
*/
public onLeaveLayer(callback: layerChangeCallback) {
this.leaveLayerCallbacks.push(callback);
}
/**
* Registers a callback called when the user moves inside another zone.
*/
public onEnterZone(callback: zoneChangeCallback) {
this.enterZoneCallbacks.push(callback);
}
/**
* Registers a callback called when the user moves outside another zone.
*/
public onLeaveZone(callback: zoneChangeCallback) {
this.leaveZoneCallbacks.push(callback);
}
public findLayer(layerName: string): ITiledMapLayer | undefined {
return this.flatLayers.find((layer) => layer.name === layerName);
}
public findPhaserLayer(layerName: string): TilemapLayer | undefined {
return this.phaserLayers.find((layer) => layer.layer.name === layerName);
}
public findPhaserLayers(groupName: string): TilemapLayer[] {
return this.phaserLayers.filter((l) => l.layer.name.includes(groupName));
}
public addTerrain(terrain: Phaser.Tilemaps.Tileset): void {
for (const phaserLayer of this.phaserLayers) {
phaserLayer.tileset.push(terrain);
}
}
public putTile(tile: string | number | null, x: number, y: number, layer: string): void {
const phaserLayer = this.findPhaserLayer(layer);
if (phaserLayer) {
if (tile === null) {
phaserLayer.putTileAt(-1, x, y);
return;
}
const tileIndex = this.getIndexForTileType(tile);
if (tileIndex !== undefined) {
this.putTileInFlatLayer(tileIndex, x, y, layer);
const phaserTile = phaserLayer.putTileAt(tileIndex, x, y);
for (const property of this.getTileProperty(tileIndex)) {
if (property.name === GameMapProperties.COLLIDES && property.value) {
phaserTile.setCollision(true);
}
}
} else {
console.error("The tile '" + tile + "' that you want to place doesn't exist.");
}
} else {
console.error("The layer '" + layer + "' does not exist (or is not a tilelaye).");
}
}
public setLayerProperty(
layerName: string,
propertyName: string,
propertyValue: string | number | undefined | boolean
) {
const layer = this.findLayer(layerName);
if (layer === undefined) {
console.warn('Could not find layer "' + layerName + '" when calling setProperty');
return;
}
if (layer.properties === undefined) {
layer.properties = [];
}
const property = layer.properties.find((property) => property.name === propertyName);
if (property === undefined) {
if (propertyValue === undefined) {
return;
}
layer.properties.push({ name: propertyName, type: typeof propertyValue, value: propertyValue });
return;
}
if (propertyValue === undefined) {
const index = layer.properties.indexOf(property);
layer.properties.splice(index, 1);
}
property.value = propertyValue;
this.triggerAllProperties();
this.triggerLayersChange();
}
/**
* Trigger all the callbacks (used when exiting a map)
*/
public triggerExitCallbacks(): void {
const emptyProps = new Map<string, string | boolean | number>();
for (const [oldPropName, oldPropValue] of this.lastProperties.entries()) {
// We found a property that disappeared
this.trigger(oldPropName, oldPropValue, undefined, emptyProps);
}
}
private getLayersByKey(key: number): Array<ITiledMapLayer> {
return this.flatLayers.filter((flatLayer) => flatLayer.type === "tilelayer" && flatLayer.data[key] !== 0);
}
private isCollidingAt(x: number, y: number): boolean {
for (const layer of this.phaserLayers) {
if (layer.getTileAt(x, y)?.properties[GameMapProperties.COLLIDES]) {
return true;
}
}
return false;
}
private triggerAllProperties(): void {
const newProps = this.getProperties(this.key ?? 0);
const oldProps = this.lastProperties;
@ -265,10 +402,6 @@ export class GameMap {
}
}
public getCurrentProperties(): Map<string, string | boolean | number> {
return this.lastProperties;
}
private getProperties(key: number): Map<string, string | boolean | number> {
const properties = new Map<string, string | boolean | number>();
@ -310,10 +443,6 @@ export class GameMap {
return properties;
}
public getMap(): ITiledMap {
return this.map;
}
private getTileProperty(index: number): Array<ITiledMapProperty> {
if (this.tileSetPropertyMap[index]) {
return this.tileSetPropertyMap[index];
@ -335,64 +464,6 @@ export class GameMap {
}
}
/**
* Registers a callback called when the user moves to a tile where the property propName is different from the last tile the user was on.
*/
public onPropertyChange(propName: string, callback: PropertyChangeCallback) {
let callbacksArray = this.propertiesChangeCallbacks.get(propName);
if (callbacksArray === undefined) {
callbacksArray = new Array<PropertyChangeCallback>();
this.propertiesChangeCallbacks.set(propName, callbacksArray);
}
callbacksArray.push(callback);
}
/**
* Registers a callback called when the user moves inside another layer.
*/
public onEnterLayer(callback: layerChangeCallback) {
this.enterLayerCallbacks.push(callback);
}
/**
* Registers a callback called when the user moves outside another layer.
*/
public onLeaveLayer(callback: layerChangeCallback) {
this.leaveLayerCallbacks.push(callback);
}
/**
* Registers a callback called when the user moves inside another zone.
*/
public onEnterZone(callback: zoneChangeCallback) {
this.enterZoneCallbacks.push(callback);
}
/**
* Registers a callback called when the user moves outside another zone.
*/
public onLeaveZone(callback: zoneChangeCallback) {
this.leaveZoneCallbacks.push(callback);
}
public findLayer(layerName: string): ITiledMapLayer | undefined {
return this.flatLayers.find((layer) => layer.name === layerName);
}
public findPhaserLayer(layerName: string): TilemapLayer | undefined {
return this.phaserLayers.find((layer) => layer.layer.name === layerName);
}
public findPhaserLayers(groupName: string): TilemapLayer[] {
return this.phaserLayers.filter((l) => l.layer.name.includes(groupName));
}
public addTerrain(terrain: Phaser.Tilemaps.Tileset): void {
for (const phaserLayer of this.phaserLayers) {
phaserLayer.tileset.push(terrain);
}
}
private putTileInFlatLayer(index: number, x: number, y: number, layer: string): void {
const fLayer = this.findLayer(layer);
if (fLayer == undefined) {
@ -414,30 +485,6 @@ export class GameMap {
fLayer.data[x + y * fLayer.width] = index;
}
public putTile(tile: string | number | null, x: number, y: number, layer: string): void {
const phaserLayer = this.findPhaserLayer(layer);
if (phaserLayer) {
if (tile === null) {
phaserLayer.putTileAt(-1, x, y);
return;
}
const tileIndex = this.getIndexForTileType(tile);
if (tileIndex !== undefined) {
this.putTileInFlatLayer(tileIndex, x, y, layer);
const phaserTile = phaserLayer.putTileAt(tileIndex, x, y);
for (const property of this.getTileProperty(tileIndex)) {
if (property.name === GameMapProperties.COLLIDES && property.value) {
phaserTile.setCollision(true);
}
}
} else {
console.error("The tile '" + tile + "' that you want to place doesn't exist.");
}
} else {
console.error("The layer '" + layer + "' does not exist (or is not a tilelaye).");
}
}
private getIndexForTileType(tile: string | number): number | undefined {
if (typeof tile == "number") {
return tile;
@ -445,48 +492,6 @@ export class GameMap {
return this.tileNameMap.get(tile);
}
public setLayerProperty(
layerName: string,
propertyName: string,
propertyValue: string | number | undefined | boolean
) {
const layer = this.findLayer(layerName);
if (layer === undefined) {
console.warn('Could not find layer "' + layerName + '" when calling setProperty');
return;
}
if (layer.properties === undefined) {
layer.properties = [];
}
const property = layer.properties.find((property) => property.name === propertyName);
if (property === undefined) {
if (propertyValue === undefined) {
return;
}
layer.properties.push({ name: propertyName, type: typeof propertyValue, value: propertyValue });
return;
}
if (propertyValue === undefined) {
const index = layer.properties.indexOf(property);
layer.properties.splice(index, 1);
}
property.value = propertyValue;
this.triggerAllProperties();
this.triggerLayersChange();
}
/**
* Trigger all the callbacks (used when exiting a map)
*/
public triggerExitCallbacks(): void {
const emptyProps = new Map<string, string | boolean | number>();
for (const [oldPropName, oldPropValue] of this.lastProperties.entries()) {
// We found a property that disappeared
this.trigger(oldPropName, oldPropValue, undefined, emptyProps);
}
}
private getObjectsFromLayers(layers: ITiledMapLayer[]): ITiledMapObject[] {
const objects: ITiledMapObject[] = [];

View File

@ -42,12 +42,16 @@ export class Player extends Character {
}
}
if (this.pathToFollow && activeUserInputEvents.anyExcept(UserInputEvent.SpeedUp)) {
this.pathToFollow = undefined;
}
let x = 0;
let y = 0;
if ((state === "active" || state === "ending") && role === "follower") {
[x, y] = this.computeFollowMovement();
}
if (this.pathToFollow && this.pathToFollow.length !== 0) {
if (this.pathToFollow) {
[x, y] = this.computeFollowPathMovement();
}
this.inputStep(activeUserInputEvents, x, y);
@ -144,7 +148,10 @@ export class Player extends Character {
}
private computeFollowPathMovement(): number[] {
if (!this.pathToFollow || this.pathToFollow.length === 0) {
if (this.pathToFollow?.length === 0) {
this.pathToFollow = undefined;
}
if (!this.pathToFollow) {
return [0, 0];
}
const nextStep = this.pathToFollow[0];
@ -153,7 +160,7 @@ export class Player extends Character {
const xDistance = nextStep.x - this.x;
const yDistance = nextStep.y - this.y;
const distance = Math.pow(xDistance, 2) + Math.pow(yDistance, 2);
if (distance < 10) {
if (distance < 200) {
this.pathToFollow.shift();
}
return this.getMovementDirection(xDistance, yDistance, distance);

View File

@ -37,6 +37,15 @@ export class ActiveEventList {
any(): boolean {
return Array.from(this.eventMap.values()).reduce((accu, curr) => accu || curr, false);
}
anyExcept(...exceptions: UserInputEvent[]): boolean {
const userInputEvents = Array.from(this.eventMap);
for (const event of userInputEvents) {
if (event[1] && !exceptions.includes(event[0])) {
return true;
}
}
return false;
}
}
//this class is responsible for catching user inputs and listing all active user actions at every game tick events.