refactor out custom app initialization.

This commit is contained in:
Michael Mainguy 2023-08-06 08:14:43 -05:00
parent 1ec8d40843
commit abbf9d594e
7 changed files with 206 additions and 188 deletions

View File

@ -1,42 +1,28 @@
import {
ArcRotateCamera,
DualShockPad,
Engine,
GroundMesh,
HavokPlugin,
HemisphericLight,
MeshBuilder,
PBRMetallicRoughnessMaterial,
PhysicsAggregate,
PhysicsShapeType,
Scene,
Texture,
Vector3,
WebXRDefaultExperience,
WebXRState
} from "@babylonjs/core";
import HavokPhysics from "@babylonjs/havok";
import {Rigplatform} from "./controllers/rigplatform";
import {DiagramManager} from "./diagram/diagramManager";
import {Toolbox} from "./toolbox/toolbox";
import {DualshockEventMapper} from "./util/dualshockEventMapper";
import log from "loglevel";
import {AppConfig} from "./util/appConfig";
import {DiaSounds} from "./util/diaSounds";
import {PeerjsNetworkConnection} from "./integration/peerjsNetworkConnection";
import {InputTextView} from "./information/inputTextView";
import {GamepadManager} from "./controllers/gamepadManager";
import {CustomEnvironment} from "./util/customEnvironment";
export class App {
//preTasks = [havokModule];
private logger = log.getLogger('App');
private scene: Scene;
private rig: Rigplatform;
constructor() {
const config = AppConfig.config;
const logger = log.getLogger('App');
log.setLevel('info');
log.getLogger('App').setLevel('info');
log.getLogger('IndexdbPersistenceManager').setLevel('info');
@ -50,29 +36,24 @@ export class App {
document.body.appendChild(canvas);
log.debug('App', 'gameCanvas created');
this.initialize(canvas).then(() => {
log.debug('App', 'Scene Initialized');
logger.debug('App', 'Scene Initialized');
});
}
async initialize(canvas) {
if (this.scene) {
this.scene.dispose();
this.scene = null;
}
const logger = log.getLogger('App');
const engine = new Engine(canvas, true);
const scene = new Scene(engine);
const environment = new CustomEnvironment(scene);
const query = Object.fromEntries(new URLSearchParams(window.location.search));
this.logger.debug('Query', query);
logger.debug('Query', query);
if (query.shareCode) {
scene.onReadyObservable.addOnce(() => {
this.logger.debug('Scene ready');
logger.debug('Scene ready');
const identityView = new InputTextView({scene: scene, text: ""});
identityView.onTextObservable.add((text) => {
if (text?.text?.trim() != "") {
this.logger.debug('Identity', text.text);
logger.debug('Identity', text.text);
const network = new PeerjsNetworkConnection(query.shareCode, text.text);
if (query.host) {
network.connect(query.host);
@ -83,31 +64,12 @@ export class App {
});
}
this.scene = scene;
const sounds = new DiaSounds(scene);
sounds.enter.autoplay = true;
const havokInstance = await HavokPhysics();
const havokPlugin = new HavokPlugin(true, havokInstance);
scene.enablePhysics(new Vector3(0, -9.8, 0), havokPlugin);
scene.collisionsEnabled = true;
const camera: ArcRotateCamera = new ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 2, 2,
new Vector3(0, 1.6, 0), scene);
camera.radius = 0;
camera.attachControl(canvas, true);
new HemisphericLight("light1", new Vector3(1, 1, 0), scene);
import('@babylonjs/core').then((babylon) => {
new babylon.PhotoDome('sky',
'./outdoor_field2.jpeg', {},
scene);
});
const ground = this.createGround();
environment.groundMeshObservable.add(async (ground) => {
const xr = await WebXRDefaultExperience.CreateAsync(scene, {
floorMeshes: [ground],
disableTeleportation: true,
@ -122,10 +84,9 @@ export class App {
}
});
xr.baseExperience.onStateChangedObservable.add((state) => {
if (state == WebXRState.IN_XR) {
this.scene.audioEnabled = true;
scene.audioEnabled = true;
xr.baseExperience.camera.position = new Vector3(0, 1.6, 0);
window.addEventListener(('pa-button-state-change'), (event: any) => {
if (event.detail) {
@ -135,82 +96,17 @@ export class App {
}
});
const diagramManager = new DiagramManager(this.scene, xr.baseExperience);
this.rig = new Rigplatform(this.scene, xr, diagramManager);
const diagramManager = new DiagramManager(scene, xr.baseExperience);
const rig = new Rigplatform(scene, xr, diagramManager);
const toolbox = new Toolbox(scene, xr.baseExperience, diagramManager);
import ('./integration/indexdbPersistenceManager').then((module) => {
const persistenceManager = new module.IndexdbPersistenceManager("diagram");
diagramManager.setPersistenceManager(persistenceManager);
AppConfig.config.setPersistenceManager(persistenceManager);
persistenceManager.initialize();
});
this.scene.gamepadManager.onGamepadConnectedObservable.add((gamepad) => {
try {
const dualshock = (gamepad as DualShockPad);
dualshock.onButtonDownObservable.add((button: any) => {
const buttonEvent = DualshockEventMapper.mapButtonEvent(button, 1);
if (buttonEvent.objectName) {
window.dispatchEvent(new CustomEvent('pa-button-state-change', {
detail: buttonEvent
}
));
}
});
dualshock.onButtonUpObservable.add((button: any) => {
const buttonEvent = DualshockEventMapper.mapButtonEvent(button, 0);
if (buttonEvent.objectName) {
window.dispatchEvent(new CustomEvent('pa-button-state-change', {
detail: buttonEvent
}
));
}
});
gamepad.onleftstickchanged((values) => {
window.dispatchEvent(
new CustomEvent('pa-analog-value-change', {
detail: {
objectName: "left-controller",
value: values.x,
axisIndex: 0
}
}));
window.dispatchEvent(
new CustomEvent('pa-analog-value-change', {
detail: {
objectName: "left-controller",
value: values.y,
axisIndex: 1
}
}));
});
gamepad.onrightstickchanged((values) => {
window.dispatchEvent(
new CustomEvent('pa-analog-value-change', {
detail: {
objectName: "right-controller",
value: values.x,
axisIndex: 0
}
}));
window.dispatchEvent(
new CustomEvent('pa-analog-value-change', {
detail: {
objectName: "right-controller",
value: values.y,
axisIndex: 1
}
}));
});
} catch (err) {
log.warn('App', err);
}
});
const gamepadManager = new GamepadManager(scene);
window.addEventListener("keydown", (ev) => {
// Shift+Ctrl+Alt+I
if (ev.shiftKey && ev.ctrlKey && ev.altKey && ev.keyCode === 73) {
@ -225,38 +121,11 @@ export class App {
});
}
});
this.logger.info('keydown event listener added, use Ctrl+Shift+Alt+I to toggle debug layer');
logger.info('keydown event listener added, use Ctrl+Shift+Alt+I to toggle debug layer');
engine.runRenderLoop(() => {
scene.render();
});
//const data = window.location.search.replace('?', '')
// .split('&')
// .map((x) => x.split('='));
//const network = new PeerjsNetworkConnection();
//network.connect(data[0][1]);
this.logger.info('Render loop started');
}
createGround() {
const groundMaterial = new PBRMetallicRoughnessMaterial("groundMaterial", this.scene);
const gText = new Texture("./grass1.jpeg", this.scene);
gText.uScale = 40;
gText.vScale = 40;
groundMaterial.baseTexture = gText;
groundMaterial.metallic = 0;
groundMaterial.roughness = 1;
const ground: GroundMesh = MeshBuilder.CreateGround("ground", {
width: 100,
height: 100,
subdivisions: 1
}, this.scene);
ground.material = groundMaterial;
new PhysicsAggregate(ground, PhysicsShapeType.BOX, {mass: 0}, this.scene);
return ground;
logger.info('Render loop started');
}
}
const app = new App();

View File

@ -0,0 +1,70 @@
import {DualShockPad, Scene} from "@babylonjs/core";
import {DualshockEventMapper} from "../util/dualshockEventMapper";
import log from "loglevel";
export class GamepadManager {
constructor(scene: Scene) {
scene.gamepadManager.onGamepadConnectedObservable.add((gamepad) => {
try {
const dualshock = (gamepad as DualShockPad);
dualshock.onButtonDownObservable.add((button: any) => {
const buttonEvent = DualshockEventMapper.mapButtonEvent(button, 1);
if (buttonEvent.objectName) {
window.dispatchEvent(new CustomEvent('pa-button-state-change', {
detail: buttonEvent
}
));
}
});
dualshock.onButtonUpObservable.add((button: any) => {
const buttonEvent = DualshockEventMapper.mapButtonEvent(button, 0);
if (buttonEvent.objectName) {
window.dispatchEvent(new CustomEvent('pa-button-state-change', {
detail: buttonEvent
}
));
}
});
gamepad.onleftstickchanged((values) => {
window.dispatchEvent(
new CustomEvent('pa-analog-value-change', {
detail: {
objectName: "left-controller",
value: values.x,
axisIndex: 0
}
}));
window.dispatchEvent(
new CustomEvent('pa-analog-value-change', {
detail: {
objectName: "left-controller",
value: values.y,
axisIndex: 1
}
}));
});
gamepad.onrightstickchanged((values) => {
window.dispatchEvent(
new CustomEvent('pa-analog-value-change', {
detail: {
objectName: "right-controller",
value: values.x,
axisIndex: 0
}
}));
window.dispatchEvent(
new CustomEvent('pa-analog-value-change', {
detail: {
objectName: "right-controller",
value: values.y,
axisIndex: 1
}
}));
});
} catch (err) {
log.warn('App', err);
}
});
}
}

View File

@ -51,7 +51,7 @@ export class DiagramConnection {
return this._mesh;
}
private _to: string;
private readonly _to: string;
public get to(): string {
return this?.toAnchor?.id;
@ -72,7 +72,7 @@ export class DiagramConnection {
}
}
private _from: string;
private readonly _from: string;
public get from(): string {
return this?.fromAnchor?.id;

View File

@ -87,8 +87,8 @@ export class DiagramManager {
newMesh.scaling = AppConfig.config.createSnapVal;
}
newMesh.material = mesh.material;
const metaCopy = this.deepCopy(mesh.metadata);
newMesh.metadata = metaCopy;
newMesh.metadata = this.deepCopy(mesh.metadata);
DiagramShapePhysics.applyPhysics(newMesh, this.scene);
this.persistenceManager.add(newMesh);
return newMesh;

View File

@ -0,0 +1,61 @@
import {
GroundMesh,
MeshBuilder,
Observable,
PBRMetallicRoughnessMaterial,
PhotoDome,
PhysicsAggregate,
PhysicsShapeType,
Scene,
Texture
} from "@babylonjs/core";
import {CustomPhysics} from "./customPhysics";
import {DiaSounds} from "./diaSounds";
export class CustomEnvironment {
private readonly scene: Scene;
private readonly name: string;
private readonly _groundMeshObservable: Observable<GroundMesh> = new Observable<GroundMesh>();
constructor(scene: Scene, name: string = "default") {
this.scene = scene;
this.name = name;
new DiaSounds(scene);
const physics = new CustomPhysics(this.scene);
physics
.initializeAsync()
.then(() => {
const ground = this.createGround();
this._groundMeshObservable.notifyObservers(ground);
});
const photo = new PhotoDome('sky',
'./outdoor_field2.jpeg', {},
scene);
}
public get groundMeshObservable() {
return this._groundMeshObservable;
}
private createGround() {
const scene = this.scene;
const groundMaterial = new PBRMetallicRoughnessMaterial("groundMaterial", scene);
const gText = new Texture("./grass1.jpeg", scene);
gText.uScale = 40;
gText.vScale = 40;
groundMaterial.baseTexture = gText;
groundMaterial.metallic = 0;
groundMaterial.roughness = 1;
const ground: GroundMesh = MeshBuilder.CreateGround("ground", {
width: 100,
height: 100,
subdivisions: 1
}, scene);
ground.material = groundMaterial;
new PhysicsAggregate(ground, PhysicsShapeType.BOX, {mass: 0}, scene);
return ground;
}
}

17
src/util/customPhysics.ts Normal file
View File

@ -0,0 +1,17 @@
import {HavokPlugin, Scene, Vector3} from "@babylonjs/core";
import HavokPhysics from "@babylonjs/havok";
export class CustomPhysics {
private scene: Scene;
constructor(scene: Scene) {
this.scene = scene;
}
public async initializeAsync() {
const havok = await HavokPhysics()
const havokPlugin = new HavokPlugin(true, havok);
this.scene.enablePhysics(new Vector3(0, -9.8, 0), havokPlugin);
this.scene.collisionsEnabled = true;
}
}

View File

@ -1,12 +1,7 @@
import {Scene, Sound} from "@babylonjs/core";
export class DiaSounds {
public static instance: DiaSounds;
private readonly scene: Scene;
constructor(scene: Scene) {
this.scene = scene;
this._enter = new Sound("enter", "./sounds.mp3", this.scene, null, {
autoplay: false,
@ -32,9 +27,15 @@ export class DiaSounds {
offset: 3,
length: 1.0
});
this._enter.autoplay = true;
DiaSounds._instance = this;
}
private readonly scene: Scene;
private static _instance: DiaSounds;
DiaSounds.instance = this;
public static get instance() {
return DiaSounds._instance;
}
public get tick() {