@mml-io/3d-web-client-core 0.0.0-experimental-42d909b-20240717 → 0.0.0-experimental-c5bc6e3-20240723
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 -340
- 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,116 @@ 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
238
|
this.phi = Math.PI / 2;
|
239
|
+
this.targetPhi = this.phi;
|
396
240
|
this.theta = Math.PI / 2;
|
397
|
-
this.
|
241
|
+
this.targetTheta = this.theta;
|
398
242
|
this.target = new Vector32(0, 1.55, 0);
|
399
243
|
this.hadTarget = false;
|
400
|
-
this.isLerping = false;
|
401
244
|
this.finalTarget = new Vector32();
|
245
|
+
this.isLerping = false;
|
402
246
|
this.lerpTarget = new Vector32();
|
403
247
|
this.lerpFactor = 0;
|
404
248
|
this.lerpDuration = 2.1;
|
405
|
-
this.
|
406
|
-
this.
|
407
|
-
this.lastTouchY = 0;
|
249
|
+
this.activePointers = /* @__PURE__ */ new Map();
|
250
|
+
this.targetElement.style.touchAction = "pinch-zoom";
|
408
251
|
this.phi = initialPhi;
|
409
|
-
this.targetPhi = initialPhi;
|
410
252
|
this.theta = initialTheta;
|
411
|
-
this.targetTheta = initialTheta;
|
412
253
|
this.camera = new PerspectiveCamera(this.fov, window.innerWidth / window.innerHeight, 0.1, 400);
|
413
254
|
this.camera.position.set(0, 1.4, -this.initialDistance);
|
414
255
|
this.rayCaster = new Raycaster();
|
415
|
-
this.hasTouchControl = VirtualJoystick.checkForTouch();
|
416
256
|
this.eventHandlerCollection = EventHandlerCollection.create([
|
417
|
-
[targetElement, "
|
418
|
-
[
|
419
|
-
[document, "
|
257
|
+
[targetElement, "pointerdown", this.onPointerDown.bind(this)],
|
258
|
+
[targetElement, "gesturestart", this.preventDefaultAndStopPropagation.bind(this)],
|
259
|
+
[document, "pointerup", this.onPointerUp.bind(this)],
|
260
|
+
[document, "pointercancel", this.onPointerUp.bind(this)],
|
261
|
+
[document, "pointermove", this.onPointerMove.bind(this)],
|
420
262
|
[targetElement, "wheel", this.onMouseWheel.bind(this)],
|
421
263
|
[targetElement, "contextmenu", this.onContextMenu.bind(this)]
|
422
264
|
]);
|
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
265
|
}
|
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
|
-
}
|
266
|
+
preventDefaultAndStopPropagation(evt) {
|
449
267
|
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
|
-
}
|
268
|
+
evt.stopPropagation();
|
462
269
|
}
|
463
|
-
|
464
|
-
|
465
|
-
const touchEnded = Array.from(evt.changedTouches).some((t) => true);
|
466
|
-
if (touchEnded) {
|
467
|
-
this.dragging = false;
|
468
|
-
}
|
469
|
-
}
|
270
|
+
setupTweakPane(tweakPane) {
|
271
|
+
tweakPane.setupCamPane(this);
|
470
272
|
}
|
471
|
-
|
273
|
+
onPointerDown(event) {
|
472
274
|
if (event.button === 0 || event.button === 2) {
|
473
|
-
|
275
|
+
const pointerInfo = { x: event.clientX, y: event.clientY };
|
276
|
+
this.activePointers.set(event.pointerId, pointerInfo);
|
474
277
|
document.body.style.cursor = "none";
|
475
278
|
}
|
476
279
|
}
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
280
|
+
onPointerUp(event) {
|
281
|
+
const existingPointer = this.activePointers.get(event.pointerId);
|
282
|
+
if (existingPointer) {
|
283
|
+
this.activePointers.delete(event.pointerId);
|
284
|
+
if (this.activePointers.size === 0) {
|
285
|
+
document.body.style.cursor = "default";
|
286
|
+
}
|
481
287
|
}
|
482
288
|
}
|
483
|
-
|
289
|
+
getAveragePointerPositionAndSpread() {
|
290
|
+
const existingSum = { x: 0, y: 0 };
|
291
|
+
this.activePointers.forEach((p) => {
|
292
|
+
existingSum.x += p.x;
|
293
|
+
existingSum.y += p.y;
|
294
|
+
});
|
295
|
+
const aX = existingSum.x / this.activePointers.size;
|
296
|
+
const aY = existingSum.y / this.activePointers.size;
|
297
|
+
let sumOfDistances = 0;
|
298
|
+
this.activePointers.forEach((p) => {
|
299
|
+
const distance = Math.sqrt((p.x - aX) ** 2 + (p.y - aY) ** 2);
|
300
|
+
sumOfDistances += distance;
|
301
|
+
});
|
302
|
+
return { pos: { x: aX, y: aY }, spread: sumOfDistances / this.activePointers.size };
|
303
|
+
}
|
304
|
+
onPointerMove(event) {
|
484
305
|
if (getTweakpaneActive()) {
|
485
306
|
return;
|
486
307
|
}
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
308
|
+
const existingPointer = this.activePointers.get(event.pointerId);
|
309
|
+
if (existingPointer) {
|
310
|
+
const previous = this.getAveragePointerPositionAndSpread();
|
311
|
+
existingPointer.x = event.clientX;
|
312
|
+
existingPointer.y = event.clientY;
|
313
|
+
const latest = this.getAveragePointerPositionAndSpread();
|
314
|
+
const sX = latest.pos.x - previous.pos.x;
|
315
|
+
const sY = latest.pos.y - previous.pos.y;
|
316
|
+
const dx = sX / this.targetElement.clientWidth * cameraPanSensitivity;
|
317
|
+
const dy = sY / this.targetElement.clientHeight * cameraPanSensitivity;
|
318
|
+
if (this.activePointers.size > 1) {
|
319
|
+
const zoomDelta = latest.spread - previous.spread;
|
320
|
+
this.zoom(-zoomDelta * pinchZoomSensitivity);
|
321
|
+
}
|
322
|
+
this.targetTheta += dx;
|
323
|
+
this.targetPhi -= dy;
|
492
324
|
this.targetPhi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this.targetPhi));
|
493
325
|
event.preventDefault();
|
494
326
|
}
|
@@ -497,14 +329,17 @@ var CameraManager = class {
|
|
497
329
|
if (getTweakpaneActive()) {
|
498
330
|
return;
|
499
331
|
}
|
500
|
-
|
501
|
-
this.
|
332
|
+
event.preventDefault();
|
333
|
+
const scrollAmount = event.deltaY * this.zoomScale * scrollZoomSensitivity;
|
334
|
+
this.zoom(scrollAmount);
|
335
|
+
}
|
336
|
+
zoom(delta) {
|
337
|
+
this.targetDistance += delta;
|
502
338
|
this.targetDistance = Math.max(
|
503
339
|
this.minDistance,
|
504
340
|
Math.min(this.maxDistance, this.targetDistance)
|
505
341
|
);
|
506
342
|
this.desiredDistance = this.targetDistance;
|
507
|
-
event.preventDefault();
|
508
343
|
}
|
509
344
|
onContextMenu(event) {
|
510
345
|
event.preventDefault();
|
@@ -533,12 +368,12 @@ var CameraManager = class {
|
|
533
368
|
const dy = this.camera.position.y - this.target.y;
|
534
369
|
const dz = this.camera.position.z - this.target.z;
|
535
370
|
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
371
|
this.distance = this.targetDistance;
|
541
372
|
this.desiredDistance = this.targetDistance;
|
373
|
+
this.theta = Math.atan2(dz, dx);
|
374
|
+
this.targetTheta = this.theta;
|
375
|
+
this.phi = Math.acos(dy / this.targetDistance);
|
376
|
+
this.targetPhi = this.phi;
|
542
377
|
this.recomputeFoV(true);
|
543
378
|
}
|
544
379
|
adjustCameraPosition() {
|
@@ -546,15 +381,15 @@ var CameraManager = class {
|
|
546
381
|
const offset = new Vector32(0, 0, offsetDistance);
|
547
382
|
offset.applyEuler(this.camera.rotation);
|
548
383
|
const rayOrigin = this.camera.position.clone().add(offset);
|
549
|
-
const rayDirection = this.target.clone()
|
550
|
-
this.rayCaster.set(
|
384
|
+
const rayDirection = rayOrigin.sub(this.target.clone()).normalize();
|
385
|
+
this.rayCaster.set(this.target.clone(), rayDirection);
|
551
386
|
const firstRaycastHit = this.collisionsManager.raycastFirst(this.rayCaster.ray);
|
552
|
-
|
553
|
-
|
554
|
-
this.targetDistance =
|
555
|
-
this.distance =
|
387
|
+
if (firstRaycastHit !== null && firstRaycastHit[0] <= this.desiredDistance) {
|
388
|
+
const distanceToCollision = firstRaycastHit[0] - 0.1;
|
389
|
+
this.targetDistance = distanceToCollision;
|
390
|
+
this.distance = distanceToCollision;
|
556
391
|
} else {
|
557
|
-
this.targetDistance
|
392
|
+
this.targetDistance = this.desiredDistance;
|
558
393
|
}
|
559
394
|
}
|
560
395
|
dispose() {
|
@@ -587,24 +422,25 @@ var CameraManager = class {
|
|
587
422
|
} else {
|
588
423
|
this.adjustCameraPosition();
|
589
424
|
}
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
this.isLerping = false;
|
605
|
-
}
|
425
|
+
this.distance += (this.targetDistance - this.distance) * this.zoomDamping;
|
426
|
+
this.theta += (this.targetTheta - this.theta) * this.damping;
|
427
|
+
this.phi += (this.targetPhi - this.phi) * this.damping;
|
428
|
+
const x = this.target.x + this.distance * Math.sin(this.phi) * Math.cos(this.theta);
|
429
|
+
const y = this.target.y + this.distance * Math.cos(this.phi);
|
430
|
+
const z = this.target.z + this.distance * Math.sin(this.phi) * Math.sin(this.theta);
|
431
|
+
this.recomputeFoV();
|
432
|
+
this.fov += (this.targetFOV - this.fov) * this.zoomDamping;
|
433
|
+
this.camera.fov = this.fov;
|
434
|
+
this.camera.updateProjectionMatrix();
|
435
|
+
this.camera.position.set(x, y, z);
|
436
|
+
this.camera.lookAt(this.target);
|
437
|
+
if (this.isLerping && this.lerpFactor >= 1) {
|
438
|
+
this.isLerping = false;
|
606
439
|
}
|
607
440
|
}
|
441
|
+
hasActiveInput() {
|
442
|
+
return this.activePointers.size > 0;
|
443
|
+
}
|
608
444
|
};
|
609
445
|
|
610
446
|
// src/character/Character.ts
|
@@ -1770,6 +1606,7 @@ var LocalController = class {
|
|
1770
1606
|
this.jumpPressed = false;
|
1771
1607
|
// Tracks if the jump button is pressed
|
1772
1608
|
this.jumpReleased = true;
|
1609
|
+
this.controlState = null;
|
1773
1610
|
this.networkState = {
|
1774
1611
|
id: this.config.id,
|
1775
1612
|
position: { x: 0, y: 0, z: 0 },
|
@@ -1777,35 +1614,22 @@ var LocalController = class {
|
|
1777
1614
|
state: 0 /* idle */
|
1778
1615
|
};
|
1779
1616
|
}
|
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
1617
|
update() {
|
1795
|
-
|
1618
|
+
var _a, _b;
|
1619
|
+
this.controlState = this.config.keyInputManager.getOutput() || ((_a = this.config.virtualJoystick) == null ? void 0 : _a.getOutput()) || null;
|
1796
1620
|
this.rayCaster.set(this.config.character.position, this.vectorDown);
|
1797
1621
|
const firstRaycastHit = this.config.collisionsManager.raycastFirst(this.rayCaster.ray);
|
1798
1622
|
if (firstRaycastHit !== null) {
|
1799
1623
|
this.currentHeight = firstRaycastHit[0];
|
1800
1624
|
this.currentSurfaceAngle.copy(firstRaycastHit[1]);
|
1801
1625
|
}
|
1802
|
-
if (this.
|
1626
|
+
if (((_b = this.controlState) == null ? void 0 : _b.direction) !== null || !this.characterOnGround) {
|
1803
1627
|
const targetAnimation = this.getTargetAnimation();
|
1804
1628
|
this.config.character.updateAnimation(targetAnimation);
|
1805
1629
|
} else {
|
1806
1630
|
this.config.character.updateAnimation(0 /* idle */);
|
1807
1631
|
}
|
1808
|
-
if (this.
|
1632
|
+
if (this.controlState) {
|
1809
1633
|
this.updateRotation();
|
1810
1634
|
}
|
1811
1635
|
for (let i = 0; i < this.collisionDetectionSteps; i++) {
|
@@ -1830,30 +1654,17 @@ var LocalController = class {
|
|
1830
1654
|
}
|
1831
1655
|
return 4 /* air */;
|
1832
1656
|
}
|
1833
|
-
if (this.
|
1657
|
+
if (!this.controlState) {
|
1834
1658
|
return 0 /* idle */;
|
1835
1659
|
}
|
1836
|
-
|
1660
|
+
if (this.controlState.isSprinting) {
|
1661
|
+
return 2 /* running */;
|
1662
|
+
}
|
1663
|
+
return 1 /* walking */;
|
1837
1664
|
}
|
1838
1665
|
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;
|
1666
|
+
if (this.controlState && this.controlState.direction !== null) {
|
1667
|
+
this.rotationOffset = this.controlState.direction;
|
1857
1668
|
}
|
1858
1669
|
}
|
1859
1670
|
updateAzimuthalAngle() {
|
@@ -1888,17 +1699,19 @@ var LocalController = class {
|
|
1888
1699
|
this.config.character.quaternion.rotateTowards(rotationQuaternion, frameRotation);
|
1889
1700
|
}
|
1890
1701
|
processJump(currentAcceleration, deltaTime) {
|
1702
|
+
var _a;
|
1703
|
+
const jump = (_a = this.controlState) == null ? void 0 : _a.jump;
|
1891
1704
|
if (this.characterOnGround) {
|
1892
1705
|
this.coyoteJumped = false;
|
1893
1706
|
this.canDoubleJump = false;
|
1894
1707
|
this.doubleJumpUsed = false;
|
1895
1708
|
this.jumpCounter = 0;
|
1896
|
-
if (!
|
1709
|
+
if (!jump) {
|
1897
1710
|
this.canDoubleJump = !this.doubleJumpUsed && this.jumpReleased && this.jumpCounter === 1;
|
1898
1711
|
this.canJump = true;
|
1899
1712
|
this.jumpReleased = true;
|
1900
1713
|
}
|
1901
|
-
if (
|
1714
|
+
if (jump && this.canJump && this.jumpReleased) {
|
1902
1715
|
currentAcceleration.y += this.jumpForce / deltaTime;
|
1903
1716
|
this.canJump = false;
|
1904
1717
|
this.jumpReleased = false;
|
@@ -1909,13 +1722,13 @@ var LocalController = class {
|
|
1909
1722
|
}
|
1910
1723
|
}
|
1911
1724
|
} else {
|
1912
|
-
if (
|
1725
|
+
if (jump && !this.coyoteJumped && this.coyoteTime) {
|
1913
1726
|
this.coyoteJumped = true;
|
1914
1727
|
currentAcceleration.y += this.jumpForce / deltaTime;
|
1915
1728
|
this.canJump = false;
|
1916
1729
|
this.jumpReleased = false;
|
1917
1730
|
this.jumpCounter++;
|
1918
|
-
} else if (
|
1731
|
+
} else if (jump && this.canDoubleJump) {
|
1919
1732
|
currentAcceleration.y += this.doubleJumpForce / deltaTime;
|
1920
1733
|
this.doubleJumpUsed = true;
|
1921
1734
|
this.jumpReleased = false;
|
@@ -1925,7 +1738,7 @@ var LocalController = class {
|
|
1925
1738
|
this.canJump = false;
|
1926
1739
|
}
|
1927
1740
|
}
|
1928
|
-
if (!
|
1741
|
+
if (!jump) {
|
1929
1742
|
this.jumpReleased = true;
|
1930
1743
|
if (!this.characterOnGround) {
|
1931
1744
|
currentAcceleration.y += this.gravity;
|
@@ -1933,31 +1746,19 @@ var LocalController = class {
|
|
1933
1746
|
}
|
1934
1747
|
}
|
1935
1748
|
applyControls(deltaTime) {
|
1749
|
+
var _a;
|
1936
1750
|
const resistance = this.characterOnGround ? this.groundResistance : this.airResistance;
|
1937
1751
|
const speedFactor = Math.pow(1 - resistance, deltaTime);
|
1938
1752
|
this.characterVelocity.multiplyScalar(speedFactor);
|
1939
1753
|
const acceleration = this.tempVector.set(0, 0, 0);
|
1940
1754
|
this.canDoubleJump = !this.doubleJumpUsed && this.jumpReleased && this.jumpCounter === 1;
|
1941
1755
|
this.processJump(acceleration, deltaTime);
|
1942
|
-
const control = (this.characterOnGround ? this.
|
1756
|
+
const control = (this.characterOnGround ? ((_a = this.controlState) == null ? void 0 : _a.isSprinting) ? this.groundRunControl : this.groundWalkControl : this.airControlModifier) * this.baseControl;
|
1943
1757
|
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
|
-
}
|
1758
|
+
if (this.controlState && this.controlState.direction !== null) {
|
1759
|
+
const heading = this.controlState.direction;
|
1760
|
+
const headingVector = this.tempVector3.set(0, 0, 1).applyAxisAngle(this.vectorUp, this.azimuthalAngle + heading);
|
1761
|
+
controlAcceleration.add(headingVector);
|
1961
1762
|
}
|
1962
1763
|
if (controlAcceleration.length() > 0) {
|
1963
1764
|
controlAcceleration.normalize();
|
@@ -1968,6 +1769,7 @@ var LocalController = class {
|
|
1968
1769
|
this.config.character.position.addScaledVector(this.characterVelocity, deltaTime);
|
1969
1770
|
}
|
1970
1771
|
updatePosition(deltaTime, stepDeltaTime, iter) {
|
1772
|
+
var _a;
|
1971
1773
|
this.applyControls(stepDeltaTime);
|
1972
1774
|
if (iter === 0) {
|
1973
1775
|
const lastMovement = this.getMovementFromSurfaces(this.config.character.position, deltaTime);
|
@@ -1999,7 +1801,7 @@ var LocalController = class {
|
|
1999
1801
|
if (this.characterWasOnGround && !this.characterOnGround) {
|
2000
1802
|
this.characterAirborneSince = Date.now();
|
2001
1803
|
}
|
2002
|
-
if (!this.jump) {
|
1804
|
+
if (!((_a = this.controlState) == null ? void 0 : _a.jump)) {
|
2003
1805
|
this.jumpReleased = true;
|
2004
1806
|
}
|
2005
1807
|
this.coyoteTime = this.characterVelocity.y < 0 && !this.characterOnGround && Date.now() - this.characterAirborneSince < this.coyoteTimeThreshold;
|
@@ -2321,7 +2123,11 @@ var CharacterManager = class {
|
|
2321
2123
|
this.remoteCharacterControllers.delete(id);
|
2322
2124
|
}
|
2323
2125
|
}
|
2324
|
-
if (this.config.updateURLLocation && this.config.timeManager.frame % 60 === 0 && document.hasFocus()
|
2126
|
+
if (this.config.updateURLLocation && this.config.timeManager.frame % 60 === 0 && document.hasFocus() && /*
|
2127
|
+
Don't update the URL if the camera is being controlled as some browsers (e.g. Chrome) cause a hitch to Pointer
|
2128
|
+
events when the url is updated
|
2129
|
+
*/
|
2130
|
+
!this.config.cameraManager.hasActiveInput()) {
|
2325
2131
|
const hash = encodeCharacterAndCamera(
|
2326
2132
|
this.localCharacter,
|
2327
2133
|
this.config.cameraManager.camera
|
@@ -2450,35 +2256,236 @@ var KeyInputManager = class {
|
|
2450
2256
|
isMovementKeyPressed() {
|
2451
2257
|
return ["w" /* W */, "a" /* A */, "s" /* S */, "d" /* D */].some((key) => this.isKeyPressed(key));
|
2452
2258
|
}
|
2453
|
-
|
2259
|
+
getForward() {
|
2454
2260
|
return this.isKeyPressed("w" /* W */);
|
2455
2261
|
}
|
2456
|
-
|
2262
|
+
getBackward() {
|
2457
2263
|
return this.isKeyPressed("s" /* S */);
|
2458
2264
|
}
|
2459
|
-
|
2265
|
+
getLeft() {
|
2460
2266
|
return this.isKeyPressed("a" /* A */);
|
2461
2267
|
}
|
2462
|
-
|
2268
|
+
getRight() {
|
2463
2269
|
return this.isKeyPressed("d" /* D */);
|
2464
2270
|
}
|
2465
|
-
|
2271
|
+
getRun() {
|
2466
2272
|
return this.isKeyPressed("shift" /* SHIFT */);
|
2467
2273
|
}
|
2468
|
-
|
2274
|
+
getJump() {
|
2469
2275
|
return this.isKeyPressed(" " /* SPACE */);
|
2470
2276
|
}
|
2471
|
-
|
2472
|
-
|
2473
|
-
|
2474
|
-
|
2475
|
-
|
2277
|
+
getOutput() {
|
2278
|
+
const dx = (this.getRight() ? 1 : 0) - (this.getLeft() ? 1 : 0);
|
2279
|
+
const dy = (this.getBackward() ? 1 : 0) - (this.getForward() ? 1 : 0);
|
2280
|
+
const jump = this.getJump();
|
2281
|
+
if (dx === 0 && dy === 0) {
|
2282
|
+
if (this.getJump()) {
|
2283
|
+
return { direction: null, isSprinting: false, jump };
|
2284
|
+
}
|
2285
|
+
return null;
|
2286
|
+
}
|
2287
|
+
const direction = Math.atan2(dx, dy);
|
2288
|
+
return { direction, isSprinting: this.getRun(), jump };
|
2476
2289
|
}
|
2477
2290
|
dispose() {
|
2478
2291
|
this.eventHandlerCollection.clear();
|
2479
2292
|
}
|
2480
2293
|
};
|
2481
2294
|
|
2295
|
+
// src/input/VirtualJoystick.ts
|
2296
|
+
var sprintingThreshold = 0.6;
|
2297
|
+
var VirtualJoystick = class _VirtualJoystick {
|
2298
|
+
constructor(holderElement, config) {
|
2299
|
+
this.holderElement = holderElement;
|
2300
|
+
this.config = config;
|
2301
|
+
this.joystickPointerId = null;
|
2302
|
+
this.joystickOutput = null;
|
2303
|
+
this.jumpPointerId = null;
|
2304
|
+
this.clearJoystickState = () => {
|
2305
|
+
this.joystickOutput = null;
|
2306
|
+
this.joystickCenterElement.style.left = `${this.radius - this.innerRadius}px`;
|
2307
|
+
this.joystickCenterElement.style.top = `${this.radius - this.innerRadius}px`;
|
2308
|
+
};
|
2309
|
+
this.radius = config.radius || 50;
|
2310
|
+
this.innerRadius = config.innerRadius || this.radius / 2;
|
2311
|
+
this.mouseSupport = this.checkTouch() || config.mouseSupport === true;
|
2312
|
+
this.element = document.createElement("div");
|
2313
|
+
const style = this.element.style;
|
2314
|
+
style.display = this.mouseSupport ? "flex" : "none";
|
2315
|
+
style.position = "absolute";
|
2316
|
+
style.width = `100%`;
|
2317
|
+
style.height = `200px`;
|
2318
|
+
style.bottom = "50px";
|
2319
|
+
style.zIndex = "10000";
|
2320
|
+
style.alignItems = "center";
|
2321
|
+
style.justifyContent = "space-between";
|
2322
|
+
style.pointerEvents = "none";
|
2323
|
+
style.padding = "20px";
|
2324
|
+
style.boxSizing = "border-box";
|
2325
|
+
style.userSelect = "none";
|
2326
|
+
this.holderElement.appendChild(this.element);
|
2327
|
+
this.joystickBaseElement = this.createBase();
|
2328
|
+
this.element.appendChild(this.joystickBaseElement);
|
2329
|
+
this.joystickCenterElement = this.createCenter();
|
2330
|
+
this.joystickBaseElement.appendChild(this.joystickCenterElement);
|
2331
|
+
this.jumpButton = this.createJumpButton();
|
2332
|
+
this.element.appendChild(this.jumpButton);
|
2333
|
+
this.bindEvents();
|
2334
|
+
this.clearJoystickState();
|
2335
|
+
}
|
2336
|
+
static checkForTouch() {
|
2337
|
+
try {
|
2338
|
+
document.createEvent("TouchEvent");
|
2339
|
+
return true;
|
2340
|
+
} catch (e) {
|
2341
|
+
return false;
|
2342
|
+
}
|
2343
|
+
}
|
2344
|
+
checkTouch() {
|
2345
|
+
return _VirtualJoystick.checkForTouch();
|
2346
|
+
}
|
2347
|
+
createBase() {
|
2348
|
+
const base = document.createElement("span");
|
2349
|
+
const style = base.style;
|
2350
|
+
style.touchAction = "pinch-zoom";
|
2351
|
+
style.width = `${this.radius * 2}px`;
|
2352
|
+
style.height = `${this.radius * 2}px`;
|
2353
|
+
style.position = "relative";
|
2354
|
+
style.display = "block";
|
2355
|
+
style.borderRadius = "50%";
|
2356
|
+
style.borderColor = "rgba(200,200,200,0.5)";
|
2357
|
+
style.borderWidth = "2px";
|
2358
|
+
style.borderStyle = "solid";
|
2359
|
+
style.pointerEvents = "auto";
|
2360
|
+
style.userSelect = "none";
|
2361
|
+
return base;
|
2362
|
+
}
|
2363
|
+
createCenter() {
|
2364
|
+
const center = document.createElement("div");
|
2365
|
+
const style = center.style;
|
2366
|
+
style.width = `${this.innerRadius * 2}px`;
|
2367
|
+
style.height = `${this.innerRadius * 2}px`;
|
2368
|
+
style.position = "absolute";
|
2369
|
+
style.borderRadius = "50%";
|
2370
|
+
style.backgroundColor = "rgba(200,200,200,0.3)";
|
2371
|
+
style.borderWidth = "1px";
|
2372
|
+
style.borderColor = "rgba(200,200,200,0.8)";
|
2373
|
+
style.borderStyle = "solid";
|
2374
|
+
style.userSelect = "none";
|
2375
|
+
return center;
|
2376
|
+
}
|
2377
|
+
createJumpButton() {
|
2378
|
+
const button = document.createElement("button");
|
2379
|
+
button.textContent = "JUMP";
|
2380
|
+
const style = button.style;
|
2381
|
+
style.touchAction = "pinch-zoom";
|
2382
|
+
style.width = `100px`;
|
2383
|
+
style.height = `100px`;
|
2384
|
+
style.borderRadius = "20px";
|
2385
|
+
style.color = "white";
|
2386
|
+
style.font = "Helvetica, sans-serif";
|
2387
|
+
style.fontSize = "16px";
|
2388
|
+
style.backgroundColor = "rgba(200,200,200,0.3)";
|
2389
|
+
style.color = "rgba(220,220,220,1)";
|
2390
|
+
style.borderWidth = "1px";
|
2391
|
+
style.borderColor = "rgba(200,200,200,0.8)";
|
2392
|
+
style.borderStyle = "solid";
|
2393
|
+
style.pointerEvents = "auto";
|
2394
|
+
style.userSelect = "none";
|
2395
|
+
return button;
|
2396
|
+
}
|
2397
|
+
bindEvents() {
|
2398
|
+
this.joystickBaseElement.addEventListener("pointerdown", this.onJoystickPointerDown.bind(this));
|
2399
|
+
this.joystickBaseElement.addEventListener(
|
2400
|
+
"contextmenu",
|
2401
|
+
this.preventDefaultAndStopPropagation.bind(this)
|
2402
|
+
);
|
2403
|
+
this.joystickBaseElement.addEventListener(
|
2404
|
+
"touchstart",
|
2405
|
+
this.preventDefaultAndStopPropagation.bind(this)
|
2406
|
+
);
|
2407
|
+
this.jumpButton.addEventListener("pointerdown", this.onJumpPointerDown.bind(this));
|
2408
|
+
this.jumpButton.addEventListener(
|
2409
|
+
"contextmenu",
|
2410
|
+
this.preventDefaultAndStopPropagation.bind(this)
|
2411
|
+
);
|
2412
|
+
this.jumpButton.addEventListener(
|
2413
|
+
"touchstart",
|
2414
|
+
this.preventDefaultAndStopPropagation.bind(this)
|
2415
|
+
);
|
2416
|
+
document.addEventListener("pointermove", this.onPointerMove.bind(this));
|
2417
|
+
document.addEventListener("pointerup", this.onPointerUp.bind(this));
|
2418
|
+
document.addEventListener("pointercancel", this.onPointerUp.bind(this));
|
2419
|
+
}
|
2420
|
+
preventDefaultAndStopPropagation(evt) {
|
2421
|
+
evt.preventDefault();
|
2422
|
+
evt.stopPropagation();
|
2423
|
+
}
|
2424
|
+
onJumpPointerDown(evt) {
|
2425
|
+
if (this.jumpPointerId === null) {
|
2426
|
+
this.jumpPointerId = evt.pointerId;
|
2427
|
+
}
|
2428
|
+
}
|
2429
|
+
onJoystickPointerDown(evt) {
|
2430
|
+
evt.preventDefault();
|
2431
|
+
evt.stopPropagation();
|
2432
|
+
if (evt.buttons !== 1) {
|
2433
|
+
return;
|
2434
|
+
}
|
2435
|
+
if (this.joystickPointerId === null) {
|
2436
|
+
this.joystickPointerId = evt.pointerId;
|
2437
|
+
this.updateControlAndDirection(evt);
|
2438
|
+
}
|
2439
|
+
}
|
2440
|
+
onPointerMove(evt) {
|
2441
|
+
evt.preventDefault();
|
2442
|
+
evt.stopPropagation();
|
2443
|
+
if (evt.pointerId !== this.joystickPointerId) {
|
2444
|
+
return;
|
2445
|
+
}
|
2446
|
+
this.updateControlAndDirection(evt);
|
2447
|
+
}
|
2448
|
+
onPointerUp(evt) {
|
2449
|
+
evt.preventDefault();
|
2450
|
+
evt.stopPropagation();
|
2451
|
+
if (evt.pointerId === this.jumpPointerId) {
|
2452
|
+
this.jumpPointerId = null;
|
2453
|
+
}
|
2454
|
+
if (evt.pointerId === this.joystickPointerId) {
|
2455
|
+
this.joystickPointerId = null;
|
2456
|
+
this.clearJoystickState();
|
2457
|
+
}
|
2458
|
+
}
|
2459
|
+
updateControlAndDirection(input) {
|
2460
|
+
const rect = this.joystickBaseElement.getBoundingClientRect();
|
2461
|
+
const dx = input.clientX - (rect.left + this.radius);
|
2462
|
+
const dy = input.clientY - (rect.top + this.radius);
|
2463
|
+
const distance = Math.min(Math.sqrt(dx * dx + dy * dy), this.radius);
|
2464
|
+
const angle = Math.atan2(dy, dx);
|
2465
|
+
const constrainedX = distance * Math.cos(angle);
|
2466
|
+
const constrainedY = distance * Math.sin(angle);
|
2467
|
+
this.joystickCenterElement.style.left = `${constrainedX + this.radius - this.innerRadius}px`;
|
2468
|
+
this.joystickCenterElement.style.top = `${constrainedY + this.radius - this.innerRadius}px`;
|
2469
|
+
const direction = Math.atan2(dx, dy);
|
2470
|
+
const speed = distance / this.radius;
|
2471
|
+
const isSprinting = speed > sprintingThreshold;
|
2472
|
+
this.joystickOutput = { direction, isSprinting };
|
2473
|
+
}
|
2474
|
+
getOutput() {
|
2475
|
+
const jump = this.jumpPointerId !== null;
|
2476
|
+
if (!this.joystickOutput) {
|
2477
|
+
if (jump) {
|
2478
|
+
return { direction: null, isSprinting: false, jump };
|
2479
|
+
}
|
2480
|
+
return null;
|
2481
|
+
}
|
2482
|
+
return {
|
2483
|
+
...this.joystickOutput,
|
2484
|
+
jump
|
2485
|
+
};
|
2486
|
+
}
|
2487
|
+
};
|
2488
|
+
|
2482
2489
|
// src/mml/MMLCompositionScene.ts
|
2483
2490
|
import {
|
2484
2491
|
InteractionManager,
|