Fixed up config and color change events.

This commit is contained in:
Michael Mainguy 2023-08-22 14:38:09 -05:00
parent 658b65e216
commit 3954619d60
15 changed files with 314 additions and 386 deletions

View File

@ -17,24 +17,15 @@ import {GamepadManager} from "./controllers/gamepadManager";
import {CustomEnvironment} from "./util/customEnvironment";
import {Controllers} from "./controllers/controllers";
import {Introduction} from "./tutorial/introduction";
import {IndexdbPersistenceManager} from "./integration/indexdbPersistenceManager";
export class App {
//preTasks = [havokModule];
constructor() {
const config = AppConfig.config;
const logger = log.getLogger('App');
//log.enableAll(true);
log.setDefaultLevel('info');
//log.getLogger('App').setLevel('info');
//log.getLogger('IndexdbPersistenceManager').setLevel('info');
//log.getLogger('DiagramManager').setLevel('info');
//log.getLogger('DiagramConnection').setLevel('debug');
//log.getLogger('DrawioManager').setLevel('warn');
//log.getLogger('VoiceManager').setLevel('debug');
//log.getLogger('EntityTree').setLevel('warn');
//log.getLogger('EditMenu').setLevel('warn');
const logger = log.getLogger('App');
log.setDefaultLevel('debug');
const canvas = document.createElement("canvas");
canvas.style.width = "100%";
canvas.style.height = "100%";
@ -51,12 +42,23 @@ export class App {
}
async initialize(canvas) {
const config = AppConfig.config;
const logger = log.getLogger('App');
const engine = new Engine(canvas, true);
const scene = new Scene(engine);
const environment = new CustomEnvironment(scene);
const persistenceManager = new IndexdbPersistenceManager("diagram");
const controllers = new Controllers();
const toolbox = new Toolbox(scene, controllers);
const diagramManager = new DiagramManager(scene, controllers, toolbox);
diagramManager.setPersistenceManager(persistenceManager);
const config = new AppConfig(persistenceManager);
const environment = new CustomEnvironment(scene, "default", config);
persistenceManager.initialize().then(() => {
if (!config.current?.demoCompleted) {
const intro = new Introduction(scene, config);
intro.start();
}
});
const camera: ArcRotateCamera = new ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2, 4,
@ -92,27 +94,14 @@ export class App {
}
});
const controllers = new Controllers();
const diagramManager = new DiagramManager(scene, xr.baseExperience, controllers);
const rig = new Rigplatform(scene, xr, diagramManager, controllers);
const toolbox = new Toolbox(scene, xr.baseExperience, diagramManager, controllers);
//const dioManager = new DrawioManager(scene, diagramManager);
import ('./integration/indexdbPersistenceManager').then((module) => {
const persistenceManager = new module.IndexdbPersistenceManager("diagram");
diagramManager.setPersistenceManager(persistenceManager);
AppConfig.config.setPersistenceManager(persistenceManager);
persistenceManager.initialize().then(() => {
if (!AppConfig.config?.demoCompleted) {
const intro = new Introduction(scene);
intro.start();
}
});
//const newRelicData = new NewRelicData(persistenceManager, scene);
});
});

View File

@ -14,7 +14,6 @@ import {DiagramManager} from "../diagram/diagramManager";
import {DiagramEvent, DiagramEventType} from "../diagram/diagramEntity";
import log from "loglevel";
import {Controllers} from "./controllers";
import {AppConfig} from "../util/appConfig";
export class Base {
static stickVector = Vector3.Zero();
@ -217,8 +216,8 @@ export class Base {
this.reparent(mesh);
if (!mesh.physicsBody) {
mesh.position = AppConfig.config.snapGridVal(mesh.position);
mesh.rotation = AppConfig.config.snapRotateVal(mesh.rotation);
mesh.position = this.diagramManager.config.snapGridVal(mesh.position);
mesh.rotation = this.diagramManager.config.snapRotateVal(mesh.rotation);
}
this.previousParentId = null;
this.previousScaling = null;

View File

@ -13,7 +13,7 @@ export class Left extends Base {
WebXRInputSource, scene: Scene, xr: WebXRDefaultExperience, diagramManager: DiagramManager, controllers: Controllers) {
super(controller, scene, xr, controllers, diagramManager);
this.configMenu = new ConfigMenu(this.scene, xr.baseExperience, this.controllers);
this.configMenu = new ConfigMenu(this.scene, xr.baseExperience, this.controllers, this.diagramManager.config);
this.controller.onMotionControllerInitObservable.add((init) => {
if (init.components['xr-standard-thumbstick']) {
init.components['xr-standard-thumbstick']

View File

@ -20,7 +20,6 @@ import {EditMenu} from "../menus/editMenu";
import {Controllers} from "./controllers";
import log from "loglevel";
import {DiagramManager} from "../diagram/diagramManager";
import {AppConfig} from "../util/appConfig";
export class Rigplatform {
@ -62,9 +61,9 @@ export class Rigplatform {
this.velocity.y = (val * this.velocityArray[this.velocityIndex])*-1;
}
public turn(val: number) {
const snap = AppConfig.config.currentTurnSnap.value;
const snap = this.diagramManager.config.current?.turnSnap;
if (snap > 0) {
if (snap && snap > 0) {
if (!this.turning) {
if (Math.abs(val) > .1) {
this.turning = true;
@ -192,7 +191,9 @@ export class Rigplatform {
}
private fixRotation() {
this.scene.onAfterPhysicsObservable.add(() => {
if (AppConfig?.config?.currentTurnSnap?.value > 0) {
const turnSnap = this.diagramManager.config.current?.turnSnap;
if (turnSnap && turnSnap > 0) {
const q = this.rigMesh.rotationQuaternion;
this.body.setAngularVelocity(Vector3.Zero());
if (q) {

View File

@ -11,7 +11,7 @@ import {
PhysicsShapeType,
PlaySoundAction,
Scene,
WebXRExperienceHelper
Vector3
} from "@babylonjs/core";
import {DiagramEntity, DiagramEvent, DiagramEventType} from "./diagramEntity";
import {IPersistenceManager} from "../integration/iPersistenceManager";
@ -21,37 +21,21 @@ import {Controllers} from "../controllers/controllers";
import {DiaSounds} from "../util/diaSounds";
import {AppConfig} from "../util/appConfig";
import {TextLabel} from "./textLabel";
import {Toolbox} from "../toolbox/toolbox";
export class DiagramManager {
public readonly onDiagramEventObservable: Observable<DiagramEvent> = new Observable();
private readonly logger = log.getLogger('DiagramManager');
private persistenceManager: IPersistenceManager = null;
private readonly toolbox: Toolbox;
private readonly scene: Scene;
private xr: WebXRExperienceHelper;
private sounds: DiaSounds;
public setPersistenceManager(persistenceManager: IPersistenceManager) {
this.persistenceManager = persistenceManager;
this.persistenceManager.updateObserver.add(this.onRemoteEvent, -1, true, this);
}
private getPersistenceManager(): IPersistenceManager {
if (!this.persistenceManager) {
this.logger.warn("persistenceManager not set");
return null;
}
return this.persistenceManager;
}
private readonly actionManager: ActionManager;
private config: AppConfig;
private controllers: Controllers;
constructor(scene: Scene, xr: WebXRExperienceHelper, controllers: Controllers) {
constructor(scene: Scene, controllers: Controllers, toolbox: Toolbox) {
this.sounds = new DiaSounds(scene);
this.scene = scene;
this.xr = xr;
this.toolbox = toolbox;
this.controllers = controllers;
this.actionManager = new ActionManager(this.scene);
this.actionManager.registerAction(
@ -86,6 +70,30 @@ export class DiagramManager {
}
});
}
private _config: AppConfig;
private getPersistenceManager(): IPersistenceManager {
if (!this.persistenceManager) {
this.logger.warn("persistenceManager not set");
return null;
}
return this.persistenceManager;
}
private readonly actionManager: ActionManager;
private controllers: Controllers;
public get config(): AppConfig {
return this._config;
}
public setPersistenceManager(persistenceManager: IPersistenceManager) {
this.persistenceManager = persistenceManager;
this._config = new AppConfig(persistenceManager);
this.persistenceManager.updateObserver.add(this.onRemoteEvent, -1, true, this);
}
public createCopy(mesh: AbstractMesh, copy: boolean = false): AbstractMesh {
let newMesh;
if (!mesh.isAnInstance) {
@ -103,12 +111,23 @@ export class DiagramManager {
if (copy) {
newMesh.scaling = mesh.scaling.clone();
} else {
newMesh.scaling = AppConfig.config.createSnapVal;
if (this.config.current?.createSnap) {
newMesh.scaling.x = this.config.current?.createSnap;
newMesh.scaling.y = this.config.current?.createSnap;
newMesh.scaling.z = this.config.current?.createSnap;
} else {
newMesh.scaling = Vector3.One();
}
}
newMesh.material = mesh.material;
newMesh.metadata = this.deepCopy(mesh.metadata);
if (this.config.current?.physicsEnabled) {
DiagramShapePhysics.applyPhysics(this.sounds, newMesh, this.scene);
}
this.persistenceManager.add(newMesh);
return newMesh;
}
@ -135,18 +154,18 @@ export class DiagramManager {
const toolMesh = this.scene.getMeshById("tool-" + event.template + "-" + event.color);
if (!toolMesh && (event.template != '#connection-template')) {
log.debug('no mesh found for ' + event.template + "-" + event.color, 'adding it');
this.onDiagramEventObservable.notifyObservers({
type: DiagramEventType.CHANGECOLOR,
entity: event
});
//this.getPersistenceManager()?.changeColor(null, Color3.FromHexString(event.color));
this.toolbox.updateToolbox(event.color);
}
const mesh = MeshConverter.fromDiagramEntity(event, this.scene);
mesh.actionManager = this.actionManager;
if (event.parent) {
mesh.parent = this.scene.getMeshById(event.parent);
}
if (this.config.current?.physicsEnabled) {
DiagramShapePhysics.applyPhysics(this.sounds, mesh, this.scene, PhysicsMotionType.DYNAMIC);
}
}
private onDiagramEvent(event: DiagramEvent) {
this.logger.debug(event.type);
@ -157,20 +176,20 @@ export class DiagramManager {
}
if (!mesh && event?.entity?.template) {
const toolMesh = this.scene.getMeshById("tool-" + event.entity.template + "-" + event.entity.color);
if (!toolMesh) {
if (!toolMesh && event.type != DiagramEventType.CHANGECOLOR) {
log.debug('no mesh found for ' + event.entity.template + "-" + event.entity.color, 'adding it');
this.onDiagramEventObservable.notifyObservers({
type: DiagramEventType.CHANGECOLOR,
entity: event.entity
});
this.toolbox.updateToolbox(event.entity.color);
}
mesh = MeshConverter.fromDiagramEntity(event.entity, this.scene);
if (mesh) {
mesh.actionManager = this.actionManager;
if (this.config.current.physicsEnabled) {
DiagramShapePhysics.applyPhysics(this.sounds, mesh, this.scene, PhysicsMotionType.DYNAMIC);
}
}
}
switch (event.type) {
case DiagramEventType.CLEAR:
@ -189,13 +208,19 @@ export class DiagramManager {
if (!mesh.actionManager) {
mesh.actionManager = this.actionManager;
}
if (this.config.current.physicsEnabled) {
DiagramShapePhysics
.applyPhysics(this.sounds, mesh, this.scene);
}
break;
case DiagramEventType.MODIFY:
this.getPersistenceManager()?.modify(mesh);
if (this.config.current.physicsEnabled) {
DiagramShapePhysics
.applyPhysics(this.sounds, mesh, this.scene);
}
break;
case DiagramEventType.CHANGECOLOR:
if (!event.oldColor) {
@ -234,9 +259,6 @@ class DiagramShapePhysics {
private static logger: log.Logger = log.getLogger('DiagramShapePhysics');
public static applyPhysics(sounds: DiaSounds, mesh: AbstractMesh, scene: Scene, motionType?: PhysicsMotionType) {
if (!AppConfig.config.physicsEnabled) {
return;
}
if (!mesh?.metadata?.template) {
this.logger.error("applyPhysics: mesh.metadata.template is null", mesh);
return;

View File

@ -43,6 +43,8 @@ export interface IPersistenceManager {
setConfig(config: AppConfigType);
getConfig(): Promise<AppConfigType>;
modifyDiagram(diagram: DiagramListing);
updateObserver: Observable<DiagramEntity>;

View File

@ -95,6 +95,12 @@ export class IndexdbPersistenceManager implements IPersistenceManager {
return this.db["newRelicData"].toArray();
}
public async getConfig(): Promise<AppConfigType> {
const configs = await this.db['config'].toArray();
const config = configs[0];
return config;
}
public async initialize() {
this.logger.info('initialize', this.db['entities'].length);
const configs = await this.db['config'].toArray();

View File

@ -12,19 +12,14 @@ export class ConfigMenu extends BaseMenu {
private configPlane: AbstractMesh = null;
private yObserver;
constructor(scene: Scene, xr: WebXRExperienceHelper, controllers: Controllers) {
super(scene, xr, controllers);
this.sounds = new DiaSounds(scene);
if (!this.yObserver) {
this.controllers.controllerObserver.add((event) => {
if (event.type == 'y-button') {
this.toggle();
}
});
}
}
private config: AppConfig;
private gridSnaps: Array<{ label: string, value: number }> = [
{label: "Off", value: 0},
{label: "0.01", value: 0.01},
{label: "0.1", value: 0.1},
{label: "0.5", value: 0.5},
{label: "1", value: 1},
]
public toggle() {
if (this.configPlane) {
@ -55,19 +50,35 @@ export class ConfigMenu extends BaseMenu {
CameraHelper.setMenuPosition(this.configPlane, this.scene);
}
private rotationSnaps: Array<{ label: string, value: number }> = [
{label: "Off", value: 0},
{label: "22.5", value: 22.5},
{label: "45", value: 45},
{label: "90", value: 90},
]
constructor(scene: Scene, xr: WebXRExperienceHelper, controllers: Controllers, config: AppConfig) {
super(scene, xr, controllers);
this.config = config;
this.sounds = new DiaSounds(scene);
if (!this.yObserver) {
this.controllers.controllerObserver.add((event) => {
if (event.type == 'y-button') {
this.toggle();
}
});
}
private createVal(value) {
AppConfig.config.currentCreateSnapIndex = value;
log.debug("configMenu", "create Snap", value);
}
private buildCreateScaleControl(selectionPanel: SelectionPanel): RadioGroup {
const radio = new RadioGroup("Create Scale");
selectionPanel.addGroup(radio);
for (const [index, snap] of AppConfig.config.createSnaps().entries()) {
const selected = AppConfig.config.currentCreateSnapIndex == index;
radio.addRadio(snap.label, this.createVal, selected);
for (const [index, snap] of this.gridSnaps.entries()) {
const selected = this.config.current.createSnap == snap.value
radio.addRadio(snap.label, this.createVal.bind(this), selected);
}
return radio;
}
@ -75,9 +86,9 @@ export class ConfigMenu extends BaseMenu {
private buildRotationSnapControl(selectionPanel: SelectionPanel): RadioGroup {
const radio = new RadioGroup("Rotation Snap");
selectionPanel.addGroup(radio);
for (const [index, snap] of AppConfig.config.rotateSnaps().entries()) {
const selected = AppConfig.config.currentRotateSnapIndex == index;
radio.addRadio(snap.label, this.rotateVal, selected);
for (const [index, snap] of this.rotationSnaps.entries()) {
const selected = this.config.current.rotateSnap == snap.value
radio.addRadio(snap.label, this.rotateVal.bind(this), selected);
}
return radio;
}
@ -85,9 +96,9 @@ export class ConfigMenu extends BaseMenu {
private buildGridSizeControl(selectionPanel: SelectionPanel): RadioGroup {
const radio = new RadioGroup("Grid Snap");
selectionPanel.addGroup(radio);
for (const [index, snap] of AppConfig.config.gridSnaps().entries()) {
const selected = AppConfig.config.currentGridSnapIndex == index;
radio.addRadio(snap.label, this.gridVal, selected);
for (const [index, snap] of this.gridSnaps.entries()) {
const selected = this.config.current.gridSnap == snap.value;
radio.addRadio(snap.label, this.gridVal.bind(this), selected);
}
return radio;
}
@ -95,25 +106,39 @@ export class ConfigMenu extends BaseMenu {
private buildTurnSnapControl(selectionPanel: SelectionPanel): RadioGroup {
const radio = new RadioGroup("Turn Snap");
selectionPanel.addGroup(radio);
for (const [index, snap] of AppConfig.config.turnSnaps().entries()) {
const selected = AppConfig.config.currentTurnSnapIndex == index;
radio.addRadio(snap.label, this.turnVal, selected);
for (const [index, snap] of this.rotationSnaps.entries()) {
const selected = this.config.current.rotateSnap == snap.value;
radio.addRadio(snap.label, this.turnVal.bind(this), selected);
}
return radio;
}
private createVal(value) {
const config = this.config.current;
config.createSnap = this.gridSnaps[value].value;
this.config.current = config;
log.debug("configMenu", "create Snap", value);
}
private rotateVal(value) {
AppConfig.config.currentRotateSnapIndex = value;
const config = this.config.current;
config.rotateSnap = this.rotationSnaps[value].value;
this.config.current = config;
log.debug("configMenu", "rotate Snap", value);
}
private turnVal(value) {
AppConfig.config.currentTurnSnapIndex = value;
const config = this.config.current;
config.turnSnap = this.rotationSnaps[value].value;
this.config.current = config;
log.debug("configMenu", "turn Snap", value);
}
private gridVal(value) {
AppConfig.config.currentGridSnapIndex = value;
const config = this.config.current;
config.gridSnap = this.gridSnaps[value].value;
this.config.current = config;
log.debug("configMenu", "grid Snap", value);
}

View File

@ -23,7 +23,6 @@ import {CameraHelper} from "../util/cameraHelper";
import {TextLabel} from "../diagram/textLabel";
import {DiagramConnection} from "../diagram/diagramConnection";
import {GLTF2Export} from "@babylonjs/serializers";
import {AppConfig} from "../util/appConfig";
export class EditMenu {
private state: EditMenuState = EditMenuState.NONE;
@ -263,11 +262,15 @@ export class EditMenu {
inputTextView.show();
inputTextView.onTextObservable.addOnce((value) => {
console.log(value.text);
AppConfig.config.newRelicKey = value.text;
const config = this.diagramManager.config.current;
config.newRelicKey = value.text;
this.diagramManager.config.current = config;
inputTextView.show();
inputTextView.onTextObservable.addOnce((value) => {
console.log(value.text);
AppConfig.config.newRelicAccount = value.text;
const config = this.diagramManager.config.current;
config.newRelicAccount = value.text;
this.diagramManager.config.current = config;
});
});

View File

@ -7,14 +7,11 @@ import {
Scene,
StandardMaterial,
TransformNode,
Vector3,
WebXRExperienceHelper
Vector3
} from "@babylonjs/core";
import {CameraHelper} from "../util/cameraHelper";
import {AdvancedDynamicTexture, Button3D, ColorPicker, GUI3DManager, StackPanel3D, TextBlock} from "@babylonjs/gui";
import {DiagramManager} from "../diagram/diagramManager";
import {DiagramEventType} from "../diagram/diagramEntity";
import {Controllers} from "../controllers/controllers";
export enum ToolType {
@ -30,24 +27,16 @@ export class Toolbox {
private index = 0;
public static instance: Toolbox;
private readonly scene: Scene;
private readonly xr: WebXRExperienceHelper;
public readonly node: TransformNode;
private readonly diagramManager: DiagramManager;
private readonly manager: GUI3DManager;
private readonly gridsize = 5;
private readonly addPanel: StackPanel3D;
private readonly controllers: Controllers;
private xObserver;
constructor(scene: Scene, xr: WebXRExperienceHelper, diagramManager: DiagramManager, controllers: Controllers) {
constructor(scene: Scene, controllers: Controllers) {
this.scene = scene;
this.controllers = controllers;
this.diagramManager = diagramManager;
this.diagramManager.onDiagramEventObservable.add((evt) => {
if (evt?.entity?.color && evt.type == DiagramEventType.CHANGECOLOR) {
this.updateToolbox(evt.entity.color);
}
}, -1, true, this);
this.addPanel = new StackPanel3D();
this.manager = new GUI3DManager(scene);
this.manager.addControl(this.addPanel);
@ -65,12 +54,8 @@ export class Toolbox {
handle.position = Vector3.Zero();
this.node.parent = handle;
this.xr = xr;
if (!this.scene.activeCamera) {
return;
} else {
this.buildToolbox();
}
Toolbox.instance = this;
if (!this.xObserver) {
@ -227,13 +212,6 @@ export class Toolbox {
material.name = "material-" + newColorHex;
mesh.id = "toolbox-color-" + newColorHex;
mesh.name = "toolbox-color-" + newColorHex;
this.diagramManager.onDiagramEventObservable.notifyObservers(
{
type: DiagramEventType.CHANGECOLOR,
oldColor: oldColor,
newColor: newColor
}
);
});
colorPickerTexture.addControl(colorPicker);

View File

@ -26,13 +26,16 @@ export class Introduction {
private items: AbstractMesh[] = [];
private advance: Button3D;
private sounds: DiaSounds;
private config: AppConfig;
constructor(scene: Scene) {
constructor(scene: Scene, config: AppConfig) {
this.sounds = new DiaSounds(scene);
this.scene = scene;
this.config = config;
this.manager = new GUI3DManager(scene);
this.physicsHelper = new PhysicsHelper(scene);
}
public start() {
this.scene.physicsEnabled = true;
this.advance = new Button3D("advance");
@ -167,7 +170,9 @@ export class Introduction {
});
this.advance.dispose();
this.manager.dispose();
AppConfig.config.demoCompleted = true;
const config = this.config.current;
config.demoCompleted = true;
this.config.current = config;
this.items = [];
}
this.step++;

View File

@ -1,4 +1,4 @@
import {Angle, Vector3} from "@babylonjs/core";
import {Angle, Observable, Vector3} from "@babylonjs/core";
import log from "loglevel";
import round from "round";
import {IPersistenceManager} from "../integration/iPersistenceManager";
@ -9,244 +9,84 @@ export type SnapValue = {
label: string
}
export class AppConfig {
private readonly logger = log.getLogger('AppConfig');
private _demoCompleted = false;
private gridSnap = 1;
private _turnSnap = 0;
private rotateSnap = 0;
private createSnap = 0;
private _newRelicKey: string = null;
public readonly onConfigChangedObservable = new Observable<AppConfigType>();
private _currentConfig: AppConfigType;
private persistenceManager: IPersistenceManager;
public get newRelicKey(): string {
return this._newRelicKey;
}
_physicsEnabled = false;
private readonly defaultGridSnapIndex = 1;
private persistenceManager: IPersistenceManager = null;
private gridSnapArray: SnapValue[] =
[{value: 0, label: "Off"},
{value: 0.05, label: "(Default)"},
{value: 0.01, label: "1 cm"},
{value: 0.1, label: "10 cm"},
{value: 0.25, label: "25 cm"},
{value: .5, label: ".5 m"}]
private createSnapArray: SnapValue[] =
[{value: .1, label: "Default (10 cm)"},
{value: 0.2, label: "20 cm"},
{value: 0.5, label: ".5 m"},
{value: 1, label: "1 m"}];
private rotateSnapArray: SnapValue[] =
[{value: 0, label: "Off"},
{value: 22.5, label: "22.5 Degrees"},
{value: 45, label: "45 Degrees"},
{value: 90, label: "90 Degrees"}];
private turnSnapArray: SnapValue[] =
[{value: 0, label: "Off"},
{value: 22.5, label: "22.5 Degrees"},
{value: 45, label: "45 Degrees"},
{value: 90, label: "90 Degrees"}];
public get currentGridSnap(): SnapValue {
return this.gridSnapArray[this.gridSnap || 0];
}
public get demoCompleted(): boolean {
return this._demoCompleted || false;
}
public set demoCompleted(val: boolean) {
this._demoCompleted = val;
this.save();
}
public set newRelicKey(val: string) {
this._newRelicKey = val;
this.save();
}
private _newRelicAccount: string = null;
public get newRelicAccount(): string {
return this._newRelicAccount;
}
public set newRelicAccount(val: string) {
this._newRelicAccount = val;
this.save();
}
public get physicsEnabled(): boolean {
return this._physicsEnabled || false;
}
public set phsyicsEnabled(val: boolean) {
this._physicsEnabled = val;
this.save();
}
private static _config: AppConfig;
public static get config() {
if (!AppConfig._config) {
AppConfig._config = new AppConfig();
}
return AppConfig._config;
}
public get currentRotateSnap(): SnapValue {
return this.rotateSnapArray[this.rotateSnap || 0];
}
public get currentCreateSnap(): SnapValue {
return this.createSnapArray[this.createSnap || 0];
}
public get currentTurnSnap(): SnapValue {
return this.turnSnapArray[this._turnSnap || 0];
}
public get currentGridSnapIndex(): number {
return this.gridSnap || 0;
}
public set currentTurnSnapIndex(val: number) {
this._turnSnap = val;
this.save();
}
public set currentGridSnapIndex(val: number) {
this.gridSnap = val;
this.save();
}
public get currentCreateSnapIndex(): number {
return this.createSnap || 0;
}
public set currentCreateSnapIndex(val: number) {
this.createSnap = val;
if (this.currentGridSnapIndex == this.defaultGridSnapIndex) {
this.currentGridSnap.value = this.currentCreateSnap.value / 2;
this.logger.debug("Set grid snap to " + this.currentGridSnap.value);
}
this.save();
}
public get currentRotateSnapIndex(): number {
return this.rotateSnap || 0;
}
public set currentRotateSnapIndex(val: number) {
this.rotateSnap = val;
this.save();
}
public get createSnapVal(): Vector3 {
return new Vector3(this.currentCreateSnap.value, this.currentCreateSnap.value, this.currentCreateSnap.value);
}
public setPersistenceManager(persistenceManager: IPersistenceManager) {
constructor(persistenceManager: IPersistenceManager) {
this.persistenceManager = persistenceManager;
this.persistenceManager.configObserver.add(this.configObserver, -1, false, this);
this.persistenceManager.configObserver.add(this.load, -1, false, this, false);
}
public gridSnaps(): SnapValue[] {
return this.gridSnapArray;
public get current(): AppConfigType {
if (!this._currentConfig) {
this.persistenceManager.getConfig().then((config) => {
if (!config) {
const newconfig = {
id: 1,
gridSnap: .1,
rotateSnap: 45,
createSnap: .1,
turnSnap: 22.5,
newRelicKey: null,
newRelicAccount: null,
physicsEnabled: false,
demoCompleted: false,
}
this._currentConfig = newconfig;
this.save();
} else {
this._currentConfig = config;
}
public turnSnaps(): SnapValue[] {
return this.turnSnapArray;
});
}
return this._currentConfig;
}
public createSnaps(): SnapValue[] {
return this.createSnapArray;
public set current(config: AppConfigType) {
this._currentConfig = config;
this.save();
}
public rotateSnaps(): SnapValue[] {
return this.rotateSnapArray;
public save() {
this.persistenceManager.setConfig(this._currentConfig);
}
public snapGridVal(value: Vector3): Vector3 {
if (this.currentGridSnapIndex == 0) {
public load(config: AppConfigType) {
this._currentConfig = config;
this.onConfigChangedObservable.notifyObservers(this._currentConfig);
}
public snapGridVal(value: Vector3, snap: number): Vector3 {
if (!snap) {
return value;
}
const position = value.clone();
position.x = round(position.x, this.currentGridSnap.value);
position.y = round(position.y, this.currentGridSnap.value);
position.z = round(position.z, this.currentGridSnap.value);
position.x = round(value.x, snap);
position.y = round(value.y, snap);
position.z = round(value.z, snap);
return position;
}
public snapRotateVal(value: Vector3): Vector3 {
if (this.currentRotateSnapIndex == 0) {
public snapRotateVal(value: Vector3, snap: number): Vector3 {
if (!snap) {
return value;
}
const rotation = new Vector3();
rotation.x = this.snapAngle(value.x);
rotation.y = this.snapAngle(value.y);
rotation.z = this.snapAngle(value.z);
rotation.x = this.snapAngle(value.x, snap);
rotation.y = this.snapAngle(value.y, snap);
rotation.z = this.snapAngle(value.z, snap);
return rotation;
}
private snapAngle(val: number): number {
private snapAngle(val: number, snap: number): number {
const angle = snap;
const deg = Angle.FromRadians(val).degrees();
const snappedDegrees = round(deg, this.currentRotateSnap.value);
this.logger.debug("deg", val, deg, snappedDegrees, this.currentRotateSnap.value);
const snappedDegrees = round(deg, angle);
this.logger.debug("deg", val, deg, snappedDegrees, angle);
return Angle.FromDegrees(snappedDegrees).radians();
}
private save() {
this.persistenceManager.setConfig(
{
gridSnap: this.currentGridSnap.value,
rotateSnap: this.currentRotateSnap.value,
createSnap: this.currentCreateSnap.value,
turnSnap: this.currentTurnSnap.value,
physicsEnabled: this._physicsEnabled,
newRelicKey: this._newRelicKey,
newRelicAccount: this._newRelicAccount,
demoCompleted: this._demoCompleted
});
}
private configObserver(config: AppConfigType) {
if (config) {
if (config.physicsEnabled && config.physicsEnabled != this._physicsEnabled) {
this._physicsEnabled = config.physicsEnabled;
this.logger.debug("Physics enabled changed to " + this._physicsEnabled);
}
if (config.demoCompleted) {
this._demoCompleted = config.demoCompleted;
}
if (config.createSnap != this.currentCreateSnap.value ||
config.gridSnap != this.currentGridSnap.value ||
config.rotateSnap != this.currentRotateSnap.value) {
this.logger.debug("Config changed", config);
this._turnSnap = this.turnSnapArray.findIndex((snap) => snap.value == config.turnSnap);
if (!this._turnSnap || this._turnSnap == -1) {
this._turnSnap = 0;
}
this.rotateSnap = this.rotateSnapArray.findIndex((snap) => snap.value == config.rotateSnap);
if (!this.rotateSnap || this.rotateSnap == -1) {
this.rotateSnap = 0;
}
this.createSnap = this.createSnapArray.findIndex((snap) => snap.value == config.createSnap);
if (!this.createSnap || this.createSnap == -1) {
this.createSnap = 0;
}
const gridSnap = this.gridSnapArray.findIndex((snap) => snap.value == config.gridSnap);
if (gridSnap == -1) {
this.gridSnap = this.defaultGridSnapIndex;
this.currentGridSnap.value = config.gridSnap;
}
} else {
this.logger.debug("Config unchanged", config);
}
} else {
this.logger.debug("Config not set");
}
}
}

View File

@ -7,21 +7,24 @@ import {
PhysicsAggregate,
PhysicsShapeType,
Scene,
Texture
Sound,
Texture,
Vector3
} from "@babylonjs/core";
import {CustomPhysics} from "./customPhysics";
import {DiaSounds} from "./diaSounds";
import {AppConfig} from "./appConfig";
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") {
constructor(scene: Scene, name: string = "default", config: AppConfig) {
this.scene = scene;
this.name = name;
const physics = new CustomPhysics(this.scene);
const physics = new CustomPhysics(this.scene, config);
physics
.initializeAsync()
.then(() => {
@ -32,7 +35,29 @@ export class CustomEnvironment {
'/assets/textures/outdoor_field2.jpeg', {},
scene);
try {
new DiaSounds(scene);
const sounds = new DiaSounds(scene);
window.setTimeout((sound) => {
sound.play()
}, 2000, sounds.background);
const birds: Array<Sound> = [sounds.birds, sounds.dove];
window.setInterval((sounds: Array<Sound>) => {
if (Math.random() < .6) {
return;
}
const sound = Math.floor(Math.random() * sounds.length);
const x = Math.floor(Math.random() * 20);
const z = Math.floor(Math.random() * 20);
const position = new Vector3(x, 0, z);
if (sounds[sound].isPlaying) {
} else {
sounds[sound].setPosition(position);
sounds[sound].setVolume(Math.random() * .5);
sounds[sound].play();
}
}, 2000, birds);
} catch (error) {
console.log(error);
}

View File

@ -4,9 +4,11 @@ import {AppConfig} from "./appConfig";
export class CustomPhysics {
private scene: Scene;
private config: AppConfig;
constructor(scene: Scene) {
constructor(scene: Scene, config: AppConfig) {
this.scene = scene;
this.config = config;
}
public async initializeAsync() {
@ -24,10 +26,10 @@ export class CustomPhysics {
if (true) {
body.disablePreStep = false;
const pos: Vector3 = body.getObjectCenterWorld();
const val: Vector3 = AppConfig.config.snapGridVal(pos);
const val: Vector3 = this.config.snapGridVal(pos);
body.transformNode.position.set(val.x, val.y, val.z);
const rot: Quaternion =
Quaternion.FromEulerVector(AppConfig.config.snapRotateVal(body.transformNode.rotationQuaternion.toEulerAngles()))
Quaternion.FromEulerVector(this.config.snapRotateVal(body.transformNode.rotationQuaternion.toEulerAngles()))
body.transformNode.rotationQuaternion.set(
rot.x, rot.y, rot.z, rot.w

View File

@ -8,32 +8,16 @@ export class DiaSounds {
public get tick() {
return new Sound("tick", '/assets/sounds/tick.mp3', this.scene);
}
private volume: number = 0.8;
private readonly _bounce;
private readonly _bounce: Sound;
private readonly _background: Sound;
private readonly _enter: Sound;
public get enter() {
return this._enter;
}
private readonly _exit: Sound;
public get exit() {
return this._exit;
}
private readonly _high: Sound;
public get high() {
return this._high;
}
private readonly _low: Sound;
public get low() {
return this._low;
}
constructor(scene: Scene) {
this.scene = scene;
this._enter = new Sound("enter", "/assets/sounds/sounds.mp3", this.scene, null, {
@ -72,15 +56,62 @@ export class DiaSounds {
offset: 0,
length: 0.990
});
this._birds = new Sound("birds", "/assets/sounds/birds.mp3", this.scene, null, {
autoplay: true,
this._background = new Sound("brown", "/assets/sounds/brown.mp3", this.scene, null, {
autoplay: false,
volume: 1,
loop: true
});
this._birds = new Sound("warbler", "/assets/sounds/warbler.mp3", this.scene, null, {
spatialSound: true,
autoplay: false,
volume: .5,
loop: false
});
this.birds.switchPanningModelToHRTF();
this.birds.maxDistance = 40;
this._dove = new Sound("dove", "/assets/sounds/dove.mp3", this.scene, null, {
spatialSound: true,
autoplay: false,
volume: .5,
loop: false
});
this._dove.switchPanningModelToHRTF();
this._dove.maxDistance = 40;
//this._enter.autoplay = true;
}
public get background(): Sound {
return this._background;
}
private readonly _exit: Sound;
public get exit() {
return this._exit;
}
private readonly _high: Sound;
public get high() {
return this._high;
}
private readonly _low: Sound;
public get low() {
return this._low;
}
public get birds(): Sound {
return this._birds;
}
_dove: Sound;
public get dove() {
return this._dove;
}
public get bounce() {
const bounce = this._bounce.clone();
bounce.updateOptions({offset: 0, volume: this.volume, length: .990});