From e88188cd6dde74591defa464013b0e84c0739c7f Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Tue, 28 Apr 2026 16:22:08 +0900
Subject: [PATCH] wip
---
packages/frontend/src/pages/room.vue | 64 ++++++-------------
.../frontend/src/world/room/controller.ts | 10 +--
packages/frontend/src/world/room/engine.ts | 12 ++--
packages/frontend/src/world/utility.ts | 49 --------------
4 files changed, 25 insertions(+), 110 deletions(-)
diff --git a/packages/frontend/src/pages/room.vue b/packages/frontend/src/pages/room.vue
index 163b10ac74..59c06213e4 100644
--- a/packages/frontend/src/pages/room.vue
+++ b/packages/frontend/src/pages/room.vue
@@ -59,15 +59,9 @@ SPDX-License-Identifier: AGPL-3.0-only
-
@@ -218,20 +212,17 @@ const resolutionRaw = prefer.model('world.resolution');
const resolutionAutoValue = computed(() => deviceKind !== 'desktop' ? 0.5 : 1);
const resolution = computed(() => resolutionRaw.value ?? resolutionAutoValue.value);
-const useVirtualJoystick = isTouchUsing && (deviceKind === 'smartphone' || deviceKind === 'tablet');
-//const useVirtualJoystick = true;
+//const useVirtualJoystick = isTouchUsing && (deviceKind === 'smartphone' || deviceKind === 'tablet');
+const useVirtualJoystick = true;
const wasdVec = { x: 0, y: 0 };
const pointerVec = { x: 0, y: 0 };
let isDashing = false;
const joyStickRadiusPx = 100;
-const joyStickLeftEl = useTemplateRef('joyStickLeftEl');
-const joyStickRightEl = useTemplateRef('joyStickRightEl');
-const joyStickLeftVec = ref({ x: 0, y: 0 });
-const joyStickRightVec = ref({ x: 0, y: 0 });
-const joyStickLeftStartPos = ref<{ x: number; y: number } | null>(null);
-const joyStickRightStartPos = ref<{ x: number; y: number } | null>(null);
+const joyStickEl = useTemplateRef('joyStickEl');
+const joyStickVec = ref({ x: 0, y: 0 });
+const joyStickStartPos = ref<{ x: number; y: number } | null>(null);
const data = localStorage.getItem('roomData') != null ? JSON.parse(localStorage.getItem('roomData')!) : {
heya: {
@@ -322,30 +313,18 @@ onMounted(async () => {
// }
//});
- if (joyStickLeftEl.value != null && joyStickRightEl.value != null) {
- const joyStickLeft = new Joystick(joyStickLeftEl.value!, { radiusPx: joyStickRadiusPx });
- joyStickLeft.on('start', (vector) => {
- joyStickLeftStartPos.value = vector;
+ if (joyStickEl.value != null) {
+ const joyStick = new Joystick(joyStickEl.value!, { radiusPx: joyStickRadiusPx });
+ joyStick.on('start', (vector) => {
+ joyStickStartPos.value = vector;
});
- joyStickLeft.on('end', () => {
- joyStickLeftStartPos.value = null;
+ joyStick.on('end', () => {
+ joyStickStartPos.value = null;
});
- joyStickLeft.on('updateVector', (vector) => {
- joyStickLeftVec.value = vector;
+ joyStick.on('updateVector', (vector) => {
+ joyStickVec.value = vector;
controller.setCameraJoystickMoveVector(vector);
});
-
- const joyStickRight = new Joystick(joyStickRightEl.value!, { radiusPx: joyStickRadiusPx });
- joyStickRight.on('start', (vector) => {
- joyStickRightStartPos.value = vector;
- });
- joyStickRight.on('end', () => {
- joyStickRightStartPos.value = null;
- });
- joyStickRight.on('updateVector', (vector) => {
- joyStickRightVec.value = vector;
- controller.setCameraJoystickRotateVector(vector);
- });
}
canvas.value!.addEventListener('keydown', (ev) => {
@@ -700,20 +679,15 @@ definePage(() => ({
}
}
-.joySticks {
- display: flex;
- width: 100%;
-}
-
-.joyStickLeft, .joyStickRight {
+.joyStick {
position: relative;
- flex: 1;
+ width: 50%;
height: 100px;
box-sizing: border-box;
padding: 8px;
}
-.joyStickLeft::before, .joyStickRight::before {
+.joyStick::before {
content: '';
display: block;
width: 100%;
diff --git a/packages/frontend/src/world/room/controller.ts b/packages/frontend/src/world/room/controller.ts
index 47708d78f9..3bb90124c9 100644
--- a/packages/frontend/src/world/room/controller.ts
+++ b/packages/frontend/src/world/room/controller.ts
@@ -185,6 +185,7 @@ export class RoomController {
private onCanvasPointerdown(ev: PointerEvent) {
this.pointerDownPosition = { x: ev.offsetX, y: ev.offsetY };
+ this.canvas!.setPointerCapture(ev.pointerId);
}
private onCanvasPointerup(ev: PointerEvent) {
@@ -201,6 +202,7 @@ export class RoomController {
}
}
this.pointerDownPosition = null;
+ this.canvas!.releasePointerCapture(ev.pointerId);
}
public async reset(roomState?: RoomState | null, options?: RoomControllerOptions | null, canvas?: HTMLCanvasElement | null) {
@@ -256,14 +258,6 @@ export class RoomController {
}
}
- public setCameraJoystickRotateVector(vec: { x: number; y: number }) {
- if (this.worker != null) {
- this.worker.postMessage({ type: 'call', fn: 'cameraJoystickRotate', args: [vec] });
- } else if (this.engine != null) {
- this.engine.cameraJoystickRotate(vec);
- }
- }
-
public enterEditMode() {
if (this.worker != null) {
this.worker.postMessage({ type: 'call', fn: 'enterEditMode' });
diff --git a/packages/frontend/src/world/room/engine.ts b/packages/frontend/src/world/room/engine.ts
index f5b89e5ffa..e06c591dd0 100644
--- a/packages/frontend/src/world/room/engine.ts
+++ b/packages/frontend/src/world/room/engine.ts
@@ -14,7 +14,7 @@
import * as BABYLON from '@babylonjs/core';
import { registerBuiltInLoaders } from '@babylonjs/loaders/dynamic';
import { EventEmitter } from 'eventemitter3';
-import { TIME_MAP, scaleMorph, camelToKebab, cm, WORLD_SCALE, getMeshesBoundingBox, Timer, getYRotationDirection, FreeCameraVirtualJoystickInput, FreeCameraManualInput } from '../utility.js';
+import { TIME_MAP, scaleMorph, camelToKebab, cm, WORLD_SCALE, getMeshesBoundingBox, Timer, getYRotationDirection, FreeCameraManualInput } from '../utility.js';
import { getObjectDef } from './object-defs.js';
import { findMaterial, ModelManager, SYSTEM_HEYA_MESH_NAMES, SYSTEM_MESH_NAMES } from './utility.js';
import { SimpleHeyaManager } from './heya.js';
@@ -301,9 +301,9 @@ export class RoomEngine extends EventEmitter {
this.camera.inputs.clear();
if (options.useVirtualJoystick) {
- this.camera.inputs.add(new FreeCameraVirtualJoystickInput({
+ this.camera.inputs.add(new FreeCameraManualInput({
moveSensitivity: 0.015 * WORLD_SCALE,
- rotationSensitivity: 0.01,
+ rotationSensitivity: 0.0005,
}));
this.camera.inertia = 0.75;
} else {
@@ -612,11 +612,7 @@ export class RoomEngine extends EventEmitter {
}
public cameraJoystickMove(vector: { x: number; y: number; }) {
- (this.camera.inputs.attached.joystick as FreeCameraVirtualJoystickInput).setJoystickMoveVector(vector);
- }
-
- public cameraJoystickRotate(vector: { x: number; y: number; }) {
- (this.camera.inputs.attached.joystick as FreeCameraVirtualJoystickInput).setJoystickRotationVector(vector);
+ (this.camera.inputs.attached.manual as FreeCameraManualInput).setMoveVector(vector);
}
public selectObject(objectId: string | null) {
diff --git a/packages/frontend/src/world/utility.ts b/packages/frontend/src/world/utility.ts
index 2990168f0f..45b414f531 100644
--- a/packages/frontend/src/world/utility.ts
+++ b/packages/frontend/src/world/utility.ts
@@ -618,55 +618,6 @@ export function getRgb(hex: string | number): [number, number, number] | null {
return m.map(x => parseInt(x, 16) / 255) as [number, number, number];
}
-export class FreeCameraVirtualJoystickInput implements BABYLON.ICameraInput {
- public camera: BABYLON.FreeCamera;
- private moveSensitivity: number;
- private rotationSensitivity: number;
- private moveVector = BABYLON.Vector3.Zero();
- private rotationVecX = 0;
- private rotationVecY = 0;
-
- constructor(options: {
- moveSensitivity?: number;
- rotationSensitivity?: number;
- }) {
- this.moveSensitivity = options.moveSensitivity ?? 0.01;
- this.rotationSensitivity = options.rotationSensitivity ?? 0.01;
- }
-
- getClassName = () => this.constructor.name;
-
- getSimpleName = () => 'joystick';
-
- attachControl(noPreventDefault) {
- }
-
- detachControl() {
- }
-
- public setJoystickMoveVector(vec: { x: number; y: number }) {
- this.moveVector = new BABYLON.Vector3(vec.x, 0, -vec.y).scale(this.moveSensitivity);
- }
-
- public setJoystickRotationVector(vec: { x: number; y: number }) {
- let directionAdjust = 1;
- if (this.camera.getScene().useRightHandedSystem) directionAdjust *= -1;
- if (this.camera.parent && this.camera.parent._getWorldMatrixDeterminant() < 0) directionAdjust *= -1;
-
- this.rotationVecX = vec.y * this.rotationSensitivity * directionAdjust;
- this.rotationVecY = vec.x * this.rotationSensitivity * directionAdjust;
- }
-
- checkInputs() {
- this.camera.cameraRotation.y += this.rotationVecY;
- this.camera.cameraRotation.x += this.rotationVecX;
-
- this.camera.cameraDirection.addInPlace(
- BABYLON.Vector3.TransformCoordinates(this.moveVector, BABYLON.Matrix.RotationY(this.camera.rotation.y)),
- );
- }
-}
-
export class FreeCameraManualInput implements BABYLON.ICameraInput {
public camera: BABYLON.FreeCamera;
private moveSensitivity: number;