@mml-io/3d-web-client-core 0.0.0-experimental-42d909b-20240717 → 0.0.0-experimental-81deb84-20240724
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/camera/CameraManager.d.ts +16 -18
- package/build/character/LocalController.d.ts +1 -9
- package/build/index.js +347 -342
- package/build/index.js.map +3 -3
- package/build/input/KeyInputManager.d.ts +11 -8
- package/build/input/VirtualJoystick.d.ts +28 -36
- package/build/tweakpane/blades/cameraFolder.d.ts +0 -6
- package/package.json +3 -3
package/build/index.js
CHANGED
@@ -82,159 +82,6 @@ var EventHandlerCollection = class _EventHandlerCollection {
|
|
82
82
|
}
|
83
83
|
};
|
84
84
|
|
85
|
-
// src/input/VirtualJoystick.ts
|
86
|
-
var VirtualJoystick = class _VirtualJoystick {
|
87
|
-
constructor(holderElement, attrs) {
|
88
|
-
this.holderElement = holderElement;
|
89
|
-
this.left = false;
|
90
|
-
this.right = false;
|
91
|
-
this.up = false;
|
92
|
-
this.down = false;
|
93
|
-
this.hasDirection = false;
|
94
|
-
this.clearFlags = () => {
|
95
|
-
this.left = false;
|
96
|
-
this.right = false;
|
97
|
-
this.up = false;
|
98
|
-
this.down = false;
|
99
|
-
this.hasDirection = false;
|
100
|
-
this.control.style.left = `${this.width / 2 - this.inner_radius}px`;
|
101
|
-
this.control.style.top = `${this.height / 2 - this.inner_radius}px`;
|
102
|
-
};
|
103
|
-
this.radius = attrs.radius || 50;
|
104
|
-
this.inner_radius = attrs.inner_radius || this.radius / 2;
|
105
|
-
this.anchor = attrs.anchor || "left";
|
106
|
-
this.x = attrs.x || 0;
|
107
|
-
this.y = attrs.y || 0;
|
108
|
-
this.width = attrs.width || this.radius * 2 + this.inner_radius * 2;
|
109
|
-
this.height = attrs.height || this.radius * 2 + this.inner_radius * 2;
|
110
|
-
this.mouse_support = this.checkTouch() || attrs.mouse_support === true;
|
111
|
-
this.div = document.createElement("div");
|
112
|
-
const divStyle = this.div.style;
|
113
|
-
divStyle.display = this.checkTouch() || this.mouse_support ? "visible" : "none";
|
114
|
-
divStyle.position = "fixed";
|
115
|
-
if (this.anchor === "left") {
|
116
|
-
divStyle.left = `${this.x}px`;
|
117
|
-
} else {
|
118
|
-
divStyle.right = `${this.x}px`;
|
119
|
-
}
|
120
|
-
divStyle.bottom = `${this.y}px`;
|
121
|
-
divStyle.width = `${this.width}px`;
|
122
|
-
divStyle.height = `${this.height}px`;
|
123
|
-
divStyle.zIndex = "10000";
|
124
|
-
divStyle.overflow = "hidden";
|
125
|
-
this.holderElement.appendChild(this.div);
|
126
|
-
this.setupBaseAndControl();
|
127
|
-
this.bindEvents();
|
128
|
-
}
|
129
|
-
static checkForTouch() {
|
130
|
-
try {
|
131
|
-
document.createEvent("TouchEvent");
|
132
|
-
return true;
|
133
|
-
} catch (e) {
|
134
|
-
return false;
|
135
|
-
}
|
136
|
-
}
|
137
|
-
checkTouch() {
|
138
|
-
return _VirtualJoystick.checkForTouch();
|
139
|
-
}
|
140
|
-
setupBaseAndControl() {
|
141
|
-
this.base = document.createElement("span");
|
142
|
-
let divStyle = this.base.style;
|
143
|
-
divStyle.width = `${this.radius * 2}px`;
|
144
|
-
divStyle.height = `${this.radius * 2}px`;
|
145
|
-
divStyle.position = "absolute";
|
146
|
-
divStyle.left = `${this.width / 2 - this.radius}px`;
|
147
|
-
divStyle.bottom = `${this.height / 2 - this.radius}px`;
|
148
|
-
divStyle.borderRadius = "50%";
|
149
|
-
divStyle.borderColor = "rgba(200,200,200,0.5)";
|
150
|
-
divStyle.borderWidth = "2px";
|
151
|
-
divStyle.borderStyle = "solid";
|
152
|
-
this.div.appendChild(this.base);
|
153
|
-
this.control = document.createElement("span");
|
154
|
-
divStyle = this.control.style;
|
155
|
-
divStyle.width = `${this.inner_radius * 2}px`;
|
156
|
-
divStyle.height = `${this.inner_radius * 2}px`;
|
157
|
-
divStyle.position = "absolute";
|
158
|
-
divStyle.left = `${this.width / 2 - this.inner_radius}px`;
|
159
|
-
divStyle.bottom = `${this.height / 2 - this.inner_radius}px`;
|
160
|
-
divStyle.borderRadius = "50%";
|
161
|
-
divStyle.backgroundColor = "rgba(200,200,200,0.3)";
|
162
|
-
divStyle.borderWidth = "1px";
|
163
|
-
divStyle.borderColor = "rgba(200,200,200,0.8)";
|
164
|
-
divStyle.borderStyle = "solid";
|
165
|
-
this.div.appendChild(this.control);
|
166
|
-
}
|
167
|
-
bindEvents() {
|
168
|
-
this.div.addEventListener("touchstart", this.handleTouchStart.bind(this), false);
|
169
|
-
this.div.addEventListener("touchmove", this.handleTouchMove.bind(this), false);
|
170
|
-
this.div.addEventListener("touchend", this.clearFlags.bind(this), false);
|
171
|
-
if (this.mouse_support) {
|
172
|
-
this.div.addEventListener("mousedown", this.handleMouseDown.bind(this));
|
173
|
-
this.div.addEventListener("mousemove", this.handleMouseMove.bind(this));
|
174
|
-
this.div.addEventListener("mouseup", this.handleMouseUp.bind(this));
|
175
|
-
}
|
176
|
-
}
|
177
|
-
handleTouchStart(evt) {
|
178
|
-
evt.preventDefault();
|
179
|
-
evt.stopPropagation();
|
180
|
-
if (evt.touches) {
|
181
|
-
const touch = evt.touches[0];
|
182
|
-
this.updateControlAndDirection(touch);
|
183
|
-
}
|
184
|
-
}
|
185
|
-
handleTouchMove(evt) {
|
186
|
-
evt.preventDefault();
|
187
|
-
evt.stopPropagation();
|
188
|
-
if (evt.touches.length > 0) {
|
189
|
-
const touch = evt.touches[0];
|
190
|
-
this.updateControlAndDirection(touch);
|
191
|
-
}
|
192
|
-
}
|
193
|
-
handleMouseDown(evt) {
|
194
|
-
evt.preventDefault();
|
195
|
-
evt.stopPropagation();
|
196
|
-
this.updateControlAndDirection(evt);
|
197
|
-
}
|
198
|
-
handleMouseMove(evt) {
|
199
|
-
if (evt.buttons === 1) {
|
200
|
-
evt.preventDefault();
|
201
|
-
evt.stopPropagation();
|
202
|
-
this.updateControlAndDirection(evt);
|
203
|
-
}
|
204
|
-
}
|
205
|
-
handleMouseUp(evt) {
|
206
|
-
this.clearFlags();
|
207
|
-
}
|
208
|
-
updateControlAndDirection(input) {
|
209
|
-
const rect = this.div.getBoundingClientRect();
|
210
|
-
const dx = input.clientX - (rect.left + this.div.offsetWidth / 2);
|
211
|
-
const dy = input.clientY - (rect.top + this.div.offsetHeight / 2);
|
212
|
-
const distance = Math.min(Math.sqrt(dx * dx + dy * dy), this.radius);
|
213
|
-
const angle = Math.atan2(dy, dx);
|
214
|
-
const constrainedX = distance * Math.cos(angle);
|
215
|
-
const constrainedY = distance * Math.sin(angle);
|
216
|
-
this.control.style.left = `${constrainedX + this.width / 2 - this.inner_radius}px`;
|
217
|
-
this.control.style.top = `${constrainedY + this.height / 2 - this.inner_radius}px`;
|
218
|
-
this.up = this.isUp(dx, dy);
|
219
|
-
this.down = this.isDown(dx, dy);
|
220
|
-
this.left = this.isLeft(dx, dy);
|
221
|
-
this.right = this.isRight(dx, dy);
|
222
|
-
this.hasDirection = this.up || this.down || this.left || this.right;
|
223
|
-
}
|
224
|
-
isUp(dx, dy) {
|
225
|
-
return dy < 0 && Math.abs(dx) <= 2 * Math.abs(dy);
|
226
|
-
}
|
227
|
-
isDown(dx, dy) {
|
228
|
-
return dy > 0 && Math.abs(dx) <= 2 * Math.abs(dy);
|
229
|
-
}
|
230
|
-
isLeft(dx, dy) {
|
231
|
-
return dx < 0 && Math.abs(dy) <= 2 * Math.abs(dx);
|
232
|
-
}
|
233
|
-
isRight(dx, dy) {
|
234
|
-
return dx > 0 && Math.abs(dy) <= 2 * Math.abs(dx);
|
235
|
-
}
|
236
|
-
};
|
237
|
-
|
238
85
|
// src/tweakpane/blades/cameraFolder.ts
|
239
86
|
var camValues = {
|
240
87
|
initialDistance: 3.3,
|
@@ -244,10 +91,9 @@ var camValues = {
|
|
244
91
|
maxFOV: 70,
|
245
92
|
minFOV: 60,
|
246
93
|
invertFOVMapping: false,
|
247
|
-
damping: 0.
|
248
|
-
dampingScale: 5e-3,
|
94
|
+
damping: 0.25,
|
249
95
|
zoomScale: 0.088,
|
250
|
-
zoomDamping: 0.
|
96
|
+
zoomDamping: 0.4
|
251
97
|
};
|
252
98
|
var camOptions = {
|
253
99
|
initialDistance: { min: 1, max: 5, step: 0.1 },
|
@@ -256,8 +102,7 @@ var camOptions = {
|
|
256
102
|
initialFOV: { min: 60, max: 85, step: 1 },
|
257
103
|
maxFOV: { min: 50, max: 100, step: 1 },
|
258
104
|
minFOV: { min: 50, max: 100, step: 1 },
|
259
|
-
damping: { min: 0.01, max:
|
260
|
-
dampingScale: { min: 1e-3, max: 0.02, step: 1e-3 },
|
105
|
+
damping: { min: 0.01, max: 1, step: 1e-3 },
|
261
106
|
zoomScale: { min: 5e-3, max: 0.3, step: 1e-3 },
|
262
107
|
zoomDamping: { min: 0, max: 2, step: 0.01 }
|
263
108
|
};
|
@@ -277,7 +122,6 @@ var CameraFolder = class {
|
|
277
122
|
this.folder.addBinding(camValues, "maxFOV", camOptions.maxFOV);
|
278
123
|
this.folder.addBinding({ invertFOVMapping: camValues.invertFOVMapping }, "invertFOVMapping");
|
279
124
|
this.folder.addBinding(camValues, "damping", camOptions.damping);
|
280
|
-
this.folder.addBinding(camValues, "dampingScale", camOptions.dampingScale);
|
281
125
|
this.folder.addBinding(camValues, "zoomScale", camOptions.zoomScale);
|
282
126
|
this.folder.addBinding(camValues, "zoomDamping", camOptions.zoomDamping);
|
283
127
|
}
|
@@ -326,20 +170,16 @@ var CameraFolder = class {
|
|
326
170
|
cameraManager.recomputeFoV();
|
327
171
|
break;
|
328
172
|
}
|
329
|
-
case "invertFOVMapping":
|
173
|
+
case "invertFOVMapping": {
|
330
174
|
const boolValue = e.value;
|
331
175
|
cameraManager.invertFOVMapping = boolValue;
|
332
176
|
break;
|
177
|
+
}
|
333
178
|
case "damping": {
|
334
179
|
const value = e.value;
|
335
180
|
cameraManager.damping = value;
|
336
181
|
break;
|
337
182
|
}
|
338
|
-
case "dampingScale": {
|
339
|
-
const value = e.value;
|
340
|
-
cameraManager.dampingScale = value;
|
341
|
-
break;
|
342
|
-
}
|
343
183
|
case "zoomScale": {
|
344
184
|
const value = e.value;
|
345
185
|
cameraManager.zoomScale = value;
|
@@ -371,124 +211,114 @@ function getTweakpaneActive() {
|
|
371
211
|
}
|
372
212
|
|
373
213
|
// src/camera/CameraManager.ts
|
214
|
+
var cameraPanSensitivity = 20;
|
215
|
+
var scrollZoomSensitivity = 0.1;
|
216
|
+
var pinchZoomSensitivity = 0.025;
|
374
217
|
var CameraManager = class {
|
375
218
|
constructor(targetElement, collisionsManager, initialPhi = Math.PI / 2, initialTheta = -Math.PI / 2) {
|
219
|
+
this.targetElement = targetElement;
|
376
220
|
this.collisionsManager = collisionsManager;
|
377
221
|
this.initialDistance = camValues.initialDistance;
|
378
222
|
this.minDistance = camValues.minDistance;
|
379
223
|
this.maxDistance = camValues.maxDistance;
|
380
|
-
this.initialFOV = camValues.initialFOV;
|
381
|
-
this.maxFOV = camValues.maxFOV;
|
382
|
-
this.minFOV = camValues.minFOV;
|
383
224
|
this.damping = camValues.damping;
|
384
|
-
this.dampingScale = 0.01;
|
385
225
|
this.zoomScale = camValues.zoomScale;
|
386
226
|
this.zoomDamping = camValues.zoomDamping;
|
227
|
+
this.initialFOV = camValues.initialFOV;
|
228
|
+
this.maxFOV = camValues.maxFOV;
|
229
|
+
this.minFOV = camValues.minFOV;
|
387
230
|
this.invertFOVMapping = camValues.invertFOVMapping;
|
388
231
|
this.fov = this.initialFOV;
|
389
232
|
this.targetFOV = this.initialFOV;
|
390
233
|
this.minPolarAngle = Math.PI * 0.25;
|
391
234
|
this.maxPolarAngle = Math.PI * 0.95;
|
392
|
-
this.targetDistance = this.initialDistance;
|
393
235
|
this.distance = this.initialDistance;
|
236
|
+
this.targetDistance = this.initialDistance;
|
394
237
|
this.desiredDistance = this.initialDistance;
|
395
|
-
this.phi = Math.PI / 2;
|
396
|
-
this.theta = Math.PI / 2;
|
397
|
-
this.dragging = false;
|
398
238
|
this.target = new Vector32(0, 1.55, 0);
|
399
239
|
this.hadTarget = false;
|
400
|
-
this.isLerping = false;
|
401
240
|
this.finalTarget = new Vector32();
|
241
|
+
this.isLerping = false;
|
402
242
|
this.lerpTarget = new Vector32();
|
403
243
|
this.lerpFactor = 0;
|
404
244
|
this.lerpDuration = 2.1;
|
405
|
-
this.
|
406
|
-
this.
|
407
|
-
this.lastTouchY = 0;
|
245
|
+
this.activePointers = /* @__PURE__ */ new Map();
|
246
|
+
this.targetElement.style.touchAction = "pinch-zoom";
|
408
247
|
this.phi = initialPhi;
|
409
|
-
this.targetPhi =
|
248
|
+
this.targetPhi = this.phi;
|
410
249
|
this.theta = initialTheta;
|
411
|
-
this.targetTheta =
|
250
|
+
this.targetTheta = this.theta;
|
412
251
|
this.camera = new PerspectiveCamera(this.fov, window.innerWidth / window.innerHeight, 0.1, 400);
|
413
252
|
this.camera.position.set(0, 1.4, -this.initialDistance);
|
414
253
|
this.rayCaster = new Raycaster();
|
415
|
-
this.hasTouchControl = VirtualJoystick.checkForTouch();
|
416
254
|
this.eventHandlerCollection = EventHandlerCollection.create([
|
417
|
-
[targetElement, "
|
418
|
-
[
|
419
|
-
[document, "
|
255
|
+
[targetElement, "pointerdown", this.onPointerDown.bind(this)],
|
256
|
+
[targetElement, "gesturestart", this.preventDefaultAndStopPropagation.bind(this)],
|
257
|
+
[document, "pointerup", this.onPointerUp.bind(this)],
|
258
|
+
[document, "pointercancel", this.onPointerUp.bind(this)],
|
259
|
+
[document, "pointermove", this.onPointerMove.bind(this)],
|
420
260
|
[targetElement, "wheel", this.onMouseWheel.bind(this)],
|
421
261
|
[targetElement, "contextmenu", this.onContextMenu.bind(this)]
|
422
262
|
]);
|
423
|
-
if (this.hasTouchControl) {
|
424
|
-
this.eventHandlerCollection.add(targetElement, "touchstart", this.onTouchStart.bind(this), {
|
425
|
-
passive: false
|
426
|
-
});
|
427
|
-
this.eventHandlerCollection.add(document, "touchmove", this.onTouchMove.bind(this), {
|
428
|
-
passive: false
|
429
|
-
});
|
430
|
-
this.eventHandlerCollection.add(document, "touchend", this.onTouchEnd.bind(this), {
|
431
|
-
passive: false
|
432
|
-
});
|
433
|
-
}
|
434
|
-
}
|
435
|
-
setupTweakPane(tweakPane) {
|
436
|
-
tweakPane.setupCamPane(this);
|
437
263
|
}
|
438
|
-
|
439
|
-
Array.from(evt.touches).forEach((touch) => {
|
440
|
-
this.dragging = true;
|
441
|
-
this.lastTouchX = touch.clientX;
|
442
|
-
this.lastTouchY = touch.clientY;
|
443
|
-
});
|
444
|
-
}
|
445
|
-
onTouchMove(evt) {
|
446
|
-
if (!this.dragging || getTweakpaneActive()) {
|
447
|
-
return;
|
448
|
-
}
|
264
|
+
preventDefaultAndStopPropagation(evt) {
|
449
265
|
evt.preventDefault();
|
450
|
-
|
451
|
-
if (touch) {
|
452
|
-
const dx = touch.clientX - this.lastTouchX;
|
453
|
-
const dy = touch.clientY - this.lastTouchY;
|
454
|
-
this.lastTouchX = touch.clientX;
|
455
|
-
this.lastTouchY = touch.clientY;
|
456
|
-
if (this.targetTheta !== null && this.targetPhi !== null) {
|
457
|
-
this.targetTheta += dx * this.dampingScale;
|
458
|
-
this.targetPhi -= dy * this.dampingScale;
|
459
|
-
this.targetPhi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this.targetPhi));
|
460
|
-
}
|
461
|
-
}
|
266
|
+
evt.stopPropagation();
|
462
267
|
}
|
463
|
-
|
464
|
-
|
465
|
-
const touchEnded = Array.from(evt.changedTouches).some((t) => true);
|
466
|
-
if (touchEnded) {
|
467
|
-
this.dragging = false;
|
468
|
-
}
|
469
|
-
}
|
268
|
+
setupTweakPane(tweakPane) {
|
269
|
+
tweakPane.setupCamPane(this);
|
470
270
|
}
|
471
|
-
|
271
|
+
onPointerDown(event) {
|
472
272
|
if (event.button === 0 || event.button === 2) {
|
473
|
-
|
273
|
+
const pointerInfo = { x: event.clientX, y: event.clientY };
|
274
|
+
this.activePointers.set(event.pointerId, pointerInfo);
|
474
275
|
document.body.style.cursor = "none";
|
475
276
|
}
|
476
277
|
}
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
278
|
+
onPointerUp(event) {
|
279
|
+
const existingPointer = this.activePointers.get(event.pointerId);
|
280
|
+
if (existingPointer) {
|
281
|
+
this.activePointers.delete(event.pointerId);
|
282
|
+
if (this.activePointers.size === 0) {
|
283
|
+
document.body.style.cursor = "default";
|
284
|
+
}
|
481
285
|
}
|
482
286
|
}
|
483
|
-
|
287
|
+
getAveragePointerPositionAndSpread() {
|
288
|
+
const existingSum = { x: 0, y: 0 };
|
289
|
+
this.activePointers.forEach((p) => {
|
290
|
+
existingSum.x += p.x;
|
291
|
+
existingSum.y += p.y;
|
292
|
+
});
|
293
|
+
const aX = existingSum.x / this.activePointers.size;
|
294
|
+
const aY = existingSum.y / this.activePointers.size;
|
295
|
+
let sumOfDistances = 0;
|
296
|
+
this.activePointers.forEach((p) => {
|
297
|
+
const distance = Math.sqrt((p.x - aX) ** 2 + (p.y - aY) ** 2);
|
298
|
+
sumOfDistances += distance;
|
299
|
+
});
|
300
|
+
return { pos: { x: aX, y: aY }, spread: sumOfDistances / this.activePointers.size };
|
301
|
+
}
|
302
|
+
onPointerMove(event) {
|
484
303
|
if (getTweakpaneActive()) {
|
485
304
|
return;
|
486
305
|
}
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
306
|
+
const existingPointer = this.activePointers.get(event.pointerId);
|
307
|
+
if (existingPointer) {
|
308
|
+
const previous = this.getAveragePointerPositionAndSpread();
|
309
|
+
existingPointer.x = event.clientX;
|
310
|
+
existingPointer.y = event.clientY;
|
311
|
+
const latest = this.getAveragePointerPositionAndSpread();
|
312
|
+
const sX = latest.pos.x - previous.pos.x;
|
313
|
+
const sY = latest.pos.y - previous.pos.y;
|
314
|
+
const dx = sX / this.targetElement.clientWidth * cameraPanSensitivity;
|
315
|
+
const dy = sY / this.targetElement.clientHeight * cameraPanSensitivity;
|
316
|
+
if (this.activePointers.size > 1) {
|
317
|
+
const zoomDelta = latest.spread - previous.spread;
|
318
|
+
this.zoom(-zoomDelta * pinchZoomSensitivity);
|
319
|
+
}
|
320
|
+
this.targetTheta += dx;
|
321
|
+
this.targetPhi -= dy;
|
492
322
|
this.targetPhi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this.targetPhi));
|
493
323
|
event.preventDefault();
|
494
324
|
}
|
@@ -497,14 +327,17 @@ var CameraManager = class {
|
|
497
327
|
if (getTweakpaneActive()) {
|
498
328
|
return;
|
499
329
|
}
|
500
|
-
|
501
|
-
this.
|
330
|
+
event.preventDefault();
|
331
|
+
const scrollAmount = event.deltaY * this.zoomScale * scrollZoomSensitivity;
|
332
|
+
this.zoom(scrollAmount);
|
333
|
+
}
|
334
|
+
zoom(delta) {
|
335
|
+
this.targetDistance += delta;
|
502
336
|
this.targetDistance = Math.max(
|
503
337
|
this.minDistance,
|
504
338
|
Math.min(this.maxDistance, this.targetDistance)
|
505
339
|
);
|
506
340
|
this.desiredDistance = this.targetDistance;
|
507
|
-
event.preventDefault();
|
508
341
|
}
|
509
342
|
onContextMenu(event) {
|
510
343
|
event.preventDefault();
|
@@ -533,12 +366,12 @@ var CameraManager = class {
|
|
533
366
|
const dy = this.camera.position.y - this.target.y;
|
534
367
|
const dz = this.camera.position.z - this.target.z;
|
535
368
|
this.targetDistance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
536
|
-
this.targetTheta = Math.atan2(dz, dx);
|
537
|
-
this.targetPhi = Math.acos(dy / this.targetDistance);
|
538
|
-
this.phi = this.targetPhi;
|
539
|
-
this.theta = this.targetTheta;
|
540
369
|
this.distance = this.targetDistance;
|
541
370
|
this.desiredDistance = this.targetDistance;
|
371
|
+
this.theta = Math.atan2(dz, dx);
|
372
|
+
this.targetTheta = this.theta;
|
373
|
+
this.phi = Math.acos(dy / this.targetDistance);
|
374
|
+
this.targetPhi = this.phi;
|
542
375
|
this.recomputeFoV(true);
|
543
376
|
}
|
544
377
|
adjustCameraPosition() {
|
@@ -546,15 +379,15 @@ var CameraManager = class {
|
|
546
379
|
const offset = new Vector32(0, 0, offsetDistance);
|
547
380
|
offset.applyEuler(this.camera.rotation);
|
548
381
|
const rayOrigin = this.camera.position.clone().add(offset);
|
549
|
-
const rayDirection = this.target.clone()
|
550
|
-
this.rayCaster.set(
|
382
|
+
const rayDirection = rayOrigin.sub(this.target.clone()).normalize();
|
383
|
+
this.rayCaster.set(this.target.clone(), rayDirection);
|
551
384
|
const firstRaycastHit = this.collisionsManager.raycastFirst(this.rayCaster.ray);
|
552
|
-
|
553
|
-
|
554
|
-
this.targetDistance =
|
555
|
-
this.distance =
|
385
|
+
if (firstRaycastHit !== null && firstRaycastHit[0] <= this.desiredDistance) {
|
386
|
+
const distanceToCollision = firstRaycastHit[0] - 0.1;
|
387
|
+
this.targetDistance = distanceToCollision;
|
388
|
+
this.distance = distanceToCollision;
|
556
389
|
} else {
|
557
|
-
this.targetDistance
|
390
|
+
this.targetDistance = this.desiredDistance;
|
558
391
|
}
|
559
392
|
}
|
560
393
|
dispose() {
|
@@ -587,24 +420,25 @@ var CameraManager = class {
|
|
587
420
|
} else {
|
588
421
|
this.adjustCameraPosition();
|
589
422
|
}
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
this.isLerping = false;
|
605
|
-
}
|
423
|
+
this.distance += (this.targetDistance - this.distance) * this.zoomDamping;
|
424
|
+
this.theta += (this.targetTheta - this.theta) * this.damping;
|
425
|
+
this.phi += (this.targetPhi - this.phi) * this.damping;
|
426
|
+
const x = this.target.x + this.distance * Math.sin(this.phi) * Math.cos(this.theta);
|
427
|
+
const y = this.target.y + this.distance * Math.cos(this.phi);
|
428
|
+
const z = this.target.z + this.distance * Math.sin(this.phi) * Math.sin(this.theta);
|
429
|
+
this.recomputeFoV();
|
430
|
+
this.fov += (this.targetFOV - this.fov) * this.zoomDamping;
|
431
|
+
this.camera.fov = this.fov;
|
432
|
+
this.camera.updateProjectionMatrix();
|
433
|
+
this.camera.position.set(x, y, z);
|
434
|
+
this.camera.lookAt(this.target);
|
435
|
+
if (this.isLerping && this.lerpFactor >= 1) {
|
436
|
+
this.isLerping = false;
|
606
437
|
}
|
607
438
|
}
|
439
|
+
hasActiveInput() {
|
440
|
+
return this.activePointers.size > 0;
|
441
|
+
}
|
608
442
|
};
|
609
443
|
|
610
444
|
// src/character/Character.ts
|
@@ -1770,6 +1604,7 @@ var LocalController = class {
|
|
1770
1604
|
this.jumpPressed = false;
|
1771
1605
|
// Tracks if the jump button is pressed
|
1772
1606
|
this.jumpReleased = true;
|
1607
|
+
this.controlState = null;
|
1773
1608
|
this.networkState = {
|
1774
1609
|
id: this.config.id,
|
1775
1610
|
position: { x: 0, y: 0, z: 0 },
|
@@ -1777,35 +1612,22 @@ var LocalController = class {
|
|
1777
1612
|
state: 0 /* idle */
|
1778
1613
|
};
|
1779
1614
|
}
|
1780
|
-
updateControllerState() {
|
1781
|
-
var _a, _b, _c, _d, _e;
|
1782
|
-
this.forward = this.config.keyInputManager.forward || ((_a = this.config.virtualJoystick) == null ? void 0 : _a.up) || false;
|
1783
|
-
this.backward = this.config.keyInputManager.backward || ((_b = this.config.virtualJoystick) == null ? void 0 : _b.down) || false;
|
1784
|
-
this.left = this.config.keyInputManager.left || ((_c = this.config.virtualJoystick) == null ? void 0 : _c.left) || false;
|
1785
|
-
this.right = this.config.keyInputManager.right || ((_d = this.config.virtualJoystick) == null ? void 0 : _d.right) || false;
|
1786
|
-
this.run = this.config.keyInputManager.run;
|
1787
|
-
this.jump = this.config.keyInputManager.jump;
|
1788
|
-
this.anyDirection = this.config.keyInputManager.anyDirection || ((_e = this.config.virtualJoystick) == null ? void 0 : _e.hasDirection) || false;
|
1789
|
-
this.conflictingDirections = this.config.keyInputManager.conflictingDirection;
|
1790
|
-
if (!this.jump) {
|
1791
|
-
this.jumpReleased = true;
|
1792
|
-
}
|
1793
|
-
}
|
1794
1615
|
update() {
|
1795
|
-
|
1616
|
+
var _a, _b;
|
1617
|
+
this.controlState = this.config.keyInputManager.getOutput() || ((_a = this.config.virtualJoystick) == null ? void 0 : _a.getOutput()) || null;
|
1796
1618
|
this.rayCaster.set(this.config.character.position, this.vectorDown);
|
1797
1619
|
const firstRaycastHit = this.config.collisionsManager.raycastFirst(this.rayCaster.ray);
|
1798
1620
|
if (firstRaycastHit !== null) {
|
1799
1621
|
this.currentHeight = firstRaycastHit[0];
|
1800
1622
|
this.currentSurfaceAngle.copy(firstRaycastHit[1]);
|
1801
1623
|
}
|
1802
|
-
if (this.
|
1624
|
+
if (((_b = this.controlState) == null ? void 0 : _b.direction) !== null || !this.characterOnGround) {
|
1803
1625
|
const targetAnimation = this.getTargetAnimation();
|
1804
1626
|
this.config.character.updateAnimation(targetAnimation);
|
1805
1627
|
} else {
|
1806
1628
|
this.config.character.updateAnimation(0 /* idle */);
|
1807
1629
|
}
|
1808
|
-
if (this.
|
1630
|
+
if (this.controlState) {
|
1809
1631
|
this.updateRotation();
|
1810
1632
|
}
|
1811
1633
|
for (let i = 0; i < this.collisionDetectionSteps; i++) {
|
@@ -1830,30 +1652,17 @@ var LocalController = class {
|
|
1830
1652
|
}
|
1831
1653
|
return 4 /* air */;
|
1832
1654
|
}
|
1833
|
-
if (this.
|
1655
|
+
if (!this.controlState) {
|
1834
1656
|
return 0 /* idle */;
|
1835
1657
|
}
|
1836
|
-
|
1658
|
+
if (this.controlState.isSprinting) {
|
1659
|
+
return 2 /* running */;
|
1660
|
+
}
|
1661
|
+
return 1 /* walking */;
|
1837
1662
|
}
|
1838
1663
|
updateRotationOffset() {
|
1839
|
-
if (this.
|
1840
|
-
|
1841
|
-
if (this.forward) {
|
1842
|
-
this.rotationOffset = Math.PI;
|
1843
|
-
if (this.left)
|
1844
|
-
this.rotationOffset = Math.PI + Math.PI / 4;
|
1845
|
-
if (this.right)
|
1846
|
-
this.rotationOffset = Math.PI - Math.PI / 4;
|
1847
|
-
} else if (this.backward) {
|
1848
|
-
this.rotationOffset = Math.PI * 2;
|
1849
|
-
if (this.left)
|
1850
|
-
this.rotationOffset = -Math.PI * 2 - Math.PI / 4;
|
1851
|
-
if (this.right)
|
1852
|
-
this.rotationOffset = Math.PI * 2 + Math.PI / 4;
|
1853
|
-
} else if (this.left) {
|
1854
|
-
this.rotationOffset = Math.PI * -0.5;
|
1855
|
-
} else if (this.right) {
|
1856
|
-
this.rotationOffset = Math.PI * 0.5;
|
1664
|
+
if (this.controlState && this.controlState.direction !== null) {
|
1665
|
+
this.rotationOffset = this.controlState.direction;
|
1857
1666
|
}
|
1858
1667
|
}
|
1859
1668
|
updateAzimuthalAngle() {
|
@@ -1888,17 +1697,19 @@ var LocalController = class {
|
|
1888
1697
|
this.config.character.quaternion.rotateTowards(rotationQuaternion, frameRotation);
|
1889
1698
|
}
|
1890
1699
|
processJump(currentAcceleration, deltaTime) {
|
1700
|
+
var _a;
|
1701
|
+
const jump = (_a = this.controlState) == null ? void 0 : _a.jump;
|
1891
1702
|
if (this.characterOnGround) {
|
1892
1703
|
this.coyoteJumped = false;
|
1893
1704
|
this.canDoubleJump = false;
|
1894
1705
|
this.doubleJumpUsed = false;
|
1895
1706
|
this.jumpCounter = 0;
|
1896
|
-
if (!
|
1707
|
+
if (!jump) {
|
1897
1708
|
this.canDoubleJump = !this.doubleJumpUsed && this.jumpReleased && this.jumpCounter === 1;
|
1898
1709
|
this.canJump = true;
|
1899
1710
|
this.jumpReleased = true;
|
1900
1711
|
}
|
1901
|
-
if (
|
1712
|
+
if (jump && this.canJump && this.jumpReleased) {
|
1902
1713
|
currentAcceleration.y += this.jumpForce / deltaTime;
|
1903
1714
|
this.canJump = false;
|
1904
1715
|
this.jumpReleased = false;
|
@@ -1909,13 +1720,13 @@ var LocalController = class {
|
|
1909
1720
|
}
|
1910
1721
|
}
|
1911
1722
|
} else {
|
1912
|
-
if (
|
1723
|
+
if (jump && !this.coyoteJumped && this.coyoteTime) {
|
1913
1724
|
this.coyoteJumped = true;
|
1914
1725
|
currentAcceleration.y += this.jumpForce / deltaTime;
|
1915
1726
|
this.canJump = false;
|
1916
1727
|
this.jumpReleased = false;
|
1917
1728
|
this.jumpCounter++;
|
1918
|
-
} else if (
|
1729
|
+
} else if (jump && this.canDoubleJump) {
|
1919
1730
|
currentAcceleration.y += this.doubleJumpForce / deltaTime;
|
1920
1731
|
this.doubleJumpUsed = true;
|
1921
1732
|
this.jumpReleased = false;
|
@@ -1925,7 +1736,7 @@ var LocalController = class {
|
|
1925
1736
|
this.canJump = false;
|
1926
1737
|
}
|
1927
1738
|
}
|
1928
|
-
if (!
|
1739
|
+
if (!jump) {
|
1929
1740
|
this.jumpReleased = true;
|
1930
1741
|
if (!this.characterOnGround) {
|
1931
1742
|
currentAcceleration.y += this.gravity;
|
@@ -1933,31 +1744,19 @@ var LocalController = class {
|
|
1933
1744
|
}
|
1934
1745
|
}
|
1935
1746
|
applyControls(deltaTime) {
|
1747
|
+
var _a;
|
1936
1748
|
const resistance = this.characterOnGround ? this.groundResistance : this.airResistance;
|
1937
1749
|
const speedFactor = Math.pow(1 - resistance, deltaTime);
|
1938
1750
|
this.characterVelocity.multiplyScalar(speedFactor);
|
1939
1751
|
const acceleration = this.tempVector.set(0, 0, 0);
|
1940
1752
|
this.canDoubleJump = !this.doubleJumpUsed && this.jumpReleased && this.jumpCounter === 1;
|
1941
1753
|
this.processJump(acceleration, deltaTime);
|
1942
|
-
const control = (this.characterOnGround ? this.
|
1754
|
+
const control = (this.characterOnGround ? ((_a = this.controlState) == null ? void 0 : _a.isSprinting) ? this.groundRunControl : this.groundWalkControl : this.airControlModifier) * this.baseControl;
|
1943
1755
|
const controlAcceleration = this.tempVector2.set(0, 0, 0);
|
1944
|
-
if (
|
1945
|
-
|
1946
|
-
|
1947
|
-
|
1948
|
-
}
|
1949
|
-
if (this.backward) {
|
1950
|
-
const backward = this.tempVector3.set(0, 0, 1).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
|
1951
|
-
controlAcceleration.add(backward);
|
1952
|
-
}
|
1953
|
-
if (this.left) {
|
1954
|
-
const left = this.tempVector3.set(-1, 0, 0).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
|
1955
|
-
controlAcceleration.add(left);
|
1956
|
-
}
|
1957
|
-
if (this.right) {
|
1958
|
-
const right = this.tempVector3.set(1, 0, 0).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
|
1959
|
-
controlAcceleration.add(right);
|
1960
|
-
}
|
1756
|
+
if (this.controlState && this.controlState.direction !== null) {
|
1757
|
+
const heading = this.controlState.direction;
|
1758
|
+
const headingVector = this.tempVector3.set(0, 0, 1).applyAxisAngle(this.vectorUp, this.azimuthalAngle + heading);
|
1759
|
+
controlAcceleration.add(headingVector);
|
1961
1760
|
}
|
1962
1761
|
if (controlAcceleration.length() > 0) {
|
1963
1762
|
controlAcceleration.normalize();
|
@@ -1968,6 +1767,7 @@ var LocalController = class {
|
|
1968
1767
|
this.config.character.position.addScaledVector(this.characterVelocity, deltaTime);
|
1969
1768
|
}
|
1970
1769
|
updatePosition(deltaTime, stepDeltaTime, iter) {
|
1770
|
+
var _a;
|
1971
1771
|
this.applyControls(stepDeltaTime);
|
1972
1772
|
if (iter === 0) {
|
1973
1773
|
const lastMovement = this.getMovementFromSurfaces(this.config.character.position, deltaTime);
|
@@ -1999,7 +1799,7 @@ var LocalController = class {
|
|
1999
1799
|
if (this.characterWasOnGround && !this.characterOnGround) {
|
2000
1800
|
this.characterAirborneSince = Date.now();
|
2001
1801
|
}
|
2002
|
-
if (!this.jump) {
|
1802
|
+
if (!((_a = this.controlState) == null ? void 0 : _a.jump)) {
|
2003
1803
|
this.jumpReleased = true;
|
2004
1804
|
}
|
2005
1805
|
this.coyoteTime = this.characterVelocity.y < 0 && !this.characterOnGround && Date.now() - this.characterAirborneSince < this.coyoteTimeThreshold;
|
@@ -2321,7 +2121,11 @@ var CharacterManager = class {
|
|
2321
2121
|
this.remoteCharacterControllers.delete(id);
|
2322
2122
|
}
|
2323
2123
|
}
|
2324
|
-
if (this.config.updateURLLocation && this.config.timeManager.frame % 60 === 0 && document.hasFocus()
|
2124
|
+
if (this.config.updateURLLocation && this.config.timeManager.frame % 60 === 0 && document.hasFocus() && /*
|
2125
|
+
Don't update the URL if the camera is being controlled as some browsers (e.g. Chrome) cause a hitch to Pointer
|
2126
|
+
events when the url is updated
|
2127
|
+
*/
|
2128
|
+
!this.config.cameraManager.hasActiveInput()) {
|
2325
2129
|
const hash = encodeCharacterAndCamera(
|
2326
2130
|
this.localCharacter,
|
2327
2131
|
this.config.cameraManager.camera
|
@@ -2450,35 +2254,236 @@ var KeyInputManager = class {
|
|
2450
2254
|
isMovementKeyPressed() {
|
2451
2255
|
return ["w" /* W */, "a" /* A */, "s" /* S */, "d" /* D */].some((key) => this.isKeyPressed(key));
|
2452
2256
|
}
|
2453
|
-
|
2257
|
+
getForward() {
|
2454
2258
|
return this.isKeyPressed("w" /* W */);
|
2455
2259
|
}
|
2456
|
-
|
2260
|
+
getBackward() {
|
2457
2261
|
return this.isKeyPressed("s" /* S */);
|
2458
2262
|
}
|
2459
|
-
|
2263
|
+
getLeft() {
|
2460
2264
|
return this.isKeyPressed("a" /* A */);
|
2461
2265
|
}
|
2462
|
-
|
2266
|
+
getRight() {
|
2463
2267
|
return this.isKeyPressed("d" /* D */);
|
2464
2268
|
}
|
2465
|
-
|
2269
|
+
getRun() {
|
2466
2270
|
return this.isKeyPressed("shift" /* SHIFT */);
|
2467
2271
|
}
|
2468
|
-
|
2272
|
+
getJump() {
|
2469
2273
|
return this.isKeyPressed(" " /* SPACE */);
|
2470
2274
|
}
|
2471
|
-
|
2472
|
-
|
2473
|
-
|
2474
|
-
|
2475
|
-
|
2275
|
+
getOutput() {
|
2276
|
+
const dx = (this.getRight() ? 1 : 0) - (this.getLeft() ? 1 : 0);
|
2277
|
+
const dy = (this.getBackward() ? 1 : 0) - (this.getForward() ? 1 : 0);
|
2278
|
+
const jump = this.getJump();
|
2279
|
+
if (dx === 0 && dy === 0) {
|
2280
|
+
if (this.getJump()) {
|
2281
|
+
return { direction: null, isSprinting: false, jump };
|
2282
|
+
}
|
2283
|
+
return null;
|
2284
|
+
}
|
2285
|
+
const direction = Math.atan2(dx, dy);
|
2286
|
+
return { direction, isSprinting: this.getRun(), jump };
|
2476
2287
|
}
|
2477
2288
|
dispose() {
|
2478
2289
|
this.eventHandlerCollection.clear();
|
2479
2290
|
}
|
2480
2291
|
};
|
2481
2292
|
|
2293
|
+
// src/input/VirtualJoystick.ts
|
2294
|
+
var sprintingThreshold = 0.6;
|
2295
|
+
var VirtualJoystick = class _VirtualJoystick {
|
2296
|
+
constructor(holderElement, config) {
|
2297
|
+
this.holderElement = holderElement;
|
2298
|
+
this.config = config;
|
2299
|
+
this.joystickPointerId = null;
|
2300
|
+
this.joystickOutput = null;
|
2301
|
+
this.jumpPointerId = null;
|
2302
|
+
this.clearJoystickState = () => {
|
2303
|
+
this.joystickOutput = null;
|
2304
|
+
this.joystickCenterElement.style.left = `${this.radius - this.innerRadius}px`;
|
2305
|
+
this.joystickCenterElement.style.top = `${this.radius - this.innerRadius}px`;
|
2306
|
+
};
|
2307
|
+
this.radius = config.radius || 50;
|
2308
|
+
this.innerRadius = config.innerRadius || this.radius / 2;
|
2309
|
+
this.mouseSupport = this.checkTouch() || config.mouseSupport === true;
|
2310
|
+
this.element = document.createElement("div");
|
2311
|
+
const style = this.element.style;
|
2312
|
+
style.display = this.mouseSupport ? "flex" : "none";
|
2313
|
+
style.position = "absolute";
|
2314
|
+
style.width = `100%`;
|
2315
|
+
style.height = `200px`;
|
2316
|
+
style.bottom = "50px";
|
2317
|
+
style.zIndex = "10000";
|
2318
|
+
style.alignItems = "center";
|
2319
|
+
style.justifyContent = "space-between";
|
2320
|
+
style.pointerEvents = "none";
|
2321
|
+
style.padding = "20px";
|
2322
|
+
style.boxSizing = "border-box";
|
2323
|
+
style.userSelect = "none";
|
2324
|
+
this.holderElement.appendChild(this.element);
|
2325
|
+
this.joystickBaseElement = this.createBase();
|
2326
|
+
this.element.appendChild(this.joystickBaseElement);
|
2327
|
+
this.joystickCenterElement = this.createCenter();
|
2328
|
+
this.joystickBaseElement.appendChild(this.joystickCenterElement);
|
2329
|
+
this.jumpButton = this.createJumpButton();
|
2330
|
+
this.element.appendChild(this.jumpButton);
|
2331
|
+
this.bindEvents();
|
2332
|
+
this.clearJoystickState();
|
2333
|
+
}
|
2334
|
+
static checkForTouch() {
|
2335
|
+
try {
|
2336
|
+
document.createEvent("TouchEvent");
|
2337
|
+
return true;
|
2338
|
+
} catch (e) {
|
2339
|
+
return false;
|
2340
|
+
}
|
2341
|
+
}
|
2342
|
+
checkTouch() {
|
2343
|
+
return _VirtualJoystick.checkForTouch();
|
2344
|
+
}
|
2345
|
+
createBase() {
|
2346
|
+
const base = document.createElement("span");
|
2347
|
+
const style = base.style;
|
2348
|
+
style.touchAction = "pinch-zoom";
|
2349
|
+
style.width = `${this.radius * 2}px`;
|
2350
|
+
style.height = `${this.radius * 2}px`;
|
2351
|
+
style.position = "relative";
|
2352
|
+
style.display = "block";
|
2353
|
+
style.borderRadius = "50%";
|
2354
|
+
style.borderColor = "rgba(200,200,200,0.5)";
|
2355
|
+
style.borderWidth = "2px";
|
2356
|
+
style.borderStyle = "solid";
|
2357
|
+
style.pointerEvents = "auto";
|
2358
|
+
style.userSelect = "none";
|
2359
|
+
return base;
|
2360
|
+
}
|
2361
|
+
createCenter() {
|
2362
|
+
const center = document.createElement("div");
|
2363
|
+
const style = center.style;
|
2364
|
+
style.width = `${this.innerRadius * 2}px`;
|
2365
|
+
style.height = `${this.innerRadius * 2}px`;
|
2366
|
+
style.position = "absolute";
|
2367
|
+
style.borderRadius = "50%";
|
2368
|
+
style.backgroundColor = "rgba(200,200,200,0.3)";
|
2369
|
+
style.borderWidth = "1px";
|
2370
|
+
style.borderColor = "rgba(200,200,200,0.8)";
|
2371
|
+
style.borderStyle = "solid";
|
2372
|
+
style.userSelect = "none";
|
2373
|
+
return center;
|
2374
|
+
}
|
2375
|
+
createJumpButton() {
|
2376
|
+
const button = document.createElement("button");
|
2377
|
+
button.textContent = "JUMP";
|
2378
|
+
const style = button.style;
|
2379
|
+
style.touchAction = "pinch-zoom";
|
2380
|
+
style.width = `100px`;
|
2381
|
+
style.height = `100px`;
|
2382
|
+
style.borderRadius = "20px";
|
2383
|
+
style.color = "white";
|
2384
|
+
style.font = "Helvetica, sans-serif";
|
2385
|
+
style.fontSize = "16px";
|
2386
|
+
style.backgroundColor = "rgba(200,200,200,0.3)";
|
2387
|
+
style.color = "rgba(220,220,220,1)";
|
2388
|
+
style.borderWidth = "1px";
|
2389
|
+
style.borderColor = "rgba(200,200,200,0.8)";
|
2390
|
+
style.borderStyle = "solid";
|
2391
|
+
style.pointerEvents = "auto";
|
2392
|
+
style.userSelect = "none";
|
2393
|
+
return button;
|
2394
|
+
}
|
2395
|
+
bindEvents() {
|
2396
|
+
this.joystickBaseElement.addEventListener("pointerdown", this.onJoystickPointerDown.bind(this));
|
2397
|
+
this.joystickBaseElement.addEventListener(
|
2398
|
+
"contextmenu",
|
2399
|
+
this.preventDefaultAndStopPropagation.bind(this)
|
2400
|
+
);
|
2401
|
+
this.joystickBaseElement.addEventListener(
|
2402
|
+
"touchstart",
|
2403
|
+
this.preventDefaultAndStopPropagation.bind(this)
|
2404
|
+
);
|
2405
|
+
this.jumpButton.addEventListener("pointerdown", this.onJumpPointerDown.bind(this));
|
2406
|
+
this.jumpButton.addEventListener(
|
2407
|
+
"contextmenu",
|
2408
|
+
this.preventDefaultAndStopPropagation.bind(this)
|
2409
|
+
);
|
2410
|
+
this.jumpButton.addEventListener(
|
2411
|
+
"touchstart",
|
2412
|
+
this.preventDefaultAndStopPropagation.bind(this)
|
2413
|
+
);
|
2414
|
+
document.addEventListener("pointermove", this.onPointerMove.bind(this));
|
2415
|
+
document.addEventListener("pointerup", this.onPointerUp.bind(this));
|
2416
|
+
document.addEventListener("pointercancel", this.onPointerUp.bind(this));
|
2417
|
+
}
|
2418
|
+
preventDefaultAndStopPropagation(evt) {
|
2419
|
+
evt.preventDefault();
|
2420
|
+
evt.stopPropagation();
|
2421
|
+
}
|
2422
|
+
onJumpPointerDown(evt) {
|
2423
|
+
if (this.jumpPointerId === null) {
|
2424
|
+
this.jumpPointerId = evt.pointerId;
|
2425
|
+
}
|
2426
|
+
}
|
2427
|
+
onJoystickPointerDown(evt) {
|
2428
|
+
evt.preventDefault();
|
2429
|
+
evt.stopPropagation();
|
2430
|
+
if (evt.buttons !== 1) {
|
2431
|
+
return;
|
2432
|
+
}
|
2433
|
+
if (this.joystickPointerId === null) {
|
2434
|
+
this.joystickPointerId = evt.pointerId;
|
2435
|
+
this.updateControlAndDirection(evt);
|
2436
|
+
}
|
2437
|
+
}
|
2438
|
+
onPointerMove(evt) {
|
2439
|
+
evt.preventDefault();
|
2440
|
+
evt.stopPropagation();
|
2441
|
+
if (evt.pointerId !== this.joystickPointerId) {
|
2442
|
+
return;
|
2443
|
+
}
|
2444
|
+
this.updateControlAndDirection(evt);
|
2445
|
+
}
|
2446
|
+
onPointerUp(evt) {
|
2447
|
+
evt.preventDefault();
|
2448
|
+
evt.stopPropagation();
|
2449
|
+
if (evt.pointerId === this.jumpPointerId) {
|
2450
|
+
this.jumpPointerId = null;
|
2451
|
+
}
|
2452
|
+
if (evt.pointerId === this.joystickPointerId) {
|
2453
|
+
this.joystickPointerId = null;
|
2454
|
+
this.clearJoystickState();
|
2455
|
+
}
|
2456
|
+
}
|
2457
|
+
updateControlAndDirection(input) {
|
2458
|
+
const rect = this.joystickBaseElement.getBoundingClientRect();
|
2459
|
+
const dx = input.clientX - (rect.left + this.radius);
|
2460
|
+
const dy = input.clientY - (rect.top + this.radius);
|
2461
|
+
const distance = Math.min(Math.sqrt(dx * dx + dy * dy), this.radius);
|
2462
|
+
const angle = Math.atan2(dy, dx);
|
2463
|
+
const constrainedX = distance * Math.cos(angle);
|
2464
|
+
const constrainedY = distance * Math.sin(angle);
|
2465
|
+
this.joystickCenterElement.style.left = `${constrainedX + this.radius - this.innerRadius}px`;
|
2466
|
+
this.joystickCenterElement.style.top = `${constrainedY + this.radius - this.innerRadius}px`;
|
2467
|
+
const direction = Math.atan2(dx, dy);
|
2468
|
+
const speed = distance / this.radius;
|
2469
|
+
const isSprinting = speed > sprintingThreshold;
|
2470
|
+
this.joystickOutput = { direction, isSprinting };
|
2471
|
+
}
|
2472
|
+
getOutput() {
|
2473
|
+
const jump = this.jumpPointerId !== null;
|
2474
|
+
if (!this.joystickOutput) {
|
2475
|
+
if (jump) {
|
2476
|
+
return { direction: null, isSprinting: false, jump };
|
2477
|
+
}
|
2478
|
+
return null;
|
2479
|
+
}
|
2480
|
+
return {
|
2481
|
+
...this.joystickOutput,
|
2482
|
+
jump
|
2483
|
+
};
|
2484
|
+
}
|
2485
|
+
};
|
2486
|
+
|
2482
2487
|
// src/mml/MMLCompositionScene.ts
|
2483
2488
|
import {
|
2484
2489
|
InteractionManager,
|