go from zones to area name for interactive Tiled Objects

This commit is contained in:
Piotr 'pwh' Hanusiak 2022-04-11 16:16:52 +02:00
parent 2fa504a189
commit 255f4375da
6 changed files with 90 additions and 72 deletions

View File

@ -1,6 +1,6 @@
import * as tg from "generic-type-guard"; import * as tg from "generic-type-guard";
export const isChangeZoneEvent = new tg.IsInterface() export const isChangeAreaEvent = new tg.IsInterface()
.withProperties({ .withProperties({
name: tg.isString, name: tg.isString,
}) })
@ -8,4 +8,4 @@ export const isChangeZoneEvent = new tg.IsInterface()
/** /**
* A message sent from the game to the iFrame when a user enters or leaves a zone. * A message sent from the game to the iFrame when a user enters or leaves a zone.
*/ */
export type ChangeZoneEvent = tg.GuardedType<typeof isChangeZoneEvent>; export type ChangeAreaEvent = tg.GuardedType<typeof isChangeAreaEvent>;

View File

@ -31,7 +31,7 @@ import type { MenuRegisterEvent, UnregisterMenuEvent } from "./ui/MenuRegisterEv
import type { ChangeLayerEvent } from "./ChangeLayerEvent"; import type { ChangeLayerEvent } from "./ChangeLayerEvent";
import { isPlayerPosition } from "./PlayerPosition"; import { isPlayerPosition } from "./PlayerPosition";
import type { WasCameraUpdatedEvent } from "./WasCameraUpdatedEvent"; import type { WasCameraUpdatedEvent } from "./WasCameraUpdatedEvent";
import type { ChangeZoneEvent } from "./ChangeZoneEvent"; import type { ChangeAreaEvent } from "./ChangeAreaEvent";
import type { CameraSetEvent } from "./CameraSetEvent"; import type { CameraSetEvent } from "./CameraSetEvent";
import type { CameraFollowPlayerEvent } from "./CameraFollowPlayerEvent"; import type { CameraFollowPlayerEvent } from "./CameraFollowPlayerEvent";
import { isColorEvent } from "./ColorEvent"; import { isColorEvent } from "./ColorEvent";
@ -95,8 +95,8 @@ export interface IframeResponseEventMap {
leaveEvent: EnterLeaveEvent; leaveEvent: EnterLeaveEvent;
enterLayerEvent: ChangeLayerEvent; enterLayerEvent: ChangeLayerEvent;
leaveLayerEvent: ChangeLayerEvent; leaveLayerEvent: ChangeLayerEvent;
enterZoneEvent: ChangeZoneEvent; enterAreaEvent: ChangeAreaEvent;
leaveZoneEvent: ChangeZoneEvent; leaveAreaEvent: ChangeAreaEvent;
buttonClickedEvent: ButtonClickedEvent; buttonClickedEvent: ButtonClickedEvent;
remotePlayerClickedEvent: RemotePlayerClickedEvent; remotePlayerClickedEvent: RemotePlayerClickedEvent;
actionsMenuActionClickedEvent: ActionsMenuActionClickedEvent; actionsMenuActionClickedEvent: ActionsMenuActionClickedEvent;

View File

@ -31,7 +31,7 @@ import { ModifyEmbeddedWebsiteEvent, isEmbeddedWebsiteEvent } from "./Events/Emb
import { handleMenuRegistrationEvent, handleMenuUnregisterEvent } from "../Stores/MenuStore"; import { handleMenuRegistrationEvent, handleMenuUnregisterEvent } from "../Stores/MenuStore";
import type { ChangeLayerEvent } from "./Events/ChangeLayerEvent"; import type { ChangeLayerEvent } from "./Events/ChangeLayerEvent";
import type { WasCameraUpdatedEvent } from "./Events/WasCameraUpdatedEvent"; import type { WasCameraUpdatedEvent } from "./Events/WasCameraUpdatedEvent";
import type { ChangeZoneEvent } from "./Events/ChangeZoneEvent"; import type { ChangeAreaEvent } from "./Events/ChangeAreaEvent";
import { CameraSetEvent, isCameraSetEvent } from "./Events/CameraSetEvent"; import { CameraSetEvent, isCameraSetEvent } from "./Events/CameraSetEvent";
import { CameraFollowPlayerEvent, isCameraFollowPlayerEvent } from "./Events/CameraFollowPlayerEvent"; import { CameraFollowPlayerEvent, isCameraFollowPlayerEvent } from "./Events/CameraFollowPlayerEvent";
import type { RemotePlayerClickedEvent } from "./Events/RemotePlayerClickedEvent"; import type { RemotePlayerClickedEvent } from "./Events/RemotePlayerClickedEvent";
@ -441,21 +441,21 @@ class IframeListener {
}); });
} }
sendEnterZoneEvent(zoneName: string) { sendEnterAreaEvent(areaName: string) {
this.postMessage({ this.postMessage({
type: "enterZoneEvent", type: "enterAreaEvent",
data: { data: {
name: zoneName, name: areaName,
} as ChangeZoneEvent, } as ChangeAreaEvent,
}); });
} }
sendLeaveZoneEvent(zoneName: string) { sendLeaveAreaEvent(areaName: string) {
this.postMessage({ this.postMessage({
type: "leaveZoneEvent", type: "leaveAreaEvent",
data: { data: {
name: zoneName, name: areaName,
} as ChangeZoneEvent, } as ChangeAreaEvent,
}); });
} }

View File

@ -22,9 +22,9 @@ export type layerChangeCallback = (
allLayersOnNewPosition: Array<ITiledMapLayer> allLayersOnNewPosition: Array<ITiledMapLayer>
) => void; ) => void;
export type zoneChangeCallback = ( export type areaChangeCallback = (
zonesChangedByAction: Array<ITiledMapObject>, areasChangedByAction: Array<ITiledMapObject>,
allZonesOnNewPosition: Array<ITiledMapObject> allAreasOnNewPosition: Array<ITiledMapObject>
) => void; ) => void;
/** /**
@ -54,8 +54,8 @@ export class GameMap {
private enterLayerCallbacks = Array<layerChangeCallback>(); private enterLayerCallbacks = Array<layerChangeCallback>();
private leaveLayerCallbacks = Array<layerChangeCallback>(); private leaveLayerCallbacks = Array<layerChangeCallback>();
private enterZoneCallbacks = Array<zoneChangeCallback>(); private enterAreaCallbacks = Array<areaChangeCallback>();
private leaveZoneCallbacks = Array<zoneChangeCallback>(); private leaveAreaCallbacks = Array<areaChangeCallback>();
private tileNameMap = new Map<string, number>(); private tileNameMap = new Map<string, number>();
@ -63,7 +63,7 @@ export class GameMap {
public readonly flatLayers: ITiledMapLayer[]; public readonly flatLayers: ITiledMapLayer[];
public readonly tiledObjects: ITiledMapObject[]; public readonly tiledObjects: ITiledMapObject[];
public readonly phaserLayers: TilemapLayer[] = []; public readonly phaserLayers: TilemapLayer[] = [];
public readonly zones: ITiledMapObject[] = []; public readonly areas: ITiledMapObject[] = [];
public exitUrls: Array<string> = []; public exitUrls: Array<string> = [];
@ -76,7 +76,8 @@ export class GameMap {
) { ) {
this.flatLayers = flattenGroupLayersMap(map); this.flatLayers = flattenGroupLayersMap(map);
this.tiledObjects = this.getObjectsFromLayers(this.flatLayers); this.tiledObjects = this.getObjectsFromLayers(this.flatLayers);
this.zones = this.tiledObjects.filter((object) => object.width > 0); // NOTE: We leave "zone" for legacy reasons
this.areas = this.tiledObjects.filter((object) => ["zone", "area"].includes(object.type));
let depth = -2; let depth = -2;
for (const layer of this.flatLayers) { for (const layer of this.flatLayers) {
@ -148,7 +149,7 @@ export class GameMap {
public setPosition(x: number, y: number) { public setPosition(x: number, y: number) {
this.oldPosition = this.position; this.oldPosition = this.position;
this.position = { x, y }; this.position = { x, y };
this.triggerZonesChange(); this.triggerAreasChange();
this.oldKey = this.key; this.oldKey = this.key;
@ -201,17 +202,17 @@ export class GameMap {
} }
/** /**
* Registers a callback called when the user moves inside another zone. * Registers a callback called when the user moves inside another area.
*/ */
public onEnterZone(callback: zoneChangeCallback) { public onEnterArea(callback: areaChangeCallback) {
this.enterZoneCallbacks.push(callback); this.enterAreaCallbacks.push(callback);
} }
/** /**
* Registers a callback called when the user moves outside another zone. * Registers a callback called when the user moves outside another area.
*/ */
public onLeaveZone(callback: zoneChangeCallback) { public onLeaveArea(callback: areaChangeCallback) {
this.leaveZoneCallbacks.push(callback); this.leaveAreaCallbacks.push(callback);
} }
public findLayer(layerName: string): ITiledMapLayer | undefined { public findLayer(layerName: string): ITiledMapLayer | undefined {
@ -420,33 +421,33 @@ export class GameMap {
} }
/** /**
* We use Tiled Objects with type "zone" as zones with defined x, y, width and height for easier event triggering. * We use Tiled Objects with type "area" as areas with defined x, y, width and height for easier event triggering.
*/ */
private triggerZonesChange(): void { private triggerAreasChange(): void {
const zonesByOldPosition = this.getZonesOnPosition(this.oldPosition); const areasByOldPosition = this.getAreasOnPosition(this.oldPosition);
const zonesByNewPosition = this.getZonesOnPosition(this.position); const areasByNewPosition = this.getAreasOnPosition(this.position);
const enterZones = new Set(zonesByNewPosition); const enterAreas = new Set(areasByNewPosition);
const leaveZones = new Set(zonesByOldPosition); const leaveAreas = new Set(areasByOldPosition);
enterZones.forEach((zone) => { enterAreas.forEach((area) => {
if (leaveZones.has(zone)) { if (leaveAreas.has(area)) {
leaveZones.delete(zone); leaveAreas.delete(area);
enterZones.delete(zone); enterAreas.delete(area);
} }
}); });
if (enterZones.size > 0) { if (enterAreas.size > 0) {
const zonesArray = Array.from(enterZones); const areasArray = Array.from(enterAreas);
for (const callback of this.enterZoneCallbacks) { for (const callback of this.enterAreaCallbacks) {
callback(zonesArray, zonesByNewPosition); callback(areasArray, areasByNewPosition);
} }
} }
if (leaveZones.size > 0) { if (leaveAreas.size > 0) {
const zonesArray = Array.from(leaveZones); const areasArray = Array.from(leaveAreas);
for (const callback of this.leaveZoneCallbacks) { for (const callback of this.leaveAreaCallbacks) {
callback(zonesArray, zonesByNewPosition); callback(areasArray, areasByNewPosition);
} }
} }
} }
@ -454,9 +455,9 @@ export class GameMap {
private getProperties(key: number): Map<string, string | boolean | number> { private getProperties(key: number): Map<string, string | boolean | number> {
const properties = new Map<string, string | boolean | number>(); const properties = new Map<string, string | boolean | number>();
for (const zone of this.getZonesOnPosition(this.position)) { for (const area of this.getAreasOnPosition(this.position)) {
if (zone.properties !== undefined) { if (area.properties !== undefined) {
for (const property of zone.properties) { for (const property of area.properties) {
if (property.value === undefined) { if (property.value === undefined) {
continue; continue;
} }
@ -503,13 +504,13 @@ export class GameMap {
return properties; return properties;
} }
private getZonesOnPosition(position?: { x: number; y: number }): ITiledMapObject[] { private getAreasOnPosition(position?: { x: number; y: number }): ITiledMapObject[] {
return position return position
? this.zones.filter((zone) => { ? this.areas.filter((area) => {
if (!position) { if (!position) {
return false; return false;
} }
return MathUtils.isOverlappingWithRectangle(position, zone); return MathUtils.isOverlappingWithRectangle(position, area);
}) })
: []; : [];
} }

View File

@ -892,42 +892,42 @@ export class GameScene extends DirtyScene {
}); });
}); });
this.gameMap.onEnterZone((zones) => { this.gameMap.onEnterArea((areas) => {
for (const zone of zones) { for (const area of areas) {
const focusable = zone.properties?.find( const focusable = area.properties?.find(
(property) => property.name === GameMapProperties.FOCUSABLE (property) => property.name === GameMapProperties.FOCUSABLE
); );
if (focusable && focusable.value === true) { if (focusable && focusable.value === true) {
const zoomMargin = zone.properties?.find( const zoomMargin = area.properties?.find(
(property) => property.name === GameMapProperties.ZOOM_MARGIN (property) => property.name === GameMapProperties.ZOOM_MARGIN
); );
this.cameraManager.enterFocusMode( this.cameraManager.enterFocusMode(
{ {
x: zone.x + zone.width * 0.5, x: area.x + area.width * 0.5,
y: zone.y + zone.height * 0.5, y: area.y + area.height * 0.5,
width: zone.width, width: area.width,
height: zone.height, height: area.height,
}, },
zoomMargin ? Math.max(0, Number(zoomMargin.value)) : undefined zoomMargin ? Math.max(0, Number(zoomMargin.value)) : undefined
); );
break; break;
} }
} }
zones.forEach((zone) => { areas.forEach((area) => {
iframeListener.sendEnterZoneEvent(zone.name); iframeListener.sendEnterAreaEvent(area.name);
}); });
}); });
this.gameMap.onLeaveZone((zones) => { this.gameMap.onLeaveArea((areas) => {
for (const zone of zones) { for (const area of areas) {
const focusable = zone.properties?.find((property) => property.name === "focusable"); const focusable = area.properties?.find((property) => property.name === "focusable");
if (focusable && focusable.value === true) { if (focusable && focusable.value === true) {
this.cameraManager.leaveFocusMode(this.CurrentPlayer, 1000); this.cameraManager.leaveFocusMode(this.CurrentPlayer, 1000);
break; break;
} }
} }
zones.forEach((zone) => { areas.forEach((area) => {
iframeListener.sendLeaveZoneEvent(zone.name); iframeListener.sendLeaveAreaEvent(area.name);
}); });
}); });

View File

@ -27,7 +27,7 @@
"y":0 "y":0
}, },
{ {
"data":[201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 223, 223, 223, 223, 223, 223, 201, 201, 201, 201, 201, 234, 234, 234, 234, 234, 234, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 223, 223, 223, 223, 223, 223, 201, 201, 201, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 223, 223, 223, 223, 223, 223, 201, 201, 201, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 223, 223, 223, 223, 223, 223, 201, 201, 201, 201, 201, 234, 234, 234, 234, 234, 234, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 234, 234, 234, 234, 234, 234, 234, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 234, 234, 234, 234, 234, 234, 234, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 234, 234, 234, 234, 234, 234, 234, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201], "data":[201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 223, 223, 223, 223, 223, 223, 201, 201, 201, 201, 201, 234, 234, 234, 234, 234, 234, 201, 201, 201, 201, 201, 201, 201, 223, 223, 223, 201, 201, 201, 201, 223, 223, 223, 223, 223, 223, 201, 201, 201, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 201, 201, 201, 201, 201, 223, 223, 223, 201, 201, 201, 201, 223, 223, 223, 223, 223, 223, 201, 201, 201, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 223, 223, 223, 223, 223, 223, 201, 201, 201, 201, 201, 234, 234, 234, 234, 234, 234, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 234, 234, 234, 234, 234, 234, 234, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 234, 234, 234, 234, 234, 234, 234, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 234, 234, 234, 234, 234, 234, 234, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201],
"height":17, "height":17,
"id":4, "id":4,
"name":"floor", "name":"floor",
@ -72,7 +72,7 @@
"value":"onaction" "value":"onaction"
}], }],
"rotation":0, "rotation":0,
"type":"", "type":"area",
"visible":true, "visible":true,
"width":320, "width":320,
"x":317.331510594668, "x":317.331510594668,
@ -89,7 +89,7 @@
"value":"MeetingRoom" "value":"MeetingRoom"
}], }],
"rotation":0, "rotation":0,
"type":"", "type":"area",
"visible":true, "visible":true,
"width":192.568694463431, "width":192.568694463431,
"x":30.738664843928, "x":30.738664843928,
@ -106,11 +106,28 @@
"value":true "value":true
}], }],
"rotation":0, "rotation":0,
"type":"", "type":"area",
"visible":true, "visible":true,
"width":225.115516062885, "width":225.115516062885,
"x":735.919799498747, "x":735.919799498747,
"y":354.398724082935 "y":354.398724082935
},
{
"height":63.2854864433812,
"id":13,
"name":"",
"properties":[
{
"name":"openWebsite",
"type":"string",
"value":"https:\/\/youtu.be\/iF-ucIgP0OE?list=RDGMEMWO-g6DgCWEqKlDtKbJA1GwVMiF-ucIgP0OE"
}],
"rotation":0,
"type":"area",
"visible":true,
"width":96.736386420597,
"x":799.205285942128,
"y":96.736386420597
}], }],
"opacity":1, "opacity":1,
"type":"objectgroup", "type":"objectgroup",
@ -119,7 +136,7 @@
"y":0 "y":0
}], }],
"nextlayerid":39, "nextlayerid":39,
"nextobjectid":13, "nextobjectid":15,
"orientation":"orthogonal", "orientation":"orthogonal",
"properties":[ "properties":[
{ {