Adding HdpiManager to start and scale from a default resolution that is correct by default for the game.
Fixing VirtualJoystick on resize.
This commit is contained in:
parent
6a2326c4b3
commit
04d3cf8593
@ -10,8 +10,8 @@ const TURN_USER: string = process.env.TURN_USER || '';
|
||||
const TURN_PASSWORD: string = process.env.TURN_PASSWORD || '';
|
||||
const JITSI_URL : string|undefined = (process.env.JITSI_URL === '') ? undefined : process.env.JITSI_URL;
|
||||
const JITSI_PRIVATE_MODE : boolean = process.env.JITSI_PRIVATE_MODE == "true";
|
||||
const RESOLUTION = 1 / window.devicePixelRatio;
|
||||
const ZOOM_LEVEL = 2 * window.devicePixelRatio/*3/4*/;
|
||||
const RESOLUTION = 2;
|
||||
const ZOOM_LEVEL = 1;
|
||||
const POSITION_DELAY = 200; // Wait 200ms between sending position events
|
||||
const MAX_EXTRAPOLATION_TIME = 100; // Extrapolate a maximum of 250ms if no new movement is sent by the player
|
||||
export const MAX_USERNAME_LENGTH = parseInt(process.env.MAX_USERNAME_LENGTH || '') || 8;
|
||||
|
@ -1,4 +1,6 @@
|
||||
import VirtualJoystick from 'phaser3-rex-plugins/plugins/virtualjoystick.js';
|
||||
import ScaleManager = Phaser.Scale.ScaleManager;
|
||||
import {waScaleManager} from "../Services/WaScaleManager";
|
||||
|
||||
const outOfScreenX = -1000;
|
||||
const outOfScreenY = -1000;
|
||||
@ -11,6 +13,7 @@ export const joystickThumbKey = 'joystickThumb';
|
||||
export const joystickThumbImg = 'resources/objects/smallHandleFilledGrey.png';
|
||||
|
||||
export class MobileJoystick extends VirtualJoystick {
|
||||
private resizeCallback: () => void;
|
||||
|
||||
constructor(scene: Phaser.Scene) {
|
||||
super(scene, {
|
||||
@ -31,5 +34,18 @@ export class MobileJoystick extends VirtualJoystick {
|
||||
this.x = outOfScreenX;
|
||||
this.y = outOfScreenY;
|
||||
});
|
||||
this.resizeCallback = this.resize.bind(this);
|
||||
this.scene.scale.on(Phaser.Scale.Events.RESIZE, this.resizeCallback);
|
||||
}
|
||||
|
||||
private resize() {
|
||||
this.base.setDisplaySize(60 / waScaleManager.zoomModifier, 60 / waScaleManager.zoomModifier);
|
||||
this.thumb.setDisplaySize(30 / waScaleManager.zoomModifier, 30 / waScaleManager.zoomModifier);
|
||||
this.setRadius(20 / waScaleManager.zoomModifier);
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
super.destroy();
|
||||
this.scene.scale.removeListener(Phaser.Scale.Events.RESIZE, this.resizeCallback);
|
||||
}
|
||||
}
|
@ -81,6 +81,7 @@ import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoading
|
||||
import {touchScreenManager} from "../../Touch/TouchScreenManager";
|
||||
import {PinchManager} from "../UserInput/PinchManager";
|
||||
import {joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey} from "../Components/MobileJoystick";
|
||||
import {waScaleManager} from "../Services/WaScaleManager";
|
||||
|
||||
export interface GameSceneInitInterface {
|
||||
initPosition: PointInterface|null,
|
||||
@ -176,6 +177,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||
private popUpElements : Map<number, DOMElement> = new Map<number, Phaser.GameObjects.DOMElement>();
|
||||
private originalMapUrl: string|undefined;
|
||||
private cursorKeys: any;
|
||||
private pinchManager: PinchManager|undefined;
|
||||
|
||||
constructor(private room: Room, MapUrlFile: string, customKey?: string|undefined) {
|
||||
super({
|
||||
@ -364,7 +366,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||
this.startLayerName = urlManager.getStartLayerNameFromUrl();
|
||||
|
||||
if (touchScreenManager.supportTouchScreen) {
|
||||
new PinchManager(this);
|
||||
this.pinchManager = new PinchManager(this);
|
||||
}
|
||||
|
||||
this.messageSubscription = worldFullMessageStream.stream.subscribe((message) => this.showWorldFullError())
|
||||
@ -899,6 +901,8 @@ ${escapedMessage}
|
||||
this.simplePeer.closeAllConnections();
|
||||
this.simplePeer?.unregister();
|
||||
this.messageSubscription?.unsubscribe();
|
||||
this.userInputManager.destroy();
|
||||
this.pinchManager?.destroy();
|
||||
|
||||
for(const iframeEvents of this.iframeSubscriptionList){
|
||||
iframeEvents.unsubscribe();
|
||||
@ -1185,9 +1189,15 @@ ${escapedMessage}
|
||||
*/
|
||||
update(time: number, delta: number) : void {
|
||||
if (this.cursorKeys.up.isDown) {
|
||||
this.cameras.main.zoom *= 1.2;
|
||||
//this.cameras.main.zoom *= 1.2;
|
||||
//this.scale.setGameSize(this.scale.width * 1.2, this.scale.height * 1.2);
|
||||
waScaleManager.zoomModifier *= 1.2;
|
||||
this.updateCameraOffset();
|
||||
} else if(this.cursorKeys.down.isDown) {
|
||||
this.cameras.main.zoom *= 0.8;
|
||||
//this.scale.setGameSize(this.scale.width * 0.8, this.scale.height * 0.8);
|
||||
//this.cameras.main.zoom *= 0.8;
|
||||
waScaleManager.zoomModifier /= 1.2;
|
||||
this.updateCameraOffset();
|
||||
}
|
||||
|
||||
mediaManager.setLastUpdateScene();
|
||||
@ -1425,17 +1435,18 @@ ${escapedMessage}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the offset of the character compared to the center of the screen according to the layout mananger
|
||||
* (tries to put the character in the center of the reamining space if there is a discussion going on.
|
||||
* 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(): void {
|
||||
const array = layoutManager.findBiggestAvailableArray();
|
||||
let xCenter = (array.xEnd - array.xStart) / 2 + array.xStart;
|
||||
let 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 - this.game.renderer.width / 2, yCenter - this.game.renderer.height / 2);
|
||||
this.cameras.main.setFollowOffset((xCenter - game.offsetWidth/2) * window.devicePixelRatio / this.scale.zoom , (yCenter - game.offsetHeight/2) * window.devicePixelRatio / this.scale.zoom);
|
||||
}
|
||||
|
||||
public onCenterChange(): void {
|
||||
|
63
front/src/Phaser/Services/HdpiManager.ts
Normal file
63
front/src/Phaser/Services/HdpiManager.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import ScaleManager = Phaser.Scale.ScaleManager;
|
||||
|
||||
interface Size {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export class HdpiManager {
|
||||
private _zoomModifier: number = 1;
|
||||
|
||||
public constructor(private minGamePixelsNumber: number) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the optimal size in "game pixels" based on the screen size in "real pixels".
|
||||
*
|
||||
* Note: the function is returning the optimal size in "game pixels" in the "game" property,
|
||||
* but also recommends resizing the "real" pixel screen size of the canvas.
|
||||
* The proposed new real size is a few pixels bigger than the real size available (if the size is not a multiple of the pixel size) and should overflow.
|
||||
*
|
||||
* @param realPixelScreenSize
|
||||
*/
|
||||
public getOptimalGameSize(realPixelScreenSize: Size): { game: Size, real: Size } {
|
||||
const realPixelNumber = realPixelScreenSize.width * realPixelScreenSize.height;
|
||||
// If the screen has not a definition small enough to match the minimum number of pixels we want to display,
|
||||
// let's make the canvas the size of the screen (in real pixels)
|
||||
if (realPixelNumber <= this.minGamePixelsNumber) {
|
||||
return {
|
||||
game: realPixelScreenSize,
|
||||
real: realPixelScreenSize
|
||||
};
|
||||
}
|
||||
|
||||
let i = 1;
|
||||
|
||||
while (true) {
|
||||
if (realPixelNumber <= this.minGamePixelsNumber * i * i) {
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return {
|
||||
game: {
|
||||
width: Math.ceil(realPixelScreenSize.width / (i - 1) / this._zoomModifier),
|
||||
height: Math.ceil(realPixelScreenSize.height / (i - 1) / this._zoomModifier),
|
||||
},
|
||||
real: {
|
||||
width: Math.ceil(realPixelScreenSize.width / (i - 1)) * (i - 1),
|
||||
height: Math.ceil(realPixelScreenSize.height / (i - 1)) * (i - 1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get zoomModifier(): number {
|
||||
return this._zoomModifier;
|
||||
}
|
||||
|
||||
public set zoomModifier(zoomModifier: number) {
|
||||
this._zoomModifier = zoomModifier;
|
||||
}
|
||||
}
|
47
front/src/Phaser/Services/WaScaleManager.ts
Normal file
47
front/src/Phaser/Services/WaScaleManager.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import {HdpiManager} from "./HdpiManager";
|
||||
import ScaleManager = Phaser.Scale.ScaleManager;
|
||||
import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager";
|
||||
|
||||
|
||||
class WaScaleManager {
|
||||
private hdpiManager: HdpiManager;
|
||||
private scaleManager!: ScaleManager;
|
||||
|
||||
public constructor(private minGamePixelsNumber: number) {
|
||||
this.hdpiManager = new HdpiManager(minGamePixelsNumber);
|
||||
}
|
||||
|
||||
public setScaleManager(scaleManager: ScaleManager) {
|
||||
this.scaleManager = scaleManager;
|
||||
}
|
||||
|
||||
public applyNewSize() {
|
||||
const {width, height} = coWebsiteManager.getGameSize();
|
||||
|
||||
let devicePixelRatio = 1;
|
||||
if (window.devicePixelRatio) {
|
||||
devicePixelRatio = window.devicePixelRatio;
|
||||
}
|
||||
|
||||
const { game: gameSize, real: realSize } = this.hdpiManager.getOptimalGameSize({width: width * devicePixelRatio, height: height * devicePixelRatio});
|
||||
|
||||
this.scaleManager.setZoom(realSize.width / gameSize.width / devicePixelRatio);
|
||||
this.scaleManager.resize(gameSize.width, gameSize.height);
|
||||
|
||||
// Override bug in canvas resizing in Phaser. Let's resize the canvas ourselves
|
||||
const style = this.scaleManager.canvas.style;
|
||||
style.width = Math.ceil(realSize.width / devicePixelRatio) + 'px';
|
||||
style.height = Math.ceil(realSize.height / devicePixelRatio) + 'px';
|
||||
};
|
||||
|
||||
public get zoomModifier(): number {
|
||||
return this.hdpiManager.zoomModifier;
|
||||
}
|
||||
|
||||
public set zoomModifier(zoomModifier: number) {
|
||||
this.hdpiManager.zoomModifier = zoomModifier;
|
||||
this.applyNewSize();
|
||||
}
|
||||
}
|
||||
|
||||
export const waScaleManager = new WaScaleManager(640*480);
|
@ -1,4 +1,5 @@
|
||||
import {Pinch} from "phaser3-rex-plugins/plugins/gestures.js";
|
||||
import {waScaleManager} from "../Services/WaScaleManager";
|
||||
|
||||
export class PinchManager {
|
||||
private scene: Phaser.Scene;
|
||||
@ -9,14 +10,11 @@ export class PinchManager {
|
||||
this.pinch = new Pinch(scene);
|
||||
|
||||
this.pinch.on('pinch', (pinch:any) => { // eslint-disable-line
|
||||
let newZoom = this.scene.cameras.main.zoom * pinch.scaleFactor;
|
||||
if (newZoom < 0.25) {
|
||||
newZoom = 0.25;
|
||||
} else if(newZoom > 2) {
|
||||
newZoom = 2;
|
||||
}
|
||||
this.scene.cameras.main.setZoom(newZoom);
|
||||
waScaleManager.zoomModifier *= pinch.scaleFactor;
|
||||
});
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.pinch.removeAllListeners();
|
||||
}
|
||||
}
|
@ -171,4 +171,8 @@ export class UserInputManager {
|
||||
removeSpaceEventListner(callback : Function){
|
||||
this.Scene.input.keyboard.removeListener('keyup-SPACE', callback);
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
this.joystick.destroy();
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ import {HelpCameraSettingsScene} from "./Phaser/Menu/HelpCameraSettingsScene";
|
||||
import {localUserStore} from "./Connexion/LocalUserStore";
|
||||
import {ErrorScene} from "./Phaser/Reconnecting/ErrorScene";
|
||||
import {iframeListener} from "./Api/IframeListener";
|
||||
import {HdpiManager} from "./Phaser/Services/HdpiManager";
|
||||
import {waScaleManager} from "./Phaser/Services/WaScaleManager";
|
||||
|
||||
const {width, height} = coWebsiteManager.getGameSize();
|
||||
|
||||
@ -67,16 +69,22 @@ switch (phaserMode) {
|
||||
throw new Error('phaserMode parameter must be one of "auto", "canvas" or "webgl"');
|
||||
}
|
||||
|
||||
const hdpiManager = new HdpiManager(640*480);
|
||||
const { game: gameSize, real: realSize } = hdpiManager.getOptimalGameSize({width, height});
|
||||
|
||||
const config: GameConfig = {
|
||||
type: mode,
|
||||
title: "WorkAdventure",
|
||||
width: width / 2,
|
||||
height: height / 2,
|
||||
scale: {
|
||||
parent: "game",
|
||||
zoom: 2,
|
||||
width: gameSize.width,
|
||||
height: gameSize.height,
|
||||
zoom: realSize.width / gameSize.width,
|
||||
autoRound: true,
|
||||
resizeInterval: 999999999999
|
||||
},
|
||||
scene: [EntryScene, LoginScene, SelectCharacterScene, SelectCompanionScene, EnableCameraScene, ReconnectingScene, ErrorScene, CustomizeScene, MenuScene, HelpCameraSettingsScene],
|
||||
resolution: window.devicePixelRatio / 2,
|
||||
//resolution: window.devicePixelRatio / 2,
|
||||
fps: fps,
|
||||
dom: {
|
||||
createContainer: true
|
||||
@ -105,10 +113,13 @@ const config: GameConfig = {
|
||||
|
||||
const game = new Phaser.Game(config);
|
||||
|
||||
waScaleManager.setScaleManager(game.scale);
|
||||
waScaleManager.applyNewSize();
|
||||
|
||||
window.addEventListener('resize', function (event) {
|
||||
coWebsiteManager.resetStyle();
|
||||
const {width, height} = coWebsiteManager.getGameSize();
|
||||
game.scale.resize(width / RESOLUTION, height / RESOLUTION);
|
||||
|
||||
waScaleManager.applyNewSize();
|
||||
|
||||
// Let's trigger the onResize method of any active scene that is a ResizableScene
|
||||
for (const scene of game.scene.getScenes(true)) {
|
||||
@ -119,8 +130,7 @@ window.addEventListener('resize', function (event) {
|
||||
});
|
||||
|
||||
coWebsiteManager.onResize.subscribe(() => {
|
||||
const {width, height} = coWebsiteManager.getGameSize();
|
||||
game.scale.resize(width / RESOLUTION, height / RESOLUTION);
|
||||
waScaleManager.applyNewSize();
|
||||
});
|
||||
|
||||
iframeListener.init();
|
||||
|
32
front/tests/Phaser/Services/HdpiManagerTest.ts
Normal file
32
front/tests/Phaser/Services/HdpiManagerTest.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import "jasmine";
|
||||
import {HdpiManager} from "../../../src/Phaser/Services/HdpiManager";
|
||||
|
||||
describe("Test HdpiManager", () => {
|
||||
it("should match screen size if size is too small.", () => {
|
||||
const hdpiManager = new HdpiManager(640*480);
|
||||
|
||||
const result = hdpiManager.getOptimalGameSize({ width: 320, height: 200 });
|
||||
expect(result.game.width).toEqual(320);
|
||||
expect(result.game.height).toEqual(200);
|
||||
expect(result.real.width).toEqual(320);
|
||||
expect(result.real.height).toEqual(200);
|
||||
});
|
||||
|
||||
it("should match multiple just above.", () => {
|
||||
const hdpiManager = new HdpiManager(640*480);
|
||||
|
||||
let result = hdpiManager.getOptimalGameSize({ width: 960, height: 600 });
|
||||
expect(result.game.width).toEqual(960);
|
||||
expect(result.game.height).toEqual(600);
|
||||
|
||||
result = hdpiManager.getOptimalGameSize({ width: 640 * 2 + 50, height: 480 * 2 + 50 });
|
||||
expect(result.game.width).toEqual(Math.ceil((640 * 2 + 50) / 2));
|
||||
expect(result.game.height).toEqual((480 * 2 + 50) / 2);
|
||||
|
||||
result = hdpiManager.getOptimalGameSize({ width: 640 * 3 + 50, height: 480 * 3 + 50 });
|
||||
expect(result.game.width).toEqual(Math.ceil((640 * 3 + 50) / 3));
|
||||
expect(result.game.height).toEqual(Math.ceil((480 * 3 + 50) / 3));
|
||||
expect(result.real.width).toEqual(result.game.width * 3);
|
||||
expect(result.real.height).toEqual(result.game.height * 3);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user