Rearrange touch/step/teleport logic
This commit is contained in:
parent
e865e00e56
commit
9bdc37bda1
114
src/engine.ts
114
src/engine.ts
|
@ -61,31 +61,46 @@ export type EngineOptions = {
|
|||
canvas: HTMLCanvasElement | null,
|
||||
};
|
||||
|
||||
export type ButtonState = { [button: number]: boolean };
|
||||
export type ButtonState = {
|
||||
checkTime: number,
|
||||
isDown: boolean,
|
||||
wasPressed: boolean,
|
||||
wasReleased: boolean,
|
||||
};
|
||||
|
||||
export class GamepadState {
|
||||
buttons: ButtonState = {};
|
||||
buttons: { [button: number]: ButtonState } = {};
|
||||
checkTime = 0;
|
||||
|
||||
constructor (
|
||||
public gp: Gamepad, // NB. browser's Gamepad class, not Babylon's Gamepad class.
|
||||
) {}
|
||||
|
||||
latch(button: number): boolean {
|
||||
let result = false;
|
||||
const b = this.gp.buttons[button];
|
||||
if (b) {
|
||||
if (b.pressed) {
|
||||
if (!this.isDown(button)) result = true;
|
||||
this.buttons[button] = true;
|
||||
} else {
|
||||
this.buttons[button] = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
tick() {
|
||||
this.checkTime++;
|
||||
}
|
||||
|
||||
isDown(button: number): boolean {
|
||||
return this.buttons[button] ?? false;
|
||||
b(button: number): ButtonState {
|
||||
if (!(button in this.buttons)) {
|
||||
this.buttons[button] = {
|
||||
checkTime: -1,
|
||||
isDown: false,
|
||||
wasPressed: false,
|
||||
wasReleased: false,
|
||||
};
|
||||
}
|
||||
const result = this.buttons[button];
|
||||
|
||||
const b = this.gp.buttons[button];
|
||||
if (b && result.checkTime !== this.checkTime) {
|
||||
result.checkTime = this.checkTime;
|
||||
const wasDown = result.isDown;
|
||||
result.isDown = b.pressed;
|
||||
result.wasPressed = result.isDown && !wasDown;
|
||||
result.wasReleased = !result.isDown && wasDown;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,6 +112,7 @@ export class RunningEngine {
|
|||
gamepadInput: FreeCameraGamepadInput;
|
||||
|
||||
xrCamera: WebXRCamera | null = null;
|
||||
xrTeleportTimer: any = null;
|
||||
|
||||
leanBase: { position: Vector3 } | null = null;
|
||||
recenterBase: { rotation: Quaternion } | null = null;
|
||||
|
@ -257,29 +273,50 @@ export class RunningEngine {
|
|||
checkGamepadInput(gp: Gamepad) {
|
||||
const state = this.padStateFor(gp);
|
||||
|
||||
if (state.latch(9 /* options */)) location.reload();
|
||||
if (state.latch(2 /* square */)) this.jump();
|
||||
if (state.latch(3 /* triangle */)) this.turn180();
|
||||
if (state.b(9 /* options */).wasPressed) location.reload();
|
||||
if (state.b(2 /* square */).wasPressed) this.jump();
|
||||
if (state.b(3 /* triangle */).wasPressed) this.turn180();
|
||||
|
||||
if (this.xrAvailable) {
|
||||
if (state.latch(16 /* ps */)) this.xrToggle();
|
||||
if (state.b(16 /* ps */).wasPressed) this.xrToggle();
|
||||
}
|
||||
|
||||
if (this.inXR) {
|
||||
this.xrUpdateLean(gp);
|
||||
if (state.latch(0 /* cross */)) this.xrTeleport();
|
||||
if (state.latch(1 /* circle */)) this.xrTouch();
|
||||
|
||||
if (state.latch(8 /* share */)) {
|
||||
const actionButton = state.b(0 /* cross */);
|
||||
if (actionButton.wasPressed) {
|
||||
this.clearTeleportTimer();
|
||||
this.xrTeleportTimer = setTimeout(() => {
|
||||
this.clearTeleportTimer();
|
||||
this.xrTeleport();
|
||||
}, 333);
|
||||
}
|
||||
if (actionButton.wasReleased && this.xrTeleportTimer !== null) {
|
||||
this.clearTeleportTimer();
|
||||
this.xrStepOrTouch();
|
||||
}
|
||||
|
||||
const shareButton = state.b(8 /* share */);
|
||||
if (shareButton.wasPressed) {
|
||||
this.recenterBase = {
|
||||
rotation: this.xrCamera!.rotationQuaternion.clone(),
|
||||
};
|
||||
}
|
||||
if (state.isDown(8 /* share */) && this.recenterBase) {
|
||||
if (shareButton.isDown && this.recenterBase) {
|
||||
this.xrCamera!.rotationQuaternion.copyFrom(
|
||||
this.recenterBase.rotation);
|
||||
}
|
||||
}
|
||||
|
||||
state.tick();
|
||||
}
|
||||
|
||||
clearTeleportTimer() {
|
||||
if (this.xrTeleportTimer !== null) {
|
||||
clearTimeout(this.xrTeleportTimer);
|
||||
this.xrTeleportTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
checkKeys() {
|
||||
|
@ -332,28 +369,35 @@ export class RunningEngine {
|
|||
}
|
||||
}
|
||||
|
||||
xrTouch() {
|
||||
xrStepOrTouch() {
|
||||
if (!this.inXR) return;
|
||||
|
||||
const ray = this.xrCamera!.getForwardRay();
|
||||
const meshes = this.interactivity.touchableMeshes();
|
||||
const hit = this.scene.pickWithRay(ray, m => meshes.indexOf(m as any) !== -1);
|
||||
|
||||
if (hit === null) return;
|
||||
if (meshes.indexOf(hit.pickedMesh as any) === -1) return;
|
||||
const hit = this.scene.pickWithRay(ray);
|
||||
|
||||
if (hit !== null
|
||||
&& hit.distance <= 1
|
||||
&& this.interactivity.touchableMeshes().indexOf(hit.pickedMesh as any) !== -1)
|
||||
{
|
||||
this.camera.onCollide?.(hit.pickedMesh!);
|
||||
return;
|
||||
}
|
||||
|
||||
const stepDistance =
|
||||
hit && hit.hit && hit.distance <= 1 ? hit.distance * 0.5 : 1;
|
||||
const pos = this.xrCamera!.position.add(ray.direction.normalizeToNew().scale(stepDistance));
|
||||
this.xrCamera!.position = pos;
|
||||
if (this.leanBase !== null) this.leanBase.position = pos;
|
||||
}
|
||||
|
||||
xrTeleport() {
|
||||
if (!this.inXR) return;
|
||||
|
||||
const ray = this.xrCamera!.getForwardRay();
|
||||
const meshes = this.interactivity.floorMeshes();
|
||||
const hit = this.scene.pickWithRay(ray, m => meshes.indexOf(m as any) !== -1);
|
||||
|
||||
const hit = this.scene.pickWithRay(ray);
|
||||
if (hit === null) return;
|
||||
if (meshes.indexOf(hit.pickedMesh as any) === -1) return;
|
||||
if (hit.pickedPoint === null) return;
|
||||
|
||||
if (this.interactivity.floorMeshes().indexOf(hit.pickedMesh as any) === -1) return;
|
||||
const pos = hit.pickedPoint.add(new Vector3(0, 1.6, 0));
|
||||
this.xrCamera!.position = pos;
|
||||
this.xrCamera!.rotation = Vector3.Zero();
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
Assertable,
|
||||
Assertion,
|
||||
Dictionary,
|
||||
Double,
|
||||
Facet,
|
||||
Ref,
|
||||
Turn,
|
||||
|
@ -36,7 +37,11 @@ export function logValues(values: Assertable[]) {
|
|||
const d = new Dictionary<Ref>();
|
||||
if (logId !== null) d.set(Symbol.for('pid'), logId);
|
||||
if (logService !== null) d.set(Symbol.for('service'), logService);
|
||||
d.set(Symbol.for('line'), values.map(v => typeof(v) === 'string' ? v : stringify(v)).join(' '));
|
||||
d.set(Symbol.for('line'), values.map(v => {
|
||||
if (typeof(v) === 'string') return v;
|
||||
if (typeof(v) === 'number' && Math.round(v) !== v) return Double(v);
|
||||
return stringify(v);
|
||||
}).join(' '));
|
||||
send message LogEntry((new Date()).toISOString(), d);
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue