diff --git a/front/src/Phaser/Game/GameMap.ts b/front/src/Phaser/Game/GameMap.ts index 6eeacd0c..fc16110f 100644 --- a/front/src/Phaser/Game/GameMap.ts +++ b/front/src/Phaser/Game/GameMap.ts @@ -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 { - 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 { + 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(); + 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(); + 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 { + 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 { - return this.lastProperties; - } - private getProperties(key: number): Map { const properties = new Map(); @@ -310,10 +443,6 @@ export class GameMap { return properties; } - public getMap(): ITiledMap { - return this.map; - } - private getTileProperty(index: number): Array { 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(); - 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(); - 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[] = []; diff --git a/front/src/Phaser/Player/Player.ts b/front/src/Phaser/Player/Player.ts index e01b351f..451a057b 100644 --- a/front/src/Phaser/Player/Player.ts +++ b/front/src/Phaser/Player/Player.ts @@ -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); diff --git a/front/src/Phaser/UserInput/UserInputManager.ts b/front/src/Phaser/UserInput/UserInputManager.ts index 56ca87a6..57ac43aa 100644 --- a/front/src/Phaser/UserInput/UserInputManager.ts +++ b/front/src/Phaser/UserInput/UserInputManager.ts @@ -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.