immersive2/src/controllers/rigplatform.ts

216 lines
7.6 KiB
TypeScript

import {Angle, Mesh, Quaternion, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core";
import {RightController} from "./rightController";
import {LeftController} from "./leftController";
import log from "loglevel";
import {DiagramManager} from "../diagram/diagramManager";
import {buildRig} from "./functions/buildRig";
import {DefaultScene} from "../defaultScene";
import {ControllerEvent} from "./types/controllerEvent";
import {ControllerEventType} from "./types/controllerEventType";
import {controllerObservable} from "./controllers";
const RIGHT = "right";
const LEFT = "left";
export class Rigplatform {
public static instance: Rigplatform;
public turnSnap: number = 0;
public rigMesh: Mesh;
private _logger = log.getLogger('Rigplatform');
private readonly _diagramManager: DiagramManager;
private readonly _scene: Scene;
private readonly _velocityArray = [0.01, 0.1, 1, 2, 5];
private readonly _xr: WebXRDefaultExperience;
private _rightController: RightController;
private _leftController: LeftController;
private _turning: boolean = false;
private _velocity: Vector3 = Vector3.Zero();
private _velocityIndex: number = 2;
private _turnVelocity: number = 0;
private _registered = false;
private _yRotation: number = 0;
constructor(
xr: WebXRDefaultExperience,
diagramManager: DiagramManager
) {
this._scene = DefaultScene.Scene;
this._diagramManager = diagramManager;
this._xr = xr;
this.rigMesh = buildRig(xr);
this._fixRotation();
this._initializeControllers();
this._registerVelocityObserver();
}
private _flyMode: boolean = true;
public set flyMode(value: boolean) {
this._flyMode = value;
if (this._flyMode) {
this.rigMesh.physicsBody.setGravityFactor(.01);
this._logger.debug('flymode');
} else {
this.rigMesh.physicsBody.setGravityFactor(1);
this._logger.debug('walkmode');
}
}
public forwardback(val: number) {
this._velocity.z = (val * this._velocityArray[this._velocityIndex]) * -1;
}
public leftright(val: number) {
this._velocity.x = (val * this._velocityArray[this._velocityIndex]);
}
public updown(val: number) {
this._velocity.y = (val * this._velocityArray[this._velocityIndex]) * -1;
}
public turn(val: number) {
const snap = this.turnSnap;
if (snap && snap > 0) {
if (!this._turning) {
if (Math.abs(val) > .1) {
this._turning = true;
this._yRotation += Angle.FromDegrees(Math.sign(val) * snap).radians();
}
} else {
if (Math.abs(val) < .1) {
this._turning = false;
}
}
} else {
if (Math.abs(val) > .1) {
this._turnVelocity = val;
} else {
this._turnVelocity = 0;
}
}
}
private _registerVelocityObserver() {
this._scene.onBeforeRenderObservable.add(() => {
const vel = this._velocity.applyRotationQuaternion(this._scene.activeCamera.absoluteRotation);
if (!this._flyMode) {
vel.y = 0;
}
if (vel.length() > 0) {
this._logger.debug('Velocity', this._velocity, vel, this._scene.activeCamera.absoluteRotation);
}
this.rigMesh.physicsBody.setLinearVelocity(vel);
});
}
private _registerObserver() {
if (this._registered) {
this._logger.warn('observer already registered, clearing and re registering');
controllerObservable.clear();
this._registered = false;
}
if (!this._registered) {
this._registered = true;
controllerObservable.add((event: ControllerEvent) => {
this._logger.debug(event);
switch (event.type) {
case ControllerEventType.INCREASE_VELOCITY:
if (this._velocityIndex < this._velocityArray.length - 1) {
this._velocityIndex++;
} else {
this._velocityIndex = 0;
}
break;
case ControllerEventType.DECREASE_VELOCITY:
if (this._velocityIndex > 0) {
this._velocityIndex--;
} else {
this._velocityIndex = this._velocityArray.length - 1;
}
break;
case ControllerEventType.TURN:
this.turn(event.value);
break;
case ControllerEventType.FORWARD_BACK:
this.forwardback(event.value);
break;
case ControllerEventType.LEFT_RIGHT:
this.leftright(event.value);
break;
case ControllerEventType.UP_DOWN:
if (this._flyMode) {
this.updown(event.value);
}
break;
case ControllerEventType.MOTION:
this._logger.debug(JSON.stringify(event));
break;
}
});
} else {
this._logger.warn('observer already registered');
}
}
private _initializeControllers() {
this._xr.input.onControllerAddedObservable.add((source) => {
this._registerObserver();
switch (source.inputSource.handedness) {
case RIGHT:
if (!this._rightController) {
this._rightController = new RightController(source, this._xr, this._diagramManager);
}
break;
case LEFT:
if (!this._leftController) {
this._leftController = new LeftController(source, this._xr, this._diagramManager);
}
break;
}
//this.xr.baseExperience.camera.position = new Vector3(0, 0, 0);
});
this._xr.input.onControllerRemovedObservable.add((source) => {
switch (source.inputSource.handedness) {
case RIGHT:
if (this._rightController) {
this._rightController = null;
}
break;
case LEFT:
if (this._leftController) {
this._leftController = null;
}
break;
}
this._logger.debug('controller removed', source);
});
}
private _fixRotation() {
if (!this._scene) {
return;
}
this._scene.onAfterPhysicsObservable.add(() => {
const turnSnap = this.turnSnap;
if (turnSnap && turnSnap > 0) {
const q = this.rigMesh.rotationQuaternion;
this.rigMesh.physicsBody.setAngularVelocity(Vector3.Zero());
if (q) {
const e = q.toEulerAngles();
e.y += this._yRotation;
q.copyFrom(Quaternion.FromEulerAngles(0, e.y, 0));
}
} else {
this.rigMesh.physicsBody.setAngularVelocity(Vector3.Up().scale(this._turnVelocity));
}
}, -1, false, this, false);
}
}