Add Firefox image

Check permissions in the game
Button Continue to continue without allowing camera and microphone
This commit is contained in:
GRL 2021-03-19 11:50:53 +01:00
parent d68406d5e1
commit c654f722e3
5 changed files with 125 additions and 112 deletions

View File

@ -76,7 +76,7 @@
margin: 0px 20px; margin: 0px 20px;
} }
#helpCameraSettings section p.err{ #helpCameraSettings section p.err{
color: red; color: #ff0000;
} }
#helpCameraSettings section ul{ #helpCameraSettings section ul{
margin: 6px; margin: 6px;
@ -101,9 +101,11 @@
<li>Please ensure that you have a camera AND microphone plugged into your computer.</li> <li>Please ensure that you have a camera AND microphone plugged into your computer.</li>
</ul> </ul>
<p class="info">Once you've followed these steps, please refresh this page.</p> <p class="info">Once you've followed these steps, please refresh this page.</p>
<img src="/resources/objects/help-setting-camera-permission.png"> <p>If you prefer to continue without allowing camera and microphone access, click on Continue</p>
<p id='browserHelpSetting'></p>
</section> </section>
<section class="action"> <section class="action">
<button type="submit" id="helpCameraSettingsFormRefresh">Refresh</button> <button type="submit" id="helpCameraSettingsFormRefresh">Refresh</button>
<button type="submit" id="helpCameraSettingsFormContinue">Continue</button>
</section> </section>
</form> </form>

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -63,6 +63,8 @@ import CanvasTexture = Phaser.Textures.CanvasTexture;
import GameObject = Phaser.GameObjects.GameObject; import GameObject = Phaser.GameObjects.GameObject;
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR; import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
import {Subscription} from "rxjs"; import {Subscription} from "rxjs";
import {tryCatch} from "rxjs/internal-compatibility";
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
export interface GameSceneInitInterface { export interface GameSceneInitInterface {
initPosition: PointInterface|null, initPosition: PointInterface|null,
@ -100,6 +102,7 @@ interface DeleteGroupEventInterface {
} }
const defaultStartLayerName = 'start'; const defaultStartLayerName = 'start';
const helpCameraSettings = 'helpCameraSettings';
export class GameScene extends ResizableScene implements CenterListener { export class GameScene extends ResizableScene implements CenterListener {
Terrains : Array<Phaser.Tilemaps.Tileset>; Terrains : Array<Phaser.Tilemaps.Tileset>;
@ -127,6 +130,8 @@ export class GameScene extends ResizableScene implements CenterListener {
// A promise that will resolve when the "create" method is called (signaling loading is ended) // A promise that will resolve when the "create" method is called (signaling loading is ended)
private createPromise: Promise<void>; private createPromise: Promise<void>;
private createPromiseResolve!: (value?: void | PromiseLike<void>) => void; private createPromiseResolve!: (value?: void | PromiseLike<void>) => void;
private helpCameraSettingsElement!: Phaser.GameObjects.DOMElement; //#700
private helpCameraSettingsOpened: boolean = false; //#700
MapUrlFile: string; MapUrlFile: string;
RoomId: string; RoomId: string;
@ -207,6 +212,7 @@ export class GameScene extends ResizableScene implements CenterListener {
this.load.spritesheet('layout_modes', 'resources/objects/layout_modes.png', {frameWidth: 32, frameHeight: 32}); this.load.spritesheet('layout_modes', 'resources/objects/layout_modes.png', {frameWidth: 32, frameHeight: 32});
this.load.bitmapFont('main_font', 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml'); this.load.bitmapFont('main_font', 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
this.load.html(helpCameraSettings, 'resources/html/helpCameraSettings.html'); //#700
addLoader(this); addLoader(this);
} }
@ -544,6 +550,27 @@ export class GameScene extends ResizableScene implements CenterListener {
//init user position and play trigger to check layers properties //init user position and play trigger to check layers properties
this.gameMap.setPosition(this.CurrentPlayer.x, this.CurrentPlayer.y); this.gameMap.setPosition(this.CurrentPlayer.x, this.CurrentPlayer.y);
// #700
const middleX = (window.innerWidth / 3) - (370*0.85);
this.helpCameraSettingsElement = this.add.dom(middleX, -800, undefined, {overflow: 'scroll'}).createFromCache(helpCameraSettings);
this.revealMenusAfterInit(this.helpCameraSettingsElement, helpCameraSettings);
this.helpCameraSettingsElement.addListener('click');
this.helpCameraSettingsElement.on('click', (event:MouseEvent) => {
event.preventDefault();
if((event?.target as HTMLInputElement).id === 'helpCameraSettingsFormRefresh') {
window.location.reload();
}else if((event?.target as HTMLInputElement).id === 'helpCameraSettingsFormContinue') {
this.closeHelpCameraSettingsOpened();
}
});
if(this.helpCameraSettingsElement.parent){
(this.helpCameraSettingsElement.parent as HTMLDivElement).style.overflow = 'scroll';
}
if(!mediaManager.constraintsMedia.audio || !mediaManager.constraintsMedia.video){
this.openHelpCameraSettingsOpened(); //#700
}
}); });
} }
@ -967,43 +994,44 @@ export class GameScene extends ResizableScene implements CenterListener {
*/ */
update(time: number, delta: number) : void { update(time: number, delta: number) : void {
mediaManager.setLastUpdateScene(); mediaManager.setLastUpdateScene();
this.currentTick = time; if(!this.helpCameraSettingsOpened) {
this.CurrentPlayer.moveUser(delta); this.currentTick = time;
this.CurrentPlayer.moveUser(delta);
// Let's handle all events // Let's handle all events
while (this.pendingEvents.length !== 0) { while (this.pendingEvents.length !== 0) {
const event = this.pendingEvents.dequeue(); const event = this.pendingEvents.dequeue();
switch (event.type) { switch (event.type) {
case "InitUserPositionEvent": case "InitUserPositionEvent":
this.doInitUsersPosition(event.event); this.doInitUsersPosition(event.event);
break; break;
case "AddPlayerEvent": case "AddPlayerEvent":
this.doAddPlayer(event.event); this.doAddPlayer(event.event);
break; break;
case "RemovePlayerEvent": case "RemovePlayerEvent":
this.doRemovePlayer(event.userId); this.doRemovePlayer(event.userId);
break; break;
case "UserMovedEvent": case "UserMovedEvent":
this.doUpdatePlayerPosition(event.event); this.doUpdatePlayerPosition(event.event);
break; break;
case "GroupCreatedUpdatedEvent": case "GroupCreatedUpdatedEvent":
this.doShareGroupPosition(event.event); this.doShareGroupPosition(event.event);
break; break;
case "DeleteGroupEvent": case "DeleteGroupEvent":
this.doDeleteGroup(event.groupId); this.doDeleteGroup(event.groupId);
break; break;
}
} }
// Let's move all users
const updatedPlayersPositions = this.playersPositionInterpolator.getUpdatedPositions(time);
updatedPlayersPositions.forEach((moveEvent: HasMovedEvent, userId: number) => {
const player: RemotePlayer | undefined = this.MapPlayersByKey.get(userId);
if (player === undefined) {
throw new Error('Cannot find player with ID "' + userId + '"');
}
player.updatePosition(moveEvent);
});
} }
// Let's move all users
const updatedPlayersPositions = this.playersPositionInterpolator.getUpdatedPositions(time);
updatedPlayersPositions.forEach((moveEvent: HasMovedEvent, userId: number) => {
const player : RemotePlayer | undefined = this.MapPlayersByKey.get(userId);
if (player === undefined) {
throw new Error('Cannot find player with ID "' + userId +'"');
}
player.updatePosition(moveEvent);
});
} }
/** /**
@ -1248,4 +1276,53 @@ export class GameScene extends ResizableScene implements CenterListener {
}); });
} }
} }
//#700
private openHelpCameraSettingsOpened(): void{
HtmlUtils.getElementByIdOrFail<HTMLDivElement>('webRtcSetup').style.display = 'none';
this.helpCameraSettingsOpened = true;
let middleY = (window.innerHeight / 3) - 275;
if(middleY < 0){
middleY = 0;
}
let middleX = (window.innerWidth / 3) - 50;
if(middleX < 0){
middleX = 0;
}
if(window.navigator.userAgent.indexOf('Firefox') != -1){
HtmlUtils.getElementByIdOrFail<HTMLParagraphElement>('browserHelpSetting').innerHTML ='<img src="/resources/objects/help-setting-camera-permission-firefox.png"/>';
}else if(window.navigator.userAgent.indexOf('Chrome') != -1){
HtmlUtils.getElementByIdOrFail<HTMLParagraphElement>('browserHelpSetting').innerHTML ='<img src="/resources/objects/help-setting-camera-permission-chrome.png"/>';
}
this.tweens.add({
targets: this.helpCameraSettingsElement,
y: this.startY - (370/2),
x: this.startX - (400/2),
duration: 1000,
ease: 'Power3',
overflow: 'scroll'
});
}
private closeHelpCameraSettingsOpened(): void{
const helpCameraSettingsInfo = this.helpCameraSettingsElement.getChildByID('helpCameraSettings') as HTMLParagraphElement;
helpCameraSettingsInfo.innerText = '';
helpCameraSettingsInfo.style.display = 'none';
this.helpCameraSettingsOpened = false;
this.tweens.add({
targets: this.helpCameraSettingsElement,
y: -400,
duration: 1000,
ease: 'Power3',
overflow: 'scroll'
});
}
private revealMenusAfterInit(menuElement: Phaser.GameObjects.DOMElement, rootDomId: string) {
//Dom elements will appear inside the viewer screen when creating before being moved out of it, which create a flicker effect.
//To prevent this, we put a 'hidden' attribute on the root element, we remove it only after the init is done.
setTimeout(() => {
(menuElement.getChildByID(rootDomId) as HTMLElement).hidden = false;
}, 250);
}
} }

View File

@ -16,7 +16,6 @@ enum LoginTextures {
arrowUp = "arrow_up" arrowUp = "arrow_up"
} }
const helpCameraSettings = 'helpCameraSettings';
export class EnableCameraScene extends Phaser.Scene { export class EnableCameraScene extends Phaser.Scene {
private textField!: TextField; private textField!: TextField;
@ -35,8 +34,6 @@ export class EnableCameraScene extends Phaser.Scene {
private soundMeterSprite!: SoundMeterSprite; private soundMeterSprite!: SoundMeterSprite;
private microphoneNameField!: TextField; private microphoneNameField!: TextField;
private repositionCallback!: (this: Window, ev: UIEvent) => void; private repositionCallback!: (this: Window, ev: UIEvent) => void;
private helpCameraSettingsElement!: Phaser.GameObjects.DOMElement;
private helpCameraSettingsOpened: boolean = false;
constructor() { constructor() {
super({ super({
@ -52,7 +49,6 @@ export class EnableCameraScene extends Phaser.Scene {
this.load.image(LoginTextures.arrowUp, "resources/objects/arrow_up.png"); this.load.image(LoginTextures.arrowUp, "resources/objects/arrow_up.png");
// Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap // Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap
this.load.bitmapFont(LoginTextures.mainFont, 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml'); this.load.bitmapFont(LoginTextures.mainFont, 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
this.load.html(helpCameraSettings, 'resources/html/helpCameraSettings.html');
} }
create() { create() {
@ -112,27 +108,6 @@ export class EnableCameraScene extends Phaser.Scene {
this.soundMeterSprite.setVisible(false); this.soundMeterSprite.setVisible(false);
this.add.existing(this.soundMeterSprite); this.add.existing(this.soundMeterSprite);
const middleX = (window.innerWidth / 3) - (370*0.85);
this.helpCameraSettingsElement = this.add.dom(middleX, -800, undefined, {overflow: 'scroll'}).createFromCache(helpCameraSettings);
this.revealMenusAfterInit(this.helpCameraSettingsElement, helpCameraSettings);
this.helpCameraSettingsElement.addListener('click');
this.helpCameraSettingsElement.on('click', (event:MouseEvent) => {
event.preventDefault();
if((event?.target as HTMLInputElement).id !== 'helpCameraSettingsFormRefresh') {
return;
}
const permission: Element = this.helpCameraSettingsElement.getChildByID('permissionError');
permission.innerHTML = '';
return mediaManager.getCamera().then(() => {
window.location.reload();
}).catch((err) => {
permission.innerHTML = err.message;
});
});
if(this.helpCameraSettingsElement.parent){
(this.helpCameraSettingsElement.parent as HTMLDivElement).style.overflow = 'scroll';
}
this.repositionCallback = this.reposition.bind(this); this.repositionCallback = this.reposition.bind(this);
window.addEventListener('resize', this.repositionCallback); window.addEventListener('resize', this.repositionCallback);
} }
@ -175,9 +150,6 @@ export class EnableCameraScene extends Phaser.Scene {
* Function called each time a camera is changed * Function called each time a camera is changed
*/ */
private setupStream(stream: MediaStream): void { private setupStream(stream: MediaStream): void {
if(this.helpCameraSettingsOpened){
return;
}
const img = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('webRtcSetupNoVideo'); const img = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('webRtcSetupNoVideo');
img.style.display = 'none'; img.style.display = 'none';
@ -284,27 +256,19 @@ export class EnableCameraScene extends Phaser.Scene {
mediaManager.setLastUpdateScene(); mediaManager.setLastUpdateScene();
} }
private login(): Promise<MediaStream> { private login(): void {
return mediaManager.getCamera() HtmlUtils.getElementByIdOrFail<HTMLDivElement>('webRtcSetup').style.display = 'none';
.then((mediaStream: MediaStream) => { this.soundMeter.stop();
HtmlUtils.getElementByIdOrFail<HTMLDivElement>('webRtcSetup').style.display = 'none'; window.removeEventListener('resize', this.repositionCallback);
this.soundMeter.stop();
window.removeEventListener('resize', this.repositionCallback); mediaManager.stopCamera();
mediaManager.stopCamera(); mediaManager.stopMicrophone();
mediaManager.stopMicrophone();
this.scene.sleep(EnableCameraSceneName) this.scene.sleep(EnableCameraSceneName)
gameManager.goToStartingMap(this.scene); gameManager.goToStartingMap(this.scene);
return mediaStream;
}).catch((err) => {
this.openHelpCameraSettingsOpened();
throw err;
});
} }
private async getDevices() { private async getDevices() {
if(this.helpCameraSettingsOpened){
return;
}
const mediaDeviceInfos = await navigator.mediaDevices.enumerateDevices(); const mediaDeviceInfos = await navigator.mediaDevices.enumerateDevices();
for (const mediaDeviceInfo of mediaDeviceInfos) { for (const mediaDeviceInfo of mediaDeviceInfos) {
if (mediaDeviceInfo.kind === 'audioinput') { if (mediaDeviceInfo.kind === 'audioinput') {
@ -316,36 +280,6 @@ export class EnableCameraScene extends Phaser.Scene {
this.updateWebCamName(); this.updateWebCamName();
} }
private openHelpCameraSettingsOpened(): void{
this.reset();
HtmlUtils.getElementByIdOrFail<HTMLDivElement>('webRtcSetup').style.display = 'none';
this.helpCameraSettingsOpened = true;
let middleY = (window.innerHeight / 3) - (495);
if(middleY < 0){
middleY = 0;
}
let middleX = (window.innerWidth / 3) - (370*0.85);
if(middleX < 0){
middleX = 0;
}
this.tweens.add({
targets: this.helpCameraSettingsElement,
y: middleY,
x: middleX,
duration: 1000,
ease: 'Power3',
overflow: 'scroll'
});
}
private revealMenusAfterInit(menuElement: Phaser.GameObjects.DOMElement, rootDomId: string) {
//Dom elements will appear inside the viewer screen when creating before being moved out of it, which create a flicker effect.
//To prevent this, we put a 'hidden' attribute on the root element, we remove it only after the init is done.
setTimeout(() => {
(menuElement.getChildByID(rootDomId) as HTMLElement).hidden = false;
}, 250);
}
private reset(){ private reset(){
this.textField.destroy(); this.textField.destroy();
this.pressReturnField.destroy(); this.pressReturnField.destroy();