Integrate virtual joystick

This commit is contained in:
PizZaKatZe 2021-02-03 23:28:46 +01:00
parent e75fb9a6a9
commit c3230bc2b3
10 changed files with 170 additions and 16 deletions

View File

@ -36,6 +36,9 @@
<section> <section>
<button id="editGameSettingsButton">Settings</button> <button id="editGameSettingsButton">Settings</button>
</section> </section>
<section>
<button id="showJoystick">Show joystick</button>
</section>
<section> <section>
<button id="sparkButton">Create map</button> <button id="sparkButton">Create map</button>
</section> </section>

View File

@ -151,6 +151,7 @@ video#myCamVideo{
.btn-cam-action { .btn-cam-action {
pointer-events: all;
position: absolute; position: absolute;
bottom: 0px; bottom: 0px;
right: 0px; right: 0px;
@ -186,18 +187,26 @@ video#myCamVideo{
transition: 280ms; transition: 280ms;
} }
.btn-micro{ .btn-micro{
pointer-events: auto;
transition: all .3s; transition: all .3s;
right: 44px; right: 44px;
} }
.btn-video{ .btn-video{
pointer-events: auto;
transition: all .25s; transition: all .25s;
right: 134px; right: 134px;
} }
.btn-monitor{ .btn-monitor{
pointer-events: auto;
transition: all .2s; transition: all .2s;
right: 224px; right: 224px;
} }
.btn-copy{
pointer-events: auto;
transition: all .3s;
right: 44px;
opacity: 1;
}
.btn-cam-action div img{ .btn-cam-action div img{
height: 22px; height: 22px;
width: 30px; width: 30px;
@ -502,6 +511,7 @@ input[type=range]:focus::-ms-fill-upper {
position: absolute; position: absolute;
width: 100%; width: 100%;
height: 100%; height: 100%;
pointer-events: none;
/* TODO: DO WE NEED FLEX HERE???? WE WANT A SIDEBAR OF EXACTLY 25% (note: flex useful for direction!!!) */ /* TODO: DO WE NEED FLEX HERE???? WE WANT A SIDEBAR OF EXACTLY 25% (note: flex useful for direction!!!) */
} }
@ -537,6 +547,7 @@ input[type=range]:focus::-ms-fill-upper {
.sidebar { .sidebar {
flex: 0 0 25%; flex: 0 0 25%;
display: flex; display: flex;
pointer-events: none;
} }
.sidebar > div { .sidebar > div {

View File

@ -31,6 +31,7 @@
"generic-type-guard": "^3.2.0", "generic-type-guard": "^3.2.0",
"google-protobuf": "^3.13.0", "google-protobuf": "^3.13.0",
"phaser": "3.24.1", "phaser": "3.24.1",
"phaser3-rex-plugins": "^1.1.42",
"queue-typescript": "^1.0.1", "queue-typescript": "^1.0.1",
"quill": "^1.3.7", "quill": "^1.3.7",
"rxjs": "^6.6.3", "rxjs": "^6.6.3",

View File

@ -9,7 +9,8 @@ const gameQualityKey = 'gameQuality';
const videoQualityKey = 'videoQuality'; const videoQualityKey = 'videoQuality';
const audioPlayerVolumeKey = 'audioVolume'; const audioPlayerVolumeKey = 'audioVolume';
const audioPlayerMuteKey = 'audioMute'; const audioPlayerMuteKey = 'audioMute';
const helpCameraSettingsShown = 'helpCameraSettingsShown'; const helpCameraSettingsShown = 'helpCameraSettingsShown';
const joystickKey = 'showJoystick';
class LocalUserStore { class LocalUserStore {
saveUser(localUser: LocalUser) { saveUser(localUser: LocalUser) {
@ -100,6 +101,13 @@ class LocalUserStore {
getHelpCameraSettingsShown(): boolean { getHelpCameraSettingsShown(): boolean {
return localStorage.getItem(helpCameraSettingsShown) === '1'; return localStorage.getItem(helpCameraSettingsShown) === '1';
} }
setJoystick(value: boolean): void {
localStorage.setItem(joystickKey, value.toString());
}
getJoystick(): boolean {
return localStorage.getItem(joystickKey) === 'true';
}
} }
export const localUserStore = new LocalUserStore(); export const localUserStore = new LocalUserStore();

View File

@ -51,6 +51,10 @@ import {Room} from "../../Connexion/Room";
import {jitsiFactory} from "../../WebRtc/JitsiFactory"; import {jitsiFactory} from "../../WebRtc/JitsiFactory";
import {urlManager} from "../../Url/UrlManager"; import {urlManager} from "../../Url/UrlManager";
import {audioManager} from "../../WebRtc/AudioManager"; import {audioManager} from "../../WebRtc/AudioManager";
import {IVirtualJoystick} from "../../types";
const {
default: VirtualJoystick,
} = require("phaser3-rex-plugins/plugins/virtualjoystick.js");
import {PresentationModeIcon} from "../Components/PresentationModeIcon"; import {PresentationModeIcon} from "../Components/PresentationModeIcon";
import {ChatModeIcon} from "../Components/ChatModeIcon"; import {ChatModeIcon} from "../Components/ChatModeIcon";
import {OpenChatIcon, openChatIconName} from "../Components/OpenChatIcon"; import {OpenChatIcon, openChatIconName} from "../Components/OpenChatIcon";
@ -164,6 +168,7 @@ export class GameScene extends ResizableScene implements CenterListener {
private messageSubscription: Subscription|null = null; private messageSubscription: Subscription|null = null;
private popUpElements : Map<number, DOMElement> = new Map<number, Phaser.GameObjects.DOMElement>(); private popUpElements : Map<number, DOMElement> = new Map<number, Phaser.GameObjects.DOMElement>();
private originalMapUrl: string|undefined; private originalMapUrl: string|undefined;
public virtualJoystick!: IVirtualJoystick;
constructor(private room: Room, MapUrlFile: string, customKey?: string|undefined) { constructor(private room: Room, MapUrlFile: string, customKey?: string|undefined) {
super({ super({
@ -183,6 +188,16 @@ export class GameScene extends ResizableScene implements CenterListener {
this.connectionAnswerPromise = new Promise<RoomJoinedMessageInterface>((resolve, reject): void => { this.connectionAnswerPromise = new Promise<RoomJoinedMessageInterface>((resolve, reject): void => {
this.connectionAnswerPromiseResolve = resolve; this.connectionAnswerPromiseResolve = resolve;
}) })
const joystickVisible = localUserStore.getJoystick();
if (joystickVisible) {
const canvas = document.querySelector('canvas')
canvas?.addEventListener('click', () => {
const body = document.querySelector('body')
body?.requestFullscreen()
}, {
once: true
})
}
} }
//hook preload scene //hook preload scene
@ -399,9 +414,19 @@ export class GameScene extends ResizableScene implements CenterListener {
//initialise list of other player //initialise list of other player
this.MapPlayers = this.physics.add.group({immovable: true}); this.MapPlayers = this.physics.add.group({immovable: true});
this.virtualJoystick = new VirtualJoystick(this, {
x: this.game.renderer.width / 2,
y: this.game.renderer.height / 2,
radius: 20,
base: this.add.circle(0, 0, 20, 0x888888),
thumb: this.add.circle(0, 0, 10, 0xcccccc),
enable: true,
dir: "8dir",
});
this.virtualJoystick.visible = localUserStore.getJoystick()
//create input to move //create input to move
this.userInputManager = new UserInputManager(this);
mediaManager.setUserInputManager(this.userInputManager); mediaManager.setUserInputManager(this.userInputManager);
this.userInputManager = new UserInputManager(this, this.virtualJoystick);
//notify game manager can to create currentUser in map //notify game manager can to create currentUser in map
this.createCurrentPlayer(); this.createCurrentPlayer();

View File

@ -291,6 +291,9 @@ export class MenuScene extends Phaser.Scene {
case 'editGameSettingsButton': case 'editGameSettingsButton':
this.openGameSettingsMenu(); this.openGameSettingsMenu();
break; break;
case 'showJoystick':
this.showJoystick();
break;
case 'adminConsoleButton': case 'adminConsoleButton':
gameManager.getCurrentGameScene(this).ConsoleGlobalMessageManager.activeMessageConsole(); gameManager.getCurrentGameScene(this).ConsoleGlobalMessageManager.activeMessageConsole();
break; break;
@ -328,4 +331,21 @@ export class MenuScene extends Phaser.Scene {
this.closeGameShare(); this.closeGameShare();
this.gameReportElement.close(); this.gameReportElement.close();
} }
private showJoystick() {
const gameScene = gameManager.getCurrentGameScene(this)
if (gameScene?.virtualJoystick) {
const joystickVisible = !gameScene.virtualJoystick.visible
gameScene.virtualJoystick.visible = joystickVisible
localUserStore.setJoystick(joystickVisible)
}
const body = document.querySelector('body')
if (body) {
if (document.fullscreenElement ?? document.fullscreen) {
document.exitFullscreen()
} else {
body.requestFullscreen();
}
}
}
} }

View File

@ -1,4 +1,8 @@
import { Direction, IVirtualJoystick } from "../../types";
import {GameScene} from "../Game/GameScene"; import {GameScene} from "../Game/GameScene";
const {
default: VirtualJoystick,
} = require("phaser3-rex-plugins/plugins/virtualjoystick.js");
interface UserInputManagerDatum { interface UserInputManagerDatum {
keyInstance: Phaser.Input.Keyboard.Key; keyInstance: Phaser.Input.Keyboard.Key;
@ -25,6 +29,9 @@ export class ActiveEventList {
set(event: UserInputEvent, value: boolean): void { set(event: UserInputEvent, value: boolean): void {
this.KeysCode.set(event, value); this.KeysCode.set(event, value);
} }
forEach(callback: (value: boolean, key: UserInputEvent) => void): void {
this.KeysCode.forEach(callback);
}
} }
//this class is responsible for catching user inputs and listing all active user actions at every game tick events. //this class is responsible for catching user inputs and listing all active user actions at every game tick events.
@ -32,10 +39,32 @@ export class UserInputManager {
private KeysCode!: UserInputManagerDatum[]; private KeysCode!: UserInputManagerDatum[];
private Scene: GameScene; private Scene: GameScene;
private isInputDisabled : boolean; private isInputDisabled : boolean;
constructor(Scene : GameScene) { private joystickEvents = new ActiveEventList();
constructor(Scene: GameScene, virtualJoystick: IVirtualJoystick) {
this.Scene = Scene; this.Scene = Scene;
this.initKeyBoardEvent();
this.isInputDisabled = false; this.isInputDisabled = false;
this.initKeyBoardEvent();
virtualJoystick.on("update", () => {
const cursorKeys = virtualJoystick.createCursorKeys();
for (const name in cursorKeys) {
const key = cursorKeys[name as Direction];
switch (name) {
case "up":
this.joystickEvents.set(UserInputEvent.MoveUp, key.isDown);
break;
case "left":
this.joystickEvents.set(UserInputEvent.MoveLeft, key.isDown);
break;
case "down":
this.joystickEvents.set(UserInputEvent.MoveDown, key.isDown);
break;
case "right":
this.joystickEvents.set(UserInputEvent.MoveRight, key.isDown);
break;
}
}
});
} }
initKeyBoardEvent(){ initKeyBoardEvent(){
@ -78,11 +107,15 @@ export class UserInputManager {
if (this.isInputDisabled) { if (this.isInputDisabled) {
return eventsMap; return eventsMap;
} }
this.joystickEvents.forEach((value, key) => {
if (value) {
eventsMap.set(key, value);
}
});
this.KeysCode.forEach(d => { this.KeysCode.forEach(d => {
if (d. keyInstance.isDown) { if (d. keyInstance.isDown) {
eventsMap.set(d.event, true); eventsMap.set(d.event, true);
} }
}); });
return eventsMap; return eventsMap;
} }

22
front/src/types.ts Normal file
View File

@ -0,0 +1,22 @@
import Phaser from "phaser";
export type CursorKey = {
isDown: boolean
}
export type Direction = 'left' | 'right' | 'up' | 'down'
export interface CursorKeys extends Record<Direction, CursorKey> {
left: CursorKey;
right: CursorKey;
up: CursorKey;
down: CursorKey;
}
export interface IVirtualJoystick extends Phaser.GameObjects.GameObject {
y: number;
x: number;
visible: boolean;
createCursorKeys: () => CursorKeys;
}

View File

@ -9,17 +9,18 @@
"downlevelIteration": true, "downlevelIteration": true,
"jsx": "react", "jsx": "react",
"allowJs": true, "allowJs": true,
"esModuleInterop": true,
"strict": true, /* Enable all strict type-checking options. */ "strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
"strictNullChecks": true, /* Enable strict null checks. */ "strictNullChecks": true, /* Enable strict null checks. */
"strictFunctionTypes": true, /* Enable strict checking of function types. */ "strictFunctionTypes": true, /* Enable strict checking of function types. */
"strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
"strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
"noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
"noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */ "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */
} }
} }

View File

@ -1819,6 +1819,11 @@ eventemitter3@^2.0.3:
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba"
integrity sha1-teEHm1n7XhuidxwKmTvgYKWMmbo= integrity sha1-teEHm1n7XhuidxwKmTvgYKWMmbo=
eventemitter3@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7"
integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==
eventemitter3@^4.0.0, eventemitter3@^4.0.4: eventemitter3@^4.0.0, eventemitter3@^4.0.4:
version "4.0.7" version "4.0.7"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
@ -3064,6 +3069,11 @@ loglevel@^1.6.8:
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.0.tgz#728166855a740d59d38db01cf46f042caa041bb0" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.0.tgz#728166855a740d59d38db01cf46f042caa041bb0"
integrity sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ== integrity sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ==
lokijs@^1.5.11:
version "1.5.11"
resolved "https://registry.yarnpkg.com/lokijs/-/lokijs-1.5.11.tgz#2b2ea82ec66050e4b112c6cfc588dac22d362b13"
integrity sha512-YYyuBPxMn/oS0tFznQDbIX5XL1ltMcwFqCboDr8voYE4VCDzR5vAsrvQDhlnua4lBeqMqHmLvUXRTmRUzUKH1Q==
lower-case@^2.0.1: lower-case@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.1.tgz#39eeb36e396115cc05e29422eaea9e692c9408c7" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.1.tgz#39eeb36e396115cc05e29422eaea9e692c9408c7"
@ -3625,6 +3635,11 @@ pako@~1.0.5:
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
papaparse@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.3.0.tgz#ab1702feb96e79ab4309652f36db9536563ad05a"
integrity sha512-Lb7jN/4bTpiuGPrYy4tkKoUS8sTki8zacB5ke1p5zolhcSE4TlWgrlsxjrDTbG/dFVh07ck7X36hUf/b5V68pg==
parallel-transform@^1.1.0: parallel-transform@^1.1.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc"
@ -3752,6 +3767,16 @@ pbkdf2@^3.0.3:
safe-buffer "^5.0.1" safe-buffer "^5.0.1"
sha.js "^2.4.8" sha.js "^2.4.8"
phaser3-rex-plugins@^1.1.42:
version "1.1.44"
resolved "https://registry.yarnpkg.com/phaser3-rex-plugins/-/phaser3-rex-plugins-1.1.44.tgz#83588ab2801c5b3a80a18be4f0ae37f1f32096b0"
integrity sha512-JPr3+UQv4+uv4etZr80aFhYxw2dk4UYG9/gQ4uMSSXQuc8gXQkXCr3J3zm8LJqH+1FXeK8nncpC7TKa4uKLgQw==
dependencies:
eventemitter3 "^3.1.2"
lokijs "^1.5.11"
papaparse "^5.3.0"
webfontloader "^1.6.28"
phaser@3.24.1: phaser@3.24.1:
version "3.24.1" version "3.24.1"
resolved "https://registry.yarnpkg.com/phaser/-/phaser-3.24.1.tgz#376e0c965d2a35af37c06ee78627dafbde5be017" resolved "https://registry.yarnpkg.com/phaser/-/phaser-3.24.1.tgz#376e0c965d2a35af37c06ee78627dafbde5be017"
@ -5144,6 +5169,11 @@ wbuf@^1.1.0, wbuf@^1.7.3:
dependencies: dependencies:
minimalistic-assert "^1.0.0" minimalistic-assert "^1.0.0"
webfontloader@^1.6.28:
version "1.6.28"
resolved "https://registry.yarnpkg.com/webfontloader/-/webfontloader-1.6.28.tgz#db786129253cb6e8eae54c2fb05f870af6675bae"
integrity sha1-23hhKSU8tujq5UwvsF+HCvZnW64=
webpack-cli@^3.3.11: webpack-cli@^3.3.11:
version "3.3.12" version "3.3.12"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.12.tgz#94e9ada081453cd0aa609c99e500012fd3ad2d4a" resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.12.tgz#94e9ada081453cd0aa609c99e500012fd3ad2d4a"