ActivatablesManager and little cleanup

This commit is contained in:
Hanusiak Piotr 2022-01-27 15:15:18 +01:00
parent 68c4a5f5ce
commit 8b8c24f6ef
3 changed files with 107 additions and 131 deletions

View File

@ -0,0 +1,94 @@
import { isOutlineable } from '../../Utils/CustomTypeGuards';
import { MathUtils } from '../../Utils/MathUtils';
import type { Player } from '../Player/Player';
import type { ActivatableInterface } from './ActivatableInterface';
export class ActivatablesManager {
// The item that can be selected by pressing the space key.
private selectedActivatableObjectByDistance?: ActivatableInterface;
private selectedActivatableObjectByPointer?: ActivatableInterface;
private activatableObjectsDistances: Map<ActivatableInterface, number> = new Map<ActivatableInterface, number>();
private currentPlayer: Player;
constructor(currentPlayer: Player) {
this.currentPlayer = currentPlayer;
}
public handlePointerOverActivatableObject(object: ActivatableInterface): void {
if (this.selectedActivatableObjectByPointer === object) {
return;
}
if (isOutlineable(this.selectedActivatableObjectByDistance)) {
this.selectedActivatableObjectByDistance?.characterFarAwayOutline();
}
if (isOutlineable(this.selectedActivatableObjectByPointer)) {
this.selectedActivatableObjectByPointer?.pointerOutOutline();
}
this.selectedActivatableObjectByPointer = object;
if (isOutlineable(this.selectedActivatableObjectByPointer)) {
this.selectedActivatableObjectByPointer?.pointerOverOutline();
}
}
public handlePointerOutActivatableObject(): void {
if (isOutlineable(this.selectedActivatableObjectByPointer)) {
this.selectedActivatableObjectByPointer?.pointerOutOutline();
}
this.selectedActivatableObjectByPointer = undefined;
if (isOutlineable(this.selectedActivatableObjectByDistance)) {
this.selectedActivatableObjectByDistance?.characterCloseByOutline();
}
}
public getSelectedActivatableObject(): ActivatableInterface | undefined {
return this.selectedActivatableObjectByPointer ?? this.selectedActivatableObjectByDistance;
}
public deduceSelectedActivatableObjectByDistance(): void {
const newNearestObject = this.findNearestActivatableObject();
if (this.selectedActivatableObjectByDistance === newNearestObject) {
return;
}
// update value but do not change the outline
if (this.selectedActivatableObjectByPointer) {
this.selectedActivatableObjectByDistance = newNearestObject;
return;
}
if (isOutlineable(this.selectedActivatableObjectByDistance)) {
this.selectedActivatableObjectByDistance?.characterFarAwayOutline();
}
this.selectedActivatableObjectByDistance = newNearestObject;
if (isOutlineable(this.selectedActivatableObjectByDistance)) {
this.selectedActivatableObjectByDistance?.characterCloseByOutline();
}
}
private findNearestActivatableObject(): ActivatableInterface | undefined {
let shortestDistance: number = Infinity;
let closestObject: ActivatableInterface | undefined = undefined;
for (const [object, distance] of this.activatableObjectsDistances.entries()) {
if (object.activationRadius > distance && shortestDistance > distance) {
shortestDistance = distance;
closestObject = object;
}
}
return closestObject;
}
public updateActivatableObjectsDistances(objects: ActivatableInterface[]): void {
const currentPlayerPos = this.currentPlayer.getPosition();
for (const object of objects) {
const distance = MathUtils.distanceBetween(currentPlayerPos, object.getPosition());
this.activatableObjectsDistances.set(object, distance);
}
}
public updateDistanceForSingleActivatableObject(object: ActivatableInterface): void {
this.activatableObjectsDistances.set(
object,
MathUtils.distanceBetween(this.currentPlayer.getPosition(), object.getPosition()),
);
}
}

View File

@ -49,6 +49,7 @@ import { GameMapPropertiesListener } from "./GameMapPropertiesListener";
import { analyticsClient } from "../../Administration/AnalyticsClient"; import { analyticsClient } from "../../Administration/AnalyticsClient";
import { GameMapProperties } from "./GameMapProperties"; import { GameMapProperties } from "./GameMapProperties";
import { PathfindingManager } from "../../Utils/PathfindingManager"; import { PathfindingManager } from "../../Utils/PathfindingManager";
import { ActivatablesManager } from './ActivatablesManager';
import type { import type {
GroupCreatedUpdatedMessageInterface, GroupCreatedUpdatedMessageInterface,
MessageUserMovedInterface, MessageUserMovedInterface,
@ -91,9 +92,6 @@ import { MapStore } from "../../Stores/Utils/MapStore";
import { followUsersColorStore } from "../../Stores/FollowStore"; import { followUsersColorStore } from "../../Stores/FollowStore";
import { GameSceneUserInputHandler } from "../UserInput/GameSceneUserInputHandler"; import { GameSceneUserInputHandler } from "../UserInput/GameSceneUserInputHandler";
import { locale } from "../../i18n/i18n-svelte"; import { locale } from "../../i18n/i18n-svelte";
import type { ActivatableInterface } from './ActivatableInterface';
import { MathUtils } from '../../Utils/MathUtils';
import { isOutlineable } from '../../Utils/CustomTypeGuards';
export interface GameSceneInitInterface { export interface GameSceneInitInterface {
initPosition: PointInterface | null; initPosition: PointInterface | null;
reconnecting: boolean; reconnecting: boolean;
@ -190,11 +188,6 @@ export class GameScene extends DirtyScene {
private gameMap!: GameMap; private gameMap!: GameMap;
private actionableItems: Map<number, ActionableItem> = new Map<number, ActionableItem>(); private actionableItems: Map<number, ActionableItem> = new Map<number, ActionableItem>();
// The item that can be selected by pressing the space key.
private selectedActivatableObjectByDistance?: ActivatableInterface;
private selectedActivatableObjectByPointer?: ActivatableInterface;
private activatableObjectsDistances: Map<ActivatableInterface, number> = new Map<ActivatableInterface, number>();
private outlinedItem: ActionableItem | null = null;
public userInputManager!: UserInputManager; public userInputManager!: UserInputManager;
private isReconnecting: boolean | undefined = undefined; private isReconnecting: boolean | undefined = undefined;
private playerName!: string; private playerName!: string;
@ -208,6 +201,7 @@ export class GameScene extends DirtyScene {
private emoteManager!: EmoteManager; private emoteManager!: EmoteManager;
private cameraManager!: CameraManager; private cameraManager!: CameraManager;
private pathfindingManager!: PathfindingManager; private pathfindingManager!: PathfindingManager;
private activatablesManager!: ActivatablesManager;
private preloading: boolean = true; private preloading: boolean = true;
private startPositionCalculator!: StartPositionCalculator; private startPositionCalculator!: StartPositionCalculator;
private sharedVariablesManager!: SharedVariablesManager; private sharedVariablesManager!: SharedVariablesManager;
@ -580,6 +574,8 @@ export class GameScene extends DirtyScene {
this.gameMap.getTileDimensions() this.gameMap.getTileDimensions()
); );
this.activatablesManager = new ActivatablesManager(this.CurrentPlayer);
biggestAvailableAreaStore.recompute(); biggestAvailableAreaStore.recompute();
this.cameraManager.startFollowPlayer(this.CurrentPlayer); this.cameraManager.startFollowPlayer(this.CurrentPlayer);
@ -685,10 +681,6 @@ export class GameScene extends DirtyScene {
); );
} }
public activateOutlinedItem(): void {
this.outlinedItem?.activate();
}
/** /**
* Initializes the connection to Pusher. * Initializes the connection to Pusher.
*/ */
@ -1683,56 +1675,8 @@ ${escapedMessage}
//listen event to share position of user //listen event to share position of user
this.pushPlayerPosition(event); this.pushPlayerPosition(event);
this.gameMap.setPosition(event.x, event.y); this.gameMap.setPosition(event.x, event.y);
this.updateActivatableObjectsDistances(); this.activatablesManager.updateActivatableObjectsDistances([...Array.from(this.MapPlayersByKey.values()), ...this.actionableItems.values()]);
this.deduceSelectedActivatableObjectByDistance(); this.activatablesManager.deduceSelectedActivatableObjectByDistance();
// this.outlineItem(event);
}
private deduceSelectedActivatableObjectByDistance(): void {
const newNearestObject = this.findNearestActivatableObject();
if (this.selectedActivatableObjectByDistance === newNearestObject) {
return;
}
// update value but do not change the outline
if (this.selectedActivatableObjectByPointer) {
this.selectedActivatableObjectByDistance = newNearestObject;
return;
}
if (isOutlineable(this.selectedActivatableObjectByDistance)) {
this.selectedActivatableObjectByDistance?.characterFarAwayOutline();
}
this.selectedActivatableObjectByDistance = newNearestObject;
if (isOutlineable(this.selectedActivatableObjectByDistance)) {
this.selectedActivatableObjectByDistance?.characterCloseByOutline();
}
}
private updateDistanceForSingleActivatableObject(object: ActivatableInterface): void {
this.activatableObjectsDistances.set(
object,
MathUtils.distanceBetween(this.CurrentPlayer.getPosition(), object.getPosition()),
);
}
private updateActivatableObjectsDistances(): void {
const currentPlayerPos = this.CurrentPlayer.getPosition();
for (const object of [...Array.from(this.MapPlayersByKey.values()), ...this.actionableItems.values()]) {
const distance = MathUtils.distanceBetween(currentPlayerPos, object.getPosition());
this.activatableObjectsDistances.set(object, distance);
}
}
private findNearestActivatableObject(): ActivatableInterface | undefined {
let shortestDistance: number = Infinity;
let closestObject: ActivatableInterface | undefined = undefined;
for (const [object, distance] of this.activatableObjectsDistances.entries()) {
if (object.activationRadius > distance && shortestDistance > distance) {
shortestDistance = distance;
closestObject = object;
}
}
return closestObject;
} }
private createCollisionWithPlayer() { private createCollisionWithPlayer() {
@ -1822,49 +1766,6 @@ ${escapedMessage}
// Otherwise, do nothing. // Otherwise, do nothing.
} }
/**
* Finds the correct item to outline and outline it (if there is an item to be outlined)
* @param event
*/
private outlineItem(event: HasPlayerMovedEvent): void {
let x = event.x;
let y = event.y;
switch (event.direction) {
case PlayerAnimationDirections.Up:
y -= 32;
break;
case PlayerAnimationDirections.Down:
y += 32;
break;
case PlayerAnimationDirections.Left:
x -= 32;
break;
case PlayerAnimationDirections.Right:
x += 32;
break;
default:
throw new Error('Unexpected direction "' + event.direction + '"');
}
let shortestDistance: number = Infinity;
let selectedItem: ActionableItem | null = null;
for (const item of this.actionableItems.values()) {
const distance = item.actionableDistance(x, y);
if (distance !== null && distance < shortestDistance) {
shortestDistance = distance;
selectedItem = item;
}
}
if (this.outlinedItem === selectedItem) {
return;
}
this.outlinedItem?.notSelectable();
this.outlinedItem = selectedItem;
this.outlinedItem?.selectable();
}
private doPushPlayerPosition(event: HasPlayerMovedEvent): void { private doPushPlayerPosition(event: HasPlayerMovedEvent): void {
this.lastMoveEventSent = event; this.lastMoveEventSent = event;
this.lastSentTick = this.currentTick; this.lastSentTick = this.currentTick;
@ -1905,8 +1806,8 @@ ${escapedMessage}
this.doUpdatePlayerPosition(event.event); this.doUpdatePlayerPosition(event.event);
const remotePlayer = this.MapPlayersByKey.get(event.event.userId); const remotePlayer = this.MapPlayersByKey.get(event.event.userId);
if (remotePlayer) { if (remotePlayer) {
this.updateDistanceForSingleActivatableObject(remotePlayer); this.activatablesManager.updateDistanceForSingleActivatableObject(remotePlayer);
this.deduceSelectedActivatableObjectByDistance(); this.activatablesManager.deduceSelectedActivatableObjectByDistance();
} }
break; break;
case "GroupCreatedUpdatedEvent": case "GroupCreatedUpdatedEvent":
@ -2002,30 +1903,12 @@ ${escapedMessage}
player.updatePosition(addPlayerData.position); player.updatePosition(addPlayerData.position);
player.on(Phaser.Input.Events.POINTER_OVER, () => { player.on(Phaser.Input.Events.POINTER_OVER, () => {
if (this.selectedActivatableObjectByPointer === player) { this.activatablesManager.handlePointerOverActivatableObject(player);
return;
}
if (isOutlineable(this.selectedActivatableObjectByDistance)) {
this.selectedActivatableObjectByDistance?.characterFarAwayOutline();
}
if (isOutlineable(this.selectedActivatableObjectByPointer)) {
this.selectedActivatableObjectByPointer?.pointerOutOutline();
}
this.selectedActivatableObjectByPointer = player;
if (isOutlineable(this.selectedActivatableObjectByPointer)) {
this.selectedActivatableObjectByPointer?.pointerOverOutline();
}
this.markDirty(); this.markDirty();
}); });
player.on(Phaser.Input.Events.POINTER_OUT, () => { player.on(Phaser.Input.Events.POINTER_OUT, () => {
if (isOutlineable(this.selectedActivatableObjectByPointer)) { this.activatablesManager.handlePointerOutActivatableObject();
this.selectedActivatableObjectByPointer?.pointerOutOutline();
}
this.selectedActivatableObjectByPointer = undefined;
if (isOutlineable(this.selectedActivatableObjectByDistance)) {
this.selectedActivatableObjectByDistance?.characterCloseByOutline();
}
this.markDirty(); this.markDirty();
}); });
} }
@ -2295,7 +2178,7 @@ ${escapedMessage}
return this.pathfindingManager; return this.pathfindingManager;
} }
public getSelectedActivatableObject(): ActivatableInterface | undefined { public getActivatablesManager(): ActivatablesManager {
return this.selectedActivatableObjectByPointer ?? this.selectedActivatableObjectByDistance; return this.activatablesManager;
} }
} }

View File

@ -53,8 +53,7 @@ export class GameSceneUserInputHandler implements UserInputHandlerInterface {
public handlePointerDownEvent(pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]): void {} public handlePointerDownEvent(pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]): void {}
public handleSpaceKeyUpEvent(event: Event): Event { public handleSpaceKeyUpEvent(event: Event): Event {
this.gameScene.activateOutlinedItem(); this.gameScene.getActivatablesManager().getSelectedActivatableObject()?.activate();
this.gameScene.getSelectedActivatableObject()?.activate();
return event; return event;
} }
} }