camera zoom using scaleManager zooming. WIP

This commit is contained in:
Hanusiak Piotr 2021-12-02 13:20:40 +01:00
parent eecf831ca5
commit 85bf2fe70d
6 changed files with 155 additions and 34 deletions

View File

@ -0,0 +1,70 @@
import { Easing } from '../../types';
import { HtmlUtils } from '../../WebRtc/HtmlUtils';
import type { Box } from '../../WebRtc/LayoutManager';
import type { WaScaleManager } from '../Services/WaScaleManager';
import type { GameScene } from './GameScene';
export class CameraManager extends Phaser.Events.EventEmitter {
private scene: GameScene;
private camera: Phaser.Cameras.Scene2D.Camera;
private waScaleManager: WaScaleManager;
private cameraBounds: { x: number, y: number };
constructor(scene: GameScene, cameraBounds: { x: number, y: number }, waScaleManager: WaScaleManager) {
super();
this.scene = scene;
this.camera = scene.cameras.main;
this.cameraBounds = cameraBounds;
this.waScaleManager = waScaleManager;
this.initCamera();
}
public getCamera(): Phaser.Cameras.Scene2D.Camera {
return this.camera;
}
public changeCameraFocus(focusOn: { x: number, y: number, width: number, height: number }, duration: number = 1000): void {
const maxZoomModifier = 2.84; // How to get max zoom value?
const currentZoomModifier = this.waScaleManager.zoomModifier;
const zoomModifierChange = maxZoomModifier - currentZoomModifier;
this.camera.stopFollow();
this.camera.pan(
focusOn.x + focusOn.width * 0.5,
focusOn.y + focusOn.height * 0.5,
duration,
Easing.SineEaseOut, false, (camera, progress, x, y) => {
this.scene.setZoomModifierTo(currentZoomModifier + progress * zoomModifierChange);
});
}
public startFollow(target: object | Phaser.GameObjects.GameObject): void {
this.camera.startFollow(target, true);
}
/**
* Updates the offset of the character compared to the center of the screen according to the layout manager
* (tries to put the character in the center of the remaining space if there is a discussion going on.
*/
public updateCameraOffset(array: Box): void {
const xCenter = (array.xEnd - array.xStart) / 2 + array.xStart;
const yCenter = (array.yEnd - array.yStart) / 2 + array.yStart;
const game = HtmlUtils.querySelectorOrFail<HTMLCanvasElement>("#game canvas");
// Let's put this in Game coordinates by applying the zoom level:
this.camera.setFollowOffset(
((xCenter - game.offsetWidth / 2) * window.devicePixelRatio) / this.scene.scale.zoom,
((yCenter - game.offsetHeight / 2) * window.devicePixelRatio) / this.scene.scale.zoom
);
}
private initCamera() {
this.camera = this.scene.cameras.main;
this.camera.setBounds(0, 0, this.cameraBounds.x, this.cameraBounds.y);
}
}

View File

@ -192,6 +192,7 @@ export class GameMap {
const zones = this.tiledObjects.filter(object => object.type === "zone"); const zones = this.tiledObjects.filter(object => object.type === "zone");
// P.H. NOTE: We could also get all of the zones and add properties of occupied tiles to them, so we could later on check collision by using tileKeys // P.H. NOTE: We could also get all of the zones and add properties of occupied tiles to them, so we could later on check collision by using tileKeys
// TODO: Change this to an array with currently occupied sone instead of doing elimination process
const zonesByOldPosition = this.oldPosition ? const zonesByOldPosition = this.oldPosition ?
zones.filter((zone) => { zones.filter((zone) => {
if (!this.oldPosition) { if (!this.oldPosition) {

View File

@ -60,6 +60,7 @@ import { PinchManager } from "../UserInput/PinchManager";
import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey } from "../Components/MobileJoystick"; import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey } from "../Components/MobileJoystick";
import { waScaleManager } from "../Services/WaScaleManager"; import { waScaleManager } from "../Services/WaScaleManager";
import { EmoteManager } from "./EmoteManager"; import { EmoteManager } from "./EmoteManager";
import { CameraManager } from './CameraManager';
import EVENT_TYPE = Phaser.Scenes.Events; import EVENT_TYPE = Phaser.Scenes.Events;
import type { HasPlayerMovedEvent } from "../../Api/Events/HasPlayerMovedEvent"; import type { HasPlayerMovedEvent } from "../../Api/Events/HasPlayerMovedEvent";
@ -198,6 +199,7 @@ export class GameScene extends DirtyScene {
private pinchManager: PinchManager | undefined; private pinchManager: PinchManager | undefined;
private mapTransitioning: boolean = false; //used to prevent transitions happening at the same time. private mapTransitioning: boolean = false; //used to prevent transitions happening at the same time.
private emoteManager!: EmoteManager; private emoteManager!: EmoteManager;
private cameraManager!: CameraManager;
private preloading: boolean = true; private preloading: boolean = true;
private startPositionCalculator!: StartPositionCalculator; private startPositionCalculator!: StartPositionCalculator;
private sharedVariablesManager!: SharedVariablesManager; private sharedVariablesManager!: SharedVariablesManager;
@ -549,7 +551,9 @@ export class GameScene extends DirtyScene {
this.createCurrentPlayer(); this.createCurrentPlayer();
this.removeAllRemotePlayers(); //cleanup the list of remote players in case the scene was rebooted this.removeAllRemotePlayers(); //cleanup the list of remote players in case the scene was rebooted
this.initCamera(); this.cameraManager = new CameraManager(this, { x: this.Map.widthInPixels, y: this.Map.heightInPixels }, waScaleManager);
biggestAvailableAreaStore.recompute();
this.cameraManager.startFollow(this.CurrentPlayer);
this.animatedTiles.init(this.Map); this.animatedTiles.init(this.Map);
this.events.on("tileanimationupdate", () => (this.dirty = true)); this.events.on("tileanimationupdate", () => (this.dirty = true));
@ -590,7 +594,7 @@ export class GameScene extends DirtyScene {
// From now, this game scene will be notified of reposition events // From now, this game scene will be notified of reposition events
this.biggestAvailableAreaStoreUnsubscribe = biggestAvailableAreaStore.subscribe((box) => this.biggestAvailableAreaStoreUnsubscribe = biggestAvailableAreaStore.subscribe((box) =>
this.updateCameraOffset(box) this.cameraManager.updateCameraOffset(box)
); );
new GameMapPropertiesListener(this, this.gameMap).register(); new GameMapPropertiesListener(this, this.gameMap).register();
@ -643,7 +647,7 @@ export class GameScene extends DirtyScene {
* Initializes the connection to Pusher. * Initializes the connection to Pusher.
*/ */
private connect(): void { private connect(): void {
const camera = this.cameras.main; const camera = this.cameraManager.getCamera();
connectionManager connectionManager
.connectToRoomSocket( .connectToRoomSocket(
@ -779,17 +783,30 @@ export class GameScene extends DirtyScene {
}); });
}); });
// P.H. TODO: Send those events to the iframe?
this.gameMap.onEnterZone((zones) => { this.gameMap.onEnterZone((zones) => {
console.log('enter zones'); for (const zone of zones) {
console.log(zones); for (const property of zone.properties ?? []) {
if (property.name === 'focusable' && property.value === true) {
this.cameraManager.changeCameraFocus(zone);
break;
}
}
}
// zones.forEach((zone) => { // zones.forEach((zone) => {
// iframeListener.sendEnterLayerEvent(zone.name); // iframeListener.sendEnterLayerEvent(zone.name);
// }); // });
}); });
this.gameMap.onLeaveZone((zones) => { this.gameMap.onLeaveZone((zones) => {
console.log('leave zones'); for (const zone of zones) {
console.log(zones); for (const property of zone.properties ?? []) {
if (property.name === 'focusable' && property.value === true) {
this.cameraManager.startFollow(this.CurrentPlayer);
break;
}
}
}
// zones.forEach((zone) => { // zones.forEach((zone) => {
// iframeListener.sendEnterLayerEvent(zone.name); // iframeListener.sendEnterLayerEvent(zone.name);
// }); // });
@ -1478,13 +1495,6 @@ ${escapedMessage}
} }
} }
//todo: in a dedicated class/function?
initCamera() {
this.cameras.main.setBounds(0, 0, this.Map.widthInPixels, this.Map.heightInPixels);
this.cameras.main.startFollow(this.CurrentPlayer, true);
biggestAvailableAreaStore.recompute();
}
createCollisionWithPlayer() { createCollisionWithPlayer() {
//add collision layer //add collision layer
for (const phaserLayer of this.gameMap.phaserLayers) { for (const phaserLayer of this.gameMap.phaserLayers) {
@ -1876,23 +1886,6 @@ ${escapedMessage}
biggestAvailableAreaStore.recompute(); biggestAvailableAreaStore.recompute();
} }
/**
* Updates the offset of the character compared to the center of the screen according to the layout manager
* (tries to put the character in the center of the remaining space if there is a discussion going on.
*/
private updateCameraOffset(array: Box): void {
const xCenter = (array.xEnd - array.xStart) / 2 + array.xStart;
const yCenter = (array.yEnd - array.yStart) / 2 + array.yStart;
const game = HtmlUtils.querySelectorOrFail<HTMLCanvasElement>("#game canvas");
// Let's put this in Game coordinates by applying the zoom level:
this.cameras.main.setFollowOffset(
((xCenter - game.offsetWidth / 2) * window.devicePixelRatio) / this.scale.zoom,
((yCenter - game.offsetHeight / 2) * window.devicePixelRatio) / this.scale.zoom
);
}
public startJitsi(roomName: string, jwt?: string): void { public startJitsi(roomName: string, jwt?: string): void {
const allProps = this.gameMap.getCurrentProperties(); const allProps = this.gameMap.getCurrentProperties();
const jitsiConfig = this.safeParseJSONstring( const jitsiConfig = this.safeParseJSONstring(
@ -1965,6 +1958,10 @@ ${escapedMessage}
biggestAvailableAreaStore.recompute(); biggestAvailableAreaStore.recompute();
} }
public setZoomModifierTo(value: number): void {
waScaleManager.zoomModifier = value;
}
public createSuccessorGameScene(autostart: boolean, reconnecting: boolean) { public createSuccessorGameScene(autostart: boolean, reconnecting: boolean) {
const gameSceneKey = "somekey" + Math.round(Math.random() * 10000); const gameSceneKey = "somekey" + Math.round(Math.random() * 10000);
const game = new GameScene(this.room, this.MapUrlFile, gameSceneKey); const game = new GameScene(this.room, this.MapUrlFile, gameSceneKey);

View File

@ -5,7 +5,7 @@ import type { Game } from "../Game/Game";
import { ResizableScene } from "../Login/ResizableScene"; import { ResizableScene } from "../Login/ResizableScene";
import { HtmlUtils } from "../../WebRtc/HtmlUtils"; import { HtmlUtils } from "../../WebRtc/HtmlUtils";
class WaScaleManager { export class WaScaleManager {
private hdpiManager: HdpiManager; private hdpiManager: HdpiManager;
private scaleManager!: ScaleManager; private scaleManager!: ScaleManager;
private game!: Game; private game!: Game;

View File

@ -21,3 +21,34 @@ export interface IVirtualJoystick extends Phaser.GameObjects.GameObject {
visible: boolean; visible: boolean;
createCursorKeys: () => CursorKeys; createCursorKeys: () => CursorKeys;
} }
export enum Easing {
Linear = "Linear",
QuadEaseIn = "Quad.easeIn",
CubicEaseIn = "Cubic.easeIn",
QuartEaseIn = "Quart.easeIn",
QuintEaseIn = "Quint.easeIn",
SineEaseIn = "Sine.easeIn",
ExpoEaseIn = "Expo.easeIn",
CircEaseIn = "Circ.easeIn",
BackEaseIn = "Back.easeIn",
BounceEaseIn = "Bounce.easeIn",
QuadEaseOut = "Quad.easeOut",
CubicEaseOut = "Cubic.easeOut",
QuartEaseOut = "Quart.easeOut",
QuintEaseOut = "Quint.easeOut",
SineEaseOut = "Sine.easeOut",
ExpoEaseOut = "Expo.easeOut",
CircEaseOut = "Circ.easeOut",
BackEaseOut = "Back.easeOut",
BounceEaseOut = "Bounce.easeOut",
QuadEaseInOut = "Quad.easeInOut",
CubicEaseInOut = "Cubic.easeInOut",
QuartEaseInOut = "Quart.easeInOut",
QuintEaseInOut = "Quint.easeInOut",
SineEaseInOut = "Sine.easeInOut",
ExpoEaseInOut = "Expo.easeInOut",
CircEaseInOut = "Circ.easeInOut",
BackEaseInOut = "Back.easeInOut",
BounceEaseInOut = "Bounce.easeInOut"
}

View File

@ -86,7 +86,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, 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, 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, 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, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 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, 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, 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, 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, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 212, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 212, 212, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 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",
@ -170,6 +170,28 @@
"width":192, "width":192,
"x":32, "x":32,
"y":96 "y":96
},
{
"height":64,
"id":11,
"name":"coffeeZone",
"properties":[
{
"name":"display_name",
"type":"string",
"value":"Coffee Time!"
},
{
"name":"focusable",
"type":"bool",
"value":true
}],
"rotation":0,
"type":"zone",
"visible":true,
"width":64,
"x":64,
"y":288
}], }],
"opacity":1, "opacity":1,
"type":"objectgroup", "type":"objectgroup",
@ -214,7 +236,7 @@
"y":0 "y":0
}], }],
"nextlayerid":39, "nextlayerid":39,
"nextobjectid":11, "nextobjectid":12,
"orientation":"orthogonal", "orientation":"orthogonal",
"properties":[ "properties":[
{ {