Activatable objects handling WIP

This commit is contained in:
Hanusiak Piotr 2022-01-26 12:57:10 +01:00
parent 5ae039b987
commit 3af6461c01
5 changed files with 89 additions and 37 deletions

View File

@ -140,6 +140,10 @@ export abstract class Character extends Container {
}
}
public getPosition(): { x: number, y: number } {
return { x: this.x, y: this.y };
}
private async getSnapshot(): Promise<string> {
const sprites = Array.from(this.sprites.values()).map((sprite) => {
return { sprite, frame: 1 };

View File

@ -6,14 +6,17 @@ import type { GameScene } from "../Game/GameScene";
import type { PointInterface } from "../../Connexion/ConnexionModels";
import type { PlayerAnimationDirections } from "../Player/Animation";
import type { Unsubscriber } from 'svelte/store';
import type { ActivatableInterface } from '../Game/ActivatableInterface';
/**
* Class representing the sprite of a remote player (a player that plays on another computer)
*/
export class RemotePlayer extends Character {
userId: number;
private visitCardUrl: string | null;
export class RemotePlayer extends Character implements ActivatableInterface {
public userId: number;
public readonly activationRadius: number;
private visitCardUrl: string | null;
private isActionsMenuInitialized: boolean = false;
private actionsMenuStoreUnsubscriber: Unsubscriber;
@ -28,7 +31,8 @@ export class RemotePlayer extends Character {
moving: boolean,
visitCardUrl: string | null,
companion: string | null,
companionTexturePromise?: Promise<string>
companionTexturePromise?: Promise<string>,
activationRadius?: number,
) {
super(
Scene,
@ -46,23 +50,13 @@ export class RemotePlayer extends Character {
//set data
this.userId = userId;
this.activationRadius = activationRadius ?? 96;
this.visitCardUrl = visitCardUrl;
this.actionsMenuStoreUnsubscriber = actionsMenuStore.subscribe((value: ActionsMenuData | undefined) => {
this.isActionsMenuInitialized = value ? true : false;
});
this.on(Phaser.Input.Events.POINTER_DOWN, (event: Phaser.Input.Pointer) => {
if (event.downElement.nodeName === "CANVAS") {
if (this.isActionsMenuInitialized) {
actionsMenuStore.clear();
return;
}
actionsMenuStore.initialize(this.playerName);
for (const action of this.getActionsMenuActions()) {
actionsMenuStore.addAction(action.actionName, action.callback);
}
}
});
this.bindEventHandlers();
}
public updatePosition(position: PointInterface): void {
@ -77,12 +71,27 @@ export class RemotePlayer extends Character {
}
}
public activate(): void {
this.toggleActionsMenu();
}
public destroy(): void {
this.actionsMenuStoreUnsubscriber();
actionsMenuStore.clear();
super.destroy();
}
private toggleActionsMenu(): void {
if (this.isActionsMenuInitialized) {
actionsMenuStore.clear();
return;
}
actionsMenuStore.initialize(this.playerName);
for (const action of this.getActionsMenuActions()) {
actionsMenuStore.addAction(action.actionName, action.callback);
}
}
private getActionsMenuActions(): { actionName: string, callback: Function }[] {
return [
{
@ -112,4 +121,12 @@ export class RemotePlayer extends Character {
},
];
}
private bindEventHandlers(): void {
this.on(Phaser.Input.Events.POINTER_DOWN, (event: Phaser.Input.Pointer) => {
if (event.downElement.nodeName === "CANVAS") {
this.toggleActionsMenu();
}
});
}
}

View File

@ -0,0 +1,6 @@
export interface ActivatableInterface {
readonly activationRadius: number;
activate: () => void;
getPosition: () => { x: number, y: number };
}

View File

@ -12,7 +12,7 @@ import { UserInputManager } from "../UserInput/UserInputManager";
import { gameManager } from "./GameManager";
import { touchScreenManager } from "../../Touch/TouchScreenManager";
import { PinchManager } from "../UserInput/PinchManager";
import { waScaleManager, WaScaleManagerEvent } from "../Services/WaScaleManager";
import { waScaleManager } from "../Services/WaScaleManager";
import { EmoteManager } from "./EmoteManager";
import { soundManager } from "./SoundManager";
import { SharedVariablesManager } from "./SharedVariablesManager";
@ -89,9 +89,10 @@ import { deepCopy } from "deep-copy-ts";
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
import { MapStore } from "../../Stores/Utils/MapStore";
import { followUsersColorStore } from "../../Stores/FollowStore";
import Camera = Phaser.Cameras.Scene2D.Camera;
import { GameSceneUserInputHandler } from "../UserInput/GameSceneUserInputHandler";
import { locale } from "../../i18n/i18n-svelte";
import type { ActivatableInterface } from './ActivatableInterface';
import { MathUtils } from '../../Utils/MathUtils';
export interface GameSceneInitInterface {
initPosition: PointInterface | null;
@ -190,6 +191,7 @@ export class GameScene extends DirtyScene {
private gameMap!: GameMap;
private actionableItems: Map<number, ActionableItem> = new Map<number, ActionableItem>();
// The item that can be selected by pressing the space key.
private nearestActivatableObject?: ActivatableInterface;
private outlinedItem: ActionableItem | null = null;
public userInputManager!: UserInputManager;
private isReconnecting: boolean | undefined = undefined;
@ -806,12 +808,10 @@ export class GameScene extends DirtyScene {
this.simplePeer = new SimplePeer(this.connection);
userMessageManager.setReceiveBanListener(this.bannedUser.bind(this));
//listen event to share position of user
this.CurrentPlayer.on(hasMovedEventName, this.pushPlayerPosition.bind(this));
this.CurrentPlayer.on(hasMovedEventName, this.outlineItem.bind(this));
this.CurrentPlayer.on(hasMovedEventName, (event: HasPlayerMovedEvent) => {
this.gameMap.setPosition(event.x, event.y);
});
this.CurrentPlayer.on(
hasMovedEventName,
(event: HasPlayerMovedEvent) => { this.handleCurrentPlayerHasMovedEvent(event); },
);
// Set up variables manager
this.sharedVariablesManager = new SharedVariablesManager(
@ -1676,7 +1676,30 @@ ${escapedMessage}
}
}
createCollisionWithPlayer() {
private handleCurrentPlayerHasMovedEvent(event: HasPlayerMovedEvent): void {
//listen event to share position of user
this.pushPlayerPosition(event);
this.nearestActivatableObject = this.getNearestActivatableObject();
this.outlineItem(event);
this.gameMap.setPosition(event.x, event.y);
}
private getNearestActivatableObject(): ActivatableInterface | undefined {
let shortestDistance: number = Infinity;
let closestObject: ActivatableInterface | undefined = undefined;
const currentPlayerPos = this.CurrentPlayer.getPosition();
for (const object of [...Array.from(this.MapPlayersByKey.values()), ...this.actionableItems.values()]) {
const distance = MathUtils.distanceBetween(currentPlayerPos, object.getPosition());
if (object.activationRadius > distance && shortestDistance > distance) {
shortestDistance = distance;
closestObject = object;
}
}
return closestObject;
}
private createCollisionWithPlayer() {
//add collision layer
for (const phaserLayer of this.gameMap.phaserLayers) {
this.physics.add.collider(this.CurrentPlayer, phaserLayer, (object1: GameObject, object2: GameObject) => {
@ -1695,7 +1718,7 @@ ${escapedMessage}
}
}
createCurrentPlayer() {
private createCurrentPlayer() {
//TODO create animation moving between exit and start
const texturesPromise = lazyLoadPlayerCharacterTextures(this.load, this.characterLayers);
try {
@ -1737,7 +1760,7 @@ ${escapedMessage}
this.createCollisionWithPlayer();
}
pushPlayerPosition(event: HasPlayerMovedEvent) {
private pushPlayerPosition(event: HasPlayerMovedEvent) {
if (this.lastMoveEventSent === event) {
return;
}
@ -1823,7 +1846,7 @@ ${escapedMessage}
* @param time
* @param delta The delta time in ms since the last frame. This is a smoothed and capped value based on the FPS rate.
*/
update(time: number, delta: number): void {
public update(time: number, delta: number): void {
this.dirty = false;
this.currentTick = time;
this.CurrentPlayer.moveUser(delta, this.userInputManager.getEventListForGameTick());
@ -1965,7 +1988,7 @@ ${escapedMessage}
this.playersPositionInterpolator.removePlayer(userId);
}
public updatePlayerPosition(message: MessageUserMovedInterface): void {
private updatePlayerPosition(message: MessageUserMovedInterface): void {
this.pendingEvents.enqueue({
type: "UserMovedEvent",
event: message,
@ -1995,7 +2018,7 @@ ${escapedMessage}
this.playersPositionInterpolator.updatePlayerPosition(player.userId, playerMovement);
}
public shareGroupPosition(groupPositionMessage: GroupCreatedUpdatedMessageInterface) {
private shareGroupPosition(groupPositionMessage: GroupCreatedUpdatedMessageInterface) {
this.pendingEvents.enqueue({
type: "GroupCreatedUpdatedEvent",
event: groupPositionMessage,
@ -2094,7 +2117,7 @@ ${escapedMessage}
biggestAvailableAreaStore.recompute();
}
public startJitsi(roomName: string, jwt?: string): void {
private startJitsi(roomName: string, jwt?: string): void {
const allProps = this.gameMap.getCurrentProperties();
const jitsiConfig = this.safeParseJSONstring(
allProps.get(GameMapProperties.JITSI_CONFIG) as string | undefined,
@ -2120,7 +2143,7 @@ ${escapedMessage}
});
}
public stopJitsi(): void {
private stopJitsi(): void {
const silent = this.gameMap.getCurrentProperties().get(GameMapProperties.SILENT);
this.connection?.setSilent(!!silent);
jitsiFactory.stop();

View File

@ -5,10 +5,11 @@
import Sprite = Phaser.GameObjects.Sprite;
import type { GameScene } from "../Game/GameScene";
import type OutlinePipelinePlugin from "phaser3-rex-plugins/plugins/outlinepipeline-plugin.js";
import type { ActivatableInterface } from '../Game/ActivatableInterface';
type EventCallback = (state: unknown, parameters: unknown) => void;
export class ActionableItem {
export class ActionableItem implements ActivatableInterface{
private readonly activationRadiusSquared: number;
private isSelectable: boolean = false;
private callbacks: Map<string, Array<EventCallback>> = new Map<string, Array<EventCallback>>();
@ -17,7 +18,7 @@ export class ActionableItem {
private id: number,
private sprite: Sprite,
private eventHandler: GameScene,
private activationRadius: number,
public readonly activationRadius: number,
private onActivateCallback: (item: ActionableItem) => void
) {
this.activationRadiusSquared = activationRadius * activationRadius;
@ -40,6 +41,10 @@ export class ActionableItem {
}
}
public getPosition(): { x: number, y: number } {
return { x: this.sprite.x, y: this.sprite.y };
}
/**
* Show the outline of the sprite.
*/
@ -70,9 +75,6 @@ export class ActionableItem {
return this.sprite.scene.plugins.get("rexOutlinePipeline") as unknown as OutlinePipelinePlugin | undefined;
}
/**
* Triggered when the "space" key is pressed and the object is in range of being activated.
*/
public activate(): void {
this.onActivateCallback(this);
}