import { Actor } from "./actor"; import { DIRECTION } from "../utils"; import { MoveTo, PathFinder, Board, } from "../phaser3-rex-plugins/plugins/board-components"; import { Label } from "../phaser3-rex-plugins/templates/ui/ui-components"; import { COLOR_DARK, COLOR_LIGHT, COLOR_PRIMARY } from "../constants"; import { TownScene } from "../scenes"; import eventsCenter from "./event_center"; export class NPC extends Actor { private moveTo: MoveTo; private board: Board; private canMove: boolean = true; private talkWithPlayer: boolean = false; private path: PathFinder.NodeType[] = []; private finalDirection: number = undefined; private targetLocation: string = undefined; private targetNPC: NPC = undefined; private textBox: Label = undefined; public id: number; public direction: number = DIRECTION.DOWN; constructor( scene: Phaser.Scene, board: Board, x: number, y: number, name: string, id: number ) { super(scene, x, y, name); this.setName(name); this.board = board; this.id = id; // PHYSICS this.getBody().setSize(14, 16); this.getBody().setOffset(0, 4); this.getBody().setImmovable(true); this.setOrigin(0, 0.2); this.initAnimations(); this.moveTo = this.scene.rexBoard.add.moveTo(this, { speed: 55, sneak: true, }); this.listenToDirectionEvent(); } update(): void { if (this.path.length > 0 && !this.moveTo.isRunning && this.canMove) { var tileXY = this.board.worldXYToTileXY(this.x, this.y); if (tileXY.x == this.path[0].x) { if (tileXY.y < this.path[0].y) this.changeDirection(DIRECTION.DOWN); else if (tileXY.y > this.path[0].y) this.changeDirection(DIRECTION.UP); } else if (tileXY.y == this.path[0].y) { if (tileXY.x < this.path[0].x) this.changeDirection(DIRECTION.RIGHT); else if (tileXY.x > this.path[0].x) this.changeDirection(DIRECTION.LEFT); } var move = this.moveTo.moveTo(this.path.shift()); move.removeAllListeners("complete"); move.on("complete", () => { if (this.path.length == 0) { this.changeDirection(this.finalDirection); this.emitTurnEvent(); if (this.targetLocation != undefined) { fetch("http://127.0.0.1:10002/update_location", { method: "POST", headers: { "Content-Type": "application/json", }, credentials: "same-origin", body: JSON.stringify({ agent_locations: { [this.name]: this.targetLocation, }, }), }); } } }); } var text = ""; switch (this.direction) { case DIRECTION.UP: text = "up"; break; case DIRECTION.DOWN: text = "down"; break; case DIRECTION.LEFT: text = "left"; break; case DIRECTION.RIGHT: text = "right"; break; } this.anims.play(this.name + "-walk-" + text, true); if (this.anims.isPlaying && !this.moveTo.isRunning) this.anims.setCurrentFrame(this.anims.currentAnim!.frames[0]); this.updateTextBox(); this.depth = this.y + this.height * 0.8; } listenToDirectionEvent(): void { eventsCenter.on(this.name + "-up", () => { this.changeDirection(DIRECTION.UP); }); eventsCenter.on(this.name + "-down", () => { this.changeDirection(DIRECTION.DOWN); }); eventsCenter.on(this.name + "-left", () => { this.changeDirection(DIRECTION.LEFT); }); eventsCenter.on(this.name + "-right", () => { this.changeDirection(DIRECTION.RIGHT); }); } emitTurnEvent(): void { // Make the listener NPC turn to the speaker NPC. if (this.targetNPC == undefined) return; var direction = ""; switch (this.finalDirection) { case DIRECTION.UP: direction = "down"; break; case DIRECTION.DOWN: direction = "up"; break; case DIRECTION.LEFT: direction = "right"; break; case DIRECTION.RIGHT: direction = "left"; break; } eventsCenter.emit(this.targetNPC.name + "-" + direction); this.setTargetNPC(); } updateTextBox(): void { if (this.textBox == undefined) return; this.textBox.setOrigin(0.5, 1.0); var scale = this.scene.cameras.main.zoom; this.textBox.setX(this.x + this.width / 2); this.textBox.setY(this.y - this.height * 0.2); this.textBox.depth = this.y + this.height * 0.8; this.textBox.getChildren().forEach((child) => { child.setDepth(this.y + this.height * 0.8); }); } public setTextBox(text: string): void { this.destroyTextBox(); var scale = this.scene.cameras.main.zoom; var scene = this.scene as TownScene; this.textBox = scene.rexUI.add .label({ x: this.x + this.width / 2, y: this.y - this.height * 0.2, width: 24 * scale, orientation: "x", background: scene.rexUI.add.roundRectangle( 0, 0, 2, 2, 20, COLOR_PRIMARY, 0.7 ), text: scene.rexUI.wrapExpandText( scene.add.text(0, 0, text, { fontSize: 10, }) ), expandTextWidth: true, space: { left: 10, right: 10, top: 10, bottom: 10, }, }) .setOrigin(0.5, 1.0) .setScale(1 / scale, 1 / scale) .setDepth(this.y + this.height * 0.8) .layout(); } public destroyTextBox(): void { if (this.textBox != undefined) this.textBox.destroy(); this.textBox = undefined; } public changeDirection(direction: number): void { if (direction == undefined) return; this.direction = direction; } public moveAlongPath( path: PathFinder.NodeType[], finalDirection: number = undefined, targetLocation: string = undefined ): void { if (path.length == 0) return; if (this.moveTo.isRunning) return; if (this.path.length > 0) return; this.path = path; this.finalDirection = finalDirection; this.targetLocation = targetLocation; } public pauseMoving(): void { this.moveTo.stop(); this.canMove = false; } public resumeMoving(): void { this.moveTo.resume(); this.canMove = true; } public isMoving(): boolean { return this.moveTo.isRunning || this.path.length > 0; } public isTalking(): boolean { return this.talkWithPlayer; } public setTalking(talking: boolean): void { this.talkWithPlayer = talking; } public setTargetNPC(targetNPC: NPC = undefined): void { this.targetNPC = targetNPC; } }