three-gamepad-controls 0.10.6 → 0.12.0
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/README.md +15 -0
- package/dist/gamepad-arcball-controls.d.ts +1 -2
- package/dist/gamepad-arcball-controls.js +75 -16
- package/dist/gamepad-controls.d.ts +25 -12
- package/dist/gamepad-controls.js +58 -51
- package/dist/gamepad-drag-controls.d.ts +1 -2
- package/dist/gamepad-drag-controls.js +86 -13
- package/dist/gamepad-first-person-controls.d.ts +1 -2
- package/dist/gamepad-first-person-controls.js +38 -13
- package/dist/gamepad-fly-controls.d.ts +1 -2
- package/dist/gamepad-fly-controls.js +9 -10
- package/dist/gamepad-input.d.ts +156 -0
- package/dist/gamepad-input.js +310 -0
- package/dist/gamepad-orbit-controls.d.ts +1 -2
- package/dist/gamepad-orbit-controls.js +8 -9
- package/dist/gamepad-pointer-lock-controls.d.ts +1 -2
- package/dist/gamepad-pointer-lock-controls.js +6 -7
- package/dist/gamepad-trackball-controls.d.ts +1 -2
- package/dist/gamepad-trackball-controls.js +45 -15
- package/dist/gamepad-transform-controls.d.ts +1 -2
- package/dist/gamepad-transform-controls.js +317 -21
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/package.json +3 -3
- package/dist/utils.js +0 -41
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
|
|
2
2
|
import { GamepadControls } from "./gamepad-controls.js";
|
|
3
|
-
import { applyGamepadDeadzone, getGamepadButtonPressed } from "./utils.js";
|
|
4
3
|
import { Matrix4, Quaternion, Vector2, Vector3 } from "three";
|
|
5
4
|
//#region src/gamepad-transform-controls.ts
|
|
6
5
|
/**
|
|
@@ -70,7 +69,6 @@ const PROJECTED_AXIS_EPSILON = .001;
|
|
|
70
69
|
var GamepadTransformControls = class extends GamepadControls {
|
|
71
70
|
#controls;
|
|
72
71
|
#options;
|
|
73
|
-
#pressedButtons;
|
|
74
72
|
#activeAxisByMode;
|
|
75
73
|
#viewSize;
|
|
76
74
|
#parentInverse;
|
|
@@ -117,7 +115,6 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
117
115
|
...DEFAULT_TRANSFORM_OPTIONS,
|
|
118
116
|
...options
|
|
119
117
|
};
|
|
120
|
-
this.#pressedButtons = /* @__PURE__ */ new Set();
|
|
121
118
|
this.#activeAxisByMode = {
|
|
122
119
|
translate: "X",
|
|
123
120
|
rotate: "X",
|
|
@@ -158,10 +155,9 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
158
155
|
* translate, rotate, scale, and reset behavior.
|
|
159
156
|
*
|
|
160
157
|
* @param deltaTime - Seconds since the last frame.
|
|
161
|
-
* @param gamepad - Fresh gamepad snapshot provided by the base class.
|
|
162
158
|
*/
|
|
163
|
-
onUpdate(deltaTime
|
|
164
|
-
const startedButtons = this.#getStartedButtons(
|
|
159
|
+
onUpdate(deltaTime) {
|
|
160
|
+
const startedButtons = this.#getStartedButtons();
|
|
165
161
|
this.#handleModeAndAxisButtons(startedButtons);
|
|
166
162
|
if (startedButtons.has(this.#options.buttonReset)) this.#resetActiveTransform();
|
|
167
163
|
const controls = this.#controls;
|
|
@@ -173,8 +169,8 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
173
169
|
this.#endTransform(true);
|
|
174
170
|
return;
|
|
175
171
|
}
|
|
176
|
-
const transformX =
|
|
177
|
-
const transformY =
|
|
172
|
+
const transformX = this.gamepadInput.axis(this.#options.axisTransformX, { deadzone: this.#options.deadzone });
|
|
173
|
+
const transformY = this.gamepadInput.axis(this.#options.axisTransformY, { deadzone: this.#options.deadzone });
|
|
178
174
|
if (transformX === 0 && transformY === 0) {
|
|
179
175
|
this.#endTransform(false);
|
|
180
176
|
return;
|
|
@@ -190,7 +186,6 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
190
186
|
*/
|
|
191
187
|
dispose() {
|
|
192
188
|
this.#endTransform(true);
|
|
193
|
-
this.#pressedButtons.clear();
|
|
194
189
|
super.dispose();
|
|
195
190
|
}
|
|
196
191
|
/**
|
|
@@ -200,9 +195,13 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
200
195
|
*/
|
|
201
196
|
onGamepadDisconnected(gamepad) {
|
|
202
197
|
this.#endTransform(true);
|
|
203
|
-
this.#pressedButtons.clear();
|
|
204
198
|
super.onGamepadDisconnected(gamepad);
|
|
205
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Applies mode, space, and axis button transitions from the current frame.
|
|
202
|
+
*
|
|
203
|
+
* @param startedButtons - Button indices that transitioned to pressed.
|
|
204
|
+
*/
|
|
206
205
|
#handleModeAndAxisButtons(startedButtons) {
|
|
207
206
|
const { buttonTranslate, buttonRotate, buttonScale, buttonToggleSpace, buttonAxisX, buttonAxisY, buttonAxisZ, buttonAxisComposite, buttonAxisPrevious, buttonAxisNext } = this.#options;
|
|
208
207
|
if (startedButtons.has(buttonTranslate)) this.#setMode("translate");
|
|
@@ -216,30 +215,57 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
216
215
|
if (startedButtons.has(buttonAxisPrevious)) this.#cycleAxis(-1);
|
|
217
216
|
if (startedButtons.has(buttonAxisNext)) this.#cycleAxis(1);
|
|
218
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Switches TransformControls mode and refreshes the active axis.
|
|
220
|
+
*
|
|
221
|
+
* @param mode - TransformControls mode to activate.
|
|
222
|
+
*/
|
|
219
223
|
#setMode(mode) {
|
|
220
224
|
if (this.#controls.mode === mode) return;
|
|
221
225
|
this.#endTransform(false);
|
|
222
226
|
this.#controls.setMode(mode);
|
|
223
227
|
this.#ensureValidAxis();
|
|
224
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Toggles TransformControls between local and world transform space.
|
|
231
|
+
*/
|
|
225
232
|
#toggleSpace() {
|
|
226
233
|
const nextSpace = this.#controls.space === "world" ? "local" : "world";
|
|
227
234
|
this.#endTransform(false);
|
|
228
235
|
this.#controls.setSpace(nextSpace);
|
|
229
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Selects an explicit axis when it is valid for the current mode.
|
|
239
|
+
*
|
|
240
|
+
* @param axis - Axis requested by the gamepad button mapping.
|
|
241
|
+
*/
|
|
230
242
|
#selectAxis(axis) {
|
|
231
243
|
if (!this.#isAxisAllowed(this.#controls.mode, axis)) return;
|
|
232
244
|
this.#endTransform(false);
|
|
233
245
|
this.#activeAxisByMode[this.#controls.mode] = axis;
|
|
234
246
|
this.#ensureValidAxis();
|
|
235
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* Cycles through composite axes available in the current mode.
|
|
250
|
+
*/
|
|
236
251
|
#cycleCompositeAxis() {
|
|
237
|
-
const validAxes = COMPOSITE_AXES[this.#controls.mode]
|
|
252
|
+
const validAxes = this.#getVisibleAxes(COMPOSITE_AXES[this.#controls.mode]);
|
|
238
253
|
this.#cycleThroughAxes(validAxes, 1);
|
|
239
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* Cycles through all valid axes for the current mode.
|
|
257
|
+
*
|
|
258
|
+
* @param direction - `1` for next axis, `-1` for previous axis.
|
|
259
|
+
*/
|
|
240
260
|
#cycleAxis(direction) {
|
|
241
261
|
this.#cycleThroughAxes(this.#getValidAxes(this.#controls.mode), direction);
|
|
242
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Moves the active axis through a candidate axis list.
|
|
265
|
+
*
|
|
266
|
+
* @param axes - Candidate axes to cycle through.
|
|
267
|
+
* @param direction - `1` for next axis, `-1` for previous axis.
|
|
268
|
+
*/
|
|
243
269
|
#cycleThroughAxes(axes, direction) {
|
|
244
270
|
if (axes.length === 0) {
|
|
245
271
|
this.#setActiveAxis(null);
|
|
@@ -252,6 +278,11 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
252
278
|
this.#activeAxisByMode[this.#controls.mode] = axes[nextIndex] ?? null;
|
|
253
279
|
this.#ensureValidAxis();
|
|
254
280
|
}
|
|
281
|
+
/**
|
|
282
|
+
* Ensures the highlighted TransformControls axis is valid and visible.
|
|
283
|
+
*
|
|
284
|
+
* @returns The active valid axis, or `null` when no axis is available.
|
|
285
|
+
*/
|
|
255
286
|
#ensureValidAxis() {
|
|
256
287
|
const mode = this.#controls.mode;
|
|
257
288
|
const current = this.#activeAxisByMode[mode];
|
|
@@ -261,16 +292,51 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
261
292
|
if (this.#controls.axis !== nextAxis) this.#controls.axis = nextAxis;
|
|
262
293
|
return nextAxis;
|
|
263
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* Updates both the remembered axis for the current mode and the control axis.
|
|
297
|
+
*
|
|
298
|
+
* @param axis - Axis to activate, or `null` to clear selection.
|
|
299
|
+
*/
|
|
264
300
|
#setActiveAxis(axis) {
|
|
265
301
|
this.#activeAxisByMode[this.#controls.mode] = axis;
|
|
266
302
|
if (this.#controls.axis !== axis) this.#controls.axis = axis;
|
|
267
303
|
}
|
|
304
|
+
/**
|
|
305
|
+
* Returns all visible axes supported by a TransformControls mode.
|
|
306
|
+
*
|
|
307
|
+
* @param mode - Mode whose axes should be inspected.
|
|
308
|
+
* @returns Visible axes for the mode.
|
|
309
|
+
*/
|
|
268
310
|
#getValidAxes(mode) {
|
|
269
|
-
return MODE_AXES[mode]
|
|
311
|
+
return this.#getVisibleAxes(MODE_AXES[mode]);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Filters a list of axes to those enabled by TransformControls visibility flags.
|
|
315
|
+
*
|
|
316
|
+
* @param axes - Axes to inspect.
|
|
317
|
+
* @returns Axes whose component visibility flags are enabled.
|
|
318
|
+
*/
|
|
319
|
+
#getVisibleAxes(axes) {
|
|
320
|
+
const visibleAxes = [];
|
|
321
|
+
for (const axis of axes) if (this.#isAxisVisible(axis)) visibleAxes.push(axis);
|
|
322
|
+
return visibleAxes;
|
|
270
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Checks whether an axis can be used in a mode and is currently visible.
|
|
326
|
+
*
|
|
327
|
+
* @param mode - TransformControls mode to validate against.
|
|
328
|
+
* @param axis - Axis to validate.
|
|
329
|
+
* @returns `true` when the axis is supported and visible.
|
|
330
|
+
*/
|
|
271
331
|
#isAxisAllowed(mode, axis) {
|
|
272
332
|
return MODE_AXES[mode].includes(axis) && this.#isAxisVisible(axis);
|
|
273
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* Reads TransformControls visibility flags for an axis or plane.
|
|
336
|
+
*
|
|
337
|
+
* @param axis - Axis whose visibility should be checked.
|
|
338
|
+
* @returns `true` when all components required by the axis are visible.
|
|
339
|
+
*/
|
|
274
340
|
#isAxisVisible(axis) {
|
|
275
341
|
const controls = this.#controls;
|
|
276
342
|
switch (axis) {
|
|
@@ -285,6 +351,11 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
285
351
|
case "E": return true;
|
|
286
352
|
}
|
|
287
353
|
}
|
|
354
|
+
/**
|
|
355
|
+
* Starts a TransformControls drag interaction for the active object and axis.
|
|
356
|
+
*
|
|
357
|
+
* @returns `true` when a transform interaction was started.
|
|
358
|
+
*/
|
|
288
359
|
#startTransform() {
|
|
289
360
|
const controls = this.#controls;
|
|
290
361
|
const object = controls.object;
|
|
@@ -298,6 +369,11 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
298
369
|
});
|
|
299
370
|
return true;
|
|
300
371
|
}
|
|
372
|
+
/**
|
|
373
|
+
* Ends an active TransformControls drag interaction.
|
|
374
|
+
*
|
|
375
|
+
* @param clearAxis - Whether to clear the highlighted axis after ending.
|
|
376
|
+
*/
|
|
301
377
|
#endTransform(clearAxis) {
|
|
302
378
|
const controls = this.#controls;
|
|
303
379
|
if (this.#isTransforming) {
|
|
@@ -310,6 +386,9 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
310
386
|
}
|
|
311
387
|
if (clearAxis) this.#setActiveAxis(null);
|
|
312
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* Resets the active object to TransformControls' captured drag start state.
|
|
391
|
+
*/
|
|
313
392
|
#resetActiveTransform() {
|
|
314
393
|
const object = this.#controls.object;
|
|
315
394
|
if (!this.#isTransforming || object === void 0) return;
|
|
@@ -320,6 +399,11 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
320
399
|
this.#freeRotationX = 0;
|
|
321
400
|
this.#freeRotationY = 0;
|
|
322
401
|
}
|
|
402
|
+
/**
|
|
403
|
+
* Captures object and control state needed to apply gamepad transforms.
|
|
404
|
+
*
|
|
405
|
+
* @param object - Object attached to TransformControls.
|
|
406
|
+
*/
|
|
323
407
|
#captureTransformStart(object) {
|
|
324
408
|
object.updateWorldMatrix(true, false);
|
|
325
409
|
object.parent?.updateWorldMatrix(true, false);
|
|
@@ -339,6 +423,11 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
339
423
|
this.#freeRotationX = 0;
|
|
340
424
|
this.#freeRotationY = 0;
|
|
341
425
|
}
|
|
426
|
+
/**
|
|
427
|
+
* Captures the attached object's parent world transform for local conversions.
|
|
428
|
+
*
|
|
429
|
+
* @param object - Object attached to TransformControls.
|
|
430
|
+
*/
|
|
342
431
|
#captureParentTransform(object) {
|
|
343
432
|
if (object.parent === null) {
|
|
344
433
|
this.#parentPosition.set(0, 0, 0);
|
|
@@ -351,6 +440,14 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
351
440
|
object.parent.matrixWorld.decompose(this.#parentPosition, this.#parentQuaternion, this.#parentScale);
|
|
352
441
|
this.#parentQuaternionInv.copy(this.#parentQuaternion).invert();
|
|
353
442
|
}
|
|
443
|
+
/**
|
|
444
|
+
* Dispatches the current stick input to the active TransformControls mode.
|
|
445
|
+
*
|
|
446
|
+
* @param deltaTime - Seconds since the last frame.
|
|
447
|
+
* @param transformX - Horizontal transform input after dead zone processing.
|
|
448
|
+
* @param transformY - Vertical transform input after dead zone processing.
|
|
449
|
+
* @returns `true` when the attached object changed.
|
|
450
|
+
*/
|
|
354
451
|
#applyCurrentTransform(deltaTime, transformX, transformY) {
|
|
355
452
|
switch (this.#controls.mode) {
|
|
356
453
|
case "translate": return this.#applyTranslate(deltaTime, transformX, transformY);
|
|
@@ -358,6 +455,14 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
358
455
|
case "scale": return this.#applyScale(deltaTime, transformX, transformY);
|
|
359
456
|
}
|
|
360
457
|
}
|
|
458
|
+
/**
|
|
459
|
+
* Applies translation in the selected axis, plane, or screen-facing plane.
|
|
460
|
+
*
|
|
461
|
+
* @param deltaTime - Seconds since the last frame.
|
|
462
|
+
* @param transformX - Horizontal transform input after dead zone processing.
|
|
463
|
+
* @param transformY - Vertical transform input after dead zone processing.
|
|
464
|
+
* @returns `true` when the attached object moved.
|
|
465
|
+
*/
|
|
361
466
|
#applyTranslate(deltaTime, transformX, transformY) {
|
|
362
467
|
const controls = this.#controls;
|
|
363
468
|
const object = controls.object;
|
|
@@ -377,6 +482,15 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
377
482
|
this.#applyAccumulatedPosition(object, axis, scale);
|
|
378
483
|
return true;
|
|
379
484
|
}
|
|
485
|
+
/**
|
|
486
|
+
* Accumulates a world-space translation delta along selected axis letters.
|
|
487
|
+
*
|
|
488
|
+
* @param axis - Transform axis or plane currently selected.
|
|
489
|
+
* @param space - Transform space used to resolve axis directions.
|
|
490
|
+
* @param transformX - Horizontal transform input after dead zone processing.
|
|
491
|
+
* @param transformY - Vertical transform input after dead zone processing.
|
|
492
|
+
* @param distance - World-space distance scale for the frame.
|
|
493
|
+
*/
|
|
380
494
|
#addAxisTranslation(axis, space, transformX, transformY, distance) {
|
|
381
495
|
for (const letter of [
|
|
382
496
|
"X",
|
|
@@ -388,6 +502,13 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
388
502
|
this.#worldDelta.addScaledVector(this.#axisWorld, this.#getProjectedAxisInput(this.#axisWorld, transformX, transformY, this.#getDominantInput(transformX, -transformY)) * distance);
|
|
389
503
|
}
|
|
390
504
|
}
|
|
505
|
+
/**
|
|
506
|
+
* Applies accumulated translation with snapping and bounds.
|
|
507
|
+
*
|
|
508
|
+
* @param object - Object attached to TransformControls.
|
|
509
|
+
* @param axis - Transform axis or plane currently selected.
|
|
510
|
+
* @param space - Transform space used for snapping.
|
|
511
|
+
*/
|
|
391
512
|
#applyAccumulatedPosition(object, axis, space) {
|
|
392
513
|
this.#snappedPosition.copy(this.#accumulatedPosition);
|
|
393
514
|
if (this.#controls.translationSnap !== null) this.#snapPosition(object, axis, space, this.#controls.translationSnap);
|
|
@@ -397,6 +518,14 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
397
518
|
object.position.copy(this.#snappedPosition);
|
|
398
519
|
object.updateMatrixWorld();
|
|
399
520
|
}
|
|
521
|
+
/**
|
|
522
|
+
* Snaps the pending position in world or local transform space.
|
|
523
|
+
*
|
|
524
|
+
* @param object - Object attached to TransformControls.
|
|
525
|
+
* @param axis - Axis letters that should be snapped.
|
|
526
|
+
* @param space - Transform space used for snapping.
|
|
527
|
+
* @param snap - Snap interval.
|
|
528
|
+
*/
|
|
400
529
|
#snapPosition(object, axis, space, snap) {
|
|
401
530
|
if (snap <= 0) return;
|
|
402
531
|
if (space === "world") {
|
|
@@ -418,6 +547,14 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
418
547
|
]) if (axis.includes(letter)) this.#setVectorComponent(this.#snappedPosition, letter, this.#snapValue(this.#getVectorComponent(this.#snappedPosition, letter), snap));
|
|
419
548
|
this.#snappedPosition.applyQuaternion(this.#quaternionStart);
|
|
420
549
|
}
|
|
550
|
+
/**
|
|
551
|
+
* Applies rotation for the selected axis or free-rotation mode.
|
|
552
|
+
*
|
|
553
|
+
* @param deltaTime - Seconds since the last frame.
|
|
554
|
+
* @param transformX - Horizontal transform input after dead zone processing.
|
|
555
|
+
* @param transformY - Vertical transform input after dead zone processing.
|
|
556
|
+
* @returns `true` when the attached object rotated.
|
|
557
|
+
*/
|
|
421
558
|
#applyRotate(deltaTime, transformX, transformY) {
|
|
422
559
|
const controls = this.#controls;
|
|
423
560
|
const object = controls.object;
|
|
@@ -450,11 +587,23 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
450
587
|
object.updateMatrixWorld();
|
|
451
588
|
return true;
|
|
452
589
|
}
|
|
590
|
+
/**
|
|
591
|
+
* Applies a rotation around a world-space axis while preserving local parent space.
|
|
592
|
+
*
|
|
593
|
+
* @param object - Object attached to TransformControls.
|
|
594
|
+
* @param worldAxis - World-space axis to rotate around.
|
|
595
|
+
* @param angle - Rotation amount in radians from the drag start.
|
|
596
|
+
*/
|
|
453
597
|
#applyWorldRotation(object, worldAxis, angle) {
|
|
454
598
|
this.#axisLocal.copy(worldAxis).applyQuaternion(this.#parentQuaternionInv).normalize();
|
|
455
599
|
this.#rotationQuaternion.setFromAxisAngle(this.#axisLocal, angle);
|
|
456
600
|
object.quaternion.copy(this.#rotationQuaternion).multiply(this.#quaternionStart).normalize();
|
|
457
601
|
}
|
|
602
|
+
/**
|
|
603
|
+
* Applies screen-relative free rotation from accumulated stick input.
|
|
604
|
+
*
|
|
605
|
+
* @param object - Object attached to TransformControls.
|
|
606
|
+
*/
|
|
458
607
|
#applyFreeRotation(object) {
|
|
459
608
|
const angleX = this.#snapRotation(this.#freeRotationX);
|
|
460
609
|
const angleY = this.#snapRotation(this.#freeRotationY);
|
|
@@ -467,6 +616,14 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
467
616
|
object.quaternion.copy(this.#rotationQuaternion2).multiply(this.#rotationQuaternion).multiply(this.#quaternionStart).normalize();
|
|
468
617
|
object.updateMatrixWorld();
|
|
469
618
|
}
|
|
619
|
+
/**
|
|
620
|
+
* Applies scale along the selected axis or uniformly across all axes.
|
|
621
|
+
*
|
|
622
|
+
* @param deltaTime - Seconds since the last frame.
|
|
623
|
+
* @param transformX - Horizontal transform input after dead zone processing.
|
|
624
|
+
* @param transformY - Vertical transform input after dead zone processing.
|
|
625
|
+
* @returns `true` when the attached object scaled.
|
|
626
|
+
*/
|
|
470
627
|
#applyScale(deltaTime, transformX, transformY) {
|
|
471
628
|
const controls = this.#controls;
|
|
472
629
|
const object = controls.object;
|
|
@@ -489,11 +646,24 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
489
646
|
object.updateMatrixWorld();
|
|
490
647
|
return true;
|
|
491
648
|
}
|
|
649
|
+
/**
|
|
650
|
+
* Projects stick input onto the selected scale axis.
|
|
651
|
+
*
|
|
652
|
+
* @param axis - Transform axis or plane currently selected.
|
|
653
|
+
* @param transformX - Horizontal transform input after dead zone processing.
|
|
654
|
+
* @param transformY - Vertical transform input after dead zone processing.
|
|
655
|
+
* @returns Signed scale input for the current frame.
|
|
656
|
+
*/
|
|
492
657
|
#getProjectedScaleInput(axis, transformX, transformY) {
|
|
493
658
|
if (axis !== "X" && axis !== "Y" && axis !== "Z") return this.#getDominantInput(transformX, -transformY);
|
|
494
659
|
this.#getTransformAxisWorld(axis, "local", this.#axisWorld);
|
|
495
660
|
return this.#getProjectedAxisInput(this.#axisWorld, transformX, transformY, this.#getDominantInput(transformX, -transformY));
|
|
496
661
|
}
|
|
662
|
+
/**
|
|
663
|
+
* Refreshes camera vectors, object world position, and viewport scale.
|
|
664
|
+
*
|
|
665
|
+
* @param object - Object attached to TransformControls.
|
|
666
|
+
*/
|
|
497
667
|
#updateCameraState(object) {
|
|
498
668
|
const camera = this.#controls.camera;
|
|
499
669
|
camera.updateMatrixWorld();
|
|
@@ -506,6 +676,11 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
506
676
|
this.#eye.copy(this.#cameraWorldPosition).sub(this.#worldPosition).normalize();
|
|
507
677
|
this.#updateViewSizeAtObjectDepth(camera);
|
|
508
678
|
}
|
|
679
|
+
/**
|
|
680
|
+
* Computes world-space viewport size at the attached object's depth.
|
|
681
|
+
*
|
|
682
|
+
* @param camera - TransformControls camera.
|
|
683
|
+
*/
|
|
509
684
|
#updateViewSizeAtObjectDepth(camera) {
|
|
510
685
|
if (this.#isOrthographicCamera(camera)) {
|
|
511
686
|
this.#viewSize.set(Math.abs(camera.right - camera.left) / camera.zoom, Math.abs(camera.top - camera.bottom) / camera.zoom);
|
|
@@ -519,16 +694,41 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
519
694
|
}
|
|
520
695
|
this.#viewSize.set(1, 1);
|
|
521
696
|
}
|
|
697
|
+
/**
|
|
698
|
+
* Resolves a transform axis letter to a normalized world-space direction.
|
|
699
|
+
*
|
|
700
|
+
* @param axis - Axis letter to resolve.
|
|
701
|
+
* @param space - Transform space used to orient the axis.
|
|
702
|
+
* @param target - Vector that receives the axis direction.
|
|
703
|
+
* @returns The normalized target vector.
|
|
704
|
+
*/
|
|
522
705
|
#getTransformAxisWorld(axis, space, target) {
|
|
523
706
|
this.#setUnitAxis(axis, target);
|
|
524
707
|
if (space === "local") target.applyQuaternion(this.#worldQuaternionStart);
|
|
525
708
|
return target.normalize();
|
|
526
709
|
}
|
|
710
|
+
/**
|
|
711
|
+
* Projects stick input onto the screen-space tangent of a rotation axis.
|
|
712
|
+
*
|
|
713
|
+
* @param axisWorld - Rotation axis in world space.
|
|
714
|
+
* @param transformX - Horizontal transform input after dead zone processing.
|
|
715
|
+
* @param transformY - Vertical transform input after dead zone processing.
|
|
716
|
+
* @returns Signed rotation input for the current frame.
|
|
717
|
+
*/
|
|
527
718
|
#getRotationAxisInput(axisWorld, transformX, transformY) {
|
|
528
719
|
this.#axisWorld2.crossVectors(axisWorld, this.#eye);
|
|
529
720
|
if (this.#axisWorld2.lengthSq() < PROJECTED_AXIS_EPSILON) return this.#getDominantInput(transformX, -transformY);
|
|
530
721
|
return this.#getProjectedAxisInput(this.#axisWorld2.normalize(), transformX, transformY, this.#getDominantInput(transformX, -transformY));
|
|
531
722
|
}
|
|
723
|
+
/**
|
|
724
|
+
* Projects two-axis stick input onto a world axis as seen by the camera.
|
|
725
|
+
*
|
|
726
|
+
* @param axisWorld - World-space axis to project onto the screen.
|
|
727
|
+
* @param transformX - Horizontal transform input after dead zone processing.
|
|
728
|
+
* @param transformY - Vertical transform input after dead zone processing.
|
|
729
|
+
* @param fallback - Value to use when the axis has no stable screen projection.
|
|
730
|
+
* @returns Signed input along the projected axis.
|
|
731
|
+
*/
|
|
532
732
|
#getProjectedAxisInput(axisWorld, transformX, transformY, fallback) {
|
|
533
733
|
const screenX = axisWorld.dot(this.#cameraRight);
|
|
534
734
|
const screenY = -axisWorld.dot(this.#cameraUp);
|
|
@@ -536,11 +736,24 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
536
736
|
if (length < PROJECTED_AXIS_EPSILON) return fallback;
|
|
537
737
|
return (transformX * screenX + transformY * screenY) / length;
|
|
538
738
|
}
|
|
739
|
+
/**
|
|
740
|
+
* Converts a world-space movement delta into the object's parent-local space.
|
|
741
|
+
*
|
|
742
|
+
* @param worldDelta - World-space delta to convert.
|
|
743
|
+
* @param target - Vector that receives the local delta.
|
|
744
|
+
* @returns The target vector containing the local delta.
|
|
745
|
+
*/
|
|
539
746
|
#worldDeltaToLocalDelta(worldDelta, target) {
|
|
540
747
|
target.copy(worldDelta).applyQuaternion(this.#parentQuaternionInv);
|
|
541
748
|
this.#divideByParentScale(target);
|
|
542
749
|
return target;
|
|
543
750
|
}
|
|
751
|
+
/**
|
|
752
|
+
* Converts a local position to world space into the reusable world position.
|
|
753
|
+
*
|
|
754
|
+
* @param object - Object whose parent space contains the local position.
|
|
755
|
+
* @param localPosition - Local position to convert.
|
|
756
|
+
*/
|
|
544
757
|
#localPositionToWorld(object, localPosition) {
|
|
545
758
|
if (object.parent === null) {
|
|
546
759
|
this.#worldPosition.copy(localPosition);
|
|
@@ -549,6 +762,12 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
549
762
|
object.parent.updateWorldMatrix(true, false);
|
|
550
763
|
this.#worldPosition.copy(localPosition).applyMatrix4(object.parent.matrixWorld);
|
|
551
764
|
}
|
|
765
|
+
/**
|
|
766
|
+
* Converts a world position to object parent-local space into snapped position.
|
|
767
|
+
*
|
|
768
|
+
* @param object - Object whose parent space should receive the result.
|
|
769
|
+
* @param worldPosition - World-space position to convert.
|
|
770
|
+
*/
|
|
552
771
|
#worldPositionToLocal(object, worldPosition) {
|
|
553
772
|
if (object.parent === null) {
|
|
554
773
|
this.#snappedPosition.copy(worldPosition);
|
|
@@ -558,11 +777,23 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
558
777
|
this.#parentInverse.copy(object.parent.matrixWorld).invert();
|
|
559
778
|
this.#snappedPosition.copy(worldPosition).applyMatrix4(this.#parentInverse);
|
|
560
779
|
}
|
|
780
|
+
/**
|
|
781
|
+
* Removes captured parent scale from a local-space delta.
|
|
782
|
+
*
|
|
783
|
+
* @param target - Vector to adjust in place.
|
|
784
|
+
*/
|
|
561
785
|
#divideByParentScale(target) {
|
|
562
786
|
target.x = this.#parentScale.x === 0 ? 0 : target.x / this.#parentScale.x;
|
|
563
787
|
target.y = this.#parentScale.y === 0 ? 0 : target.y / this.#parentScale.y;
|
|
564
788
|
target.z = this.#parentScale.z === 0 ? 0 : target.z / this.#parentScale.z;
|
|
565
789
|
}
|
|
790
|
+
/**
|
|
791
|
+
* Writes a unit axis vector into a target vector.
|
|
792
|
+
*
|
|
793
|
+
* @param axis - Axis letter to write.
|
|
794
|
+
* @param target - Vector that receives the unit axis.
|
|
795
|
+
* @returns The target vector.
|
|
796
|
+
*/
|
|
566
797
|
#setUnitAxis(axis, target) {
|
|
567
798
|
switch (axis) {
|
|
568
799
|
case "X": return target.set(1, 0, 0);
|
|
@@ -570,6 +801,13 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
570
801
|
case "Z": return target.set(0, 0, 1);
|
|
571
802
|
}
|
|
572
803
|
}
|
|
804
|
+
/**
|
|
805
|
+
* Reads one component from a vector by axis letter.
|
|
806
|
+
*
|
|
807
|
+
* @param vector - Vector to inspect.
|
|
808
|
+
* @param axis - Component axis to read.
|
|
809
|
+
* @returns The selected component value.
|
|
810
|
+
*/
|
|
573
811
|
#getVectorComponent(vector, axis) {
|
|
574
812
|
switch (axis) {
|
|
575
813
|
case "X": return vector.x;
|
|
@@ -577,6 +815,13 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
577
815
|
case "Z": return vector.z;
|
|
578
816
|
}
|
|
579
817
|
}
|
|
818
|
+
/**
|
|
819
|
+
* Writes one component on a vector by axis letter.
|
|
820
|
+
*
|
|
821
|
+
* @param vector - Vector to modify.
|
|
822
|
+
* @param axis - Component axis to write.
|
|
823
|
+
* @param value - Component value to assign.
|
|
824
|
+
*/
|
|
580
825
|
#setVectorComponent(vector, axis, value) {
|
|
581
826
|
switch (axis) {
|
|
582
827
|
case "X":
|
|
@@ -590,34 +835,85 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
590
835
|
return;
|
|
591
836
|
}
|
|
592
837
|
}
|
|
838
|
+
/**
|
|
839
|
+
* Applies TransformControls rotation snapping to an angle.
|
|
840
|
+
*
|
|
841
|
+
* @param value - Angle in radians.
|
|
842
|
+
* @returns Snapped angle, or the original angle when snapping is disabled.
|
|
843
|
+
*/
|
|
593
844
|
#snapRotation(value) {
|
|
594
845
|
const snap = this.#controls.rotationSnap;
|
|
595
846
|
return snap === null || snap <= 0 ? value : this.#snapValue(value, snap);
|
|
596
847
|
}
|
|
848
|
+
/**
|
|
849
|
+
* Snaps a numeric value to the nearest interval.
|
|
850
|
+
*
|
|
851
|
+
* @param value - Value to snap.
|
|
852
|
+
* @param snap - Snap interval.
|
|
853
|
+
* @returns Value rounded to the nearest snap interval.
|
|
854
|
+
*/
|
|
597
855
|
#snapValue(value, snap) {
|
|
598
856
|
return Math.round(value / snap) * snap;
|
|
599
857
|
}
|
|
858
|
+
/**
|
|
859
|
+
* Snaps a scale component while avoiding zero scale.
|
|
860
|
+
*
|
|
861
|
+
* @param value - Scale component to snap.
|
|
862
|
+
* @param snap - Snap interval.
|
|
863
|
+
* @returns Snapped scale component.
|
|
864
|
+
*/
|
|
600
865
|
#snapScale(value, snap) {
|
|
601
866
|
return this.#snapValue(value, snap) || snap;
|
|
602
867
|
}
|
|
868
|
+
/**
|
|
869
|
+
* Chooses the larger-magnitude stick component for ambiguous transforms.
|
|
870
|
+
*
|
|
871
|
+
* @param inputX - Horizontal input component.
|
|
872
|
+
* @param inputY - Vertical input component.
|
|
873
|
+
* @returns The input component with the larger absolute magnitude.
|
|
874
|
+
*/
|
|
603
875
|
#getDominantInput(inputX, inputY) {
|
|
604
876
|
return Math.abs(inputX) >= Math.abs(inputY) ? inputX : inputY;
|
|
605
877
|
}
|
|
606
|
-
|
|
878
|
+
/**
|
|
879
|
+
* Returns configured button indices that were newly pressed this frame.
|
|
880
|
+
*
|
|
881
|
+
* @returns Button indices that transitioned to pressed.
|
|
882
|
+
*/
|
|
883
|
+
#getStartedButtons() {
|
|
607
884
|
const startedButtons = /* @__PURE__ */ new Set();
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
885
|
+
const input = this.gamepadInput;
|
|
886
|
+
const buttons = [
|
|
887
|
+
this.#options.buttonTranslate,
|
|
888
|
+
this.#options.buttonRotate,
|
|
889
|
+
this.#options.buttonScale,
|
|
890
|
+
this.#options.buttonToggleSpace,
|
|
891
|
+
this.#options.buttonAxisX,
|
|
892
|
+
this.#options.buttonAxisY,
|
|
893
|
+
this.#options.buttonAxisZ,
|
|
894
|
+
this.#options.buttonAxisComposite,
|
|
895
|
+
this.#options.buttonAxisPrevious,
|
|
896
|
+
this.#options.buttonAxisNext,
|
|
897
|
+
this.#options.buttonReset
|
|
898
|
+
];
|
|
899
|
+
for (const button of buttons) if (input.wasPressed(button)) startedButtons.add(button);
|
|
616
900
|
return startedButtons;
|
|
617
901
|
}
|
|
902
|
+
/**
|
|
903
|
+
* Narrows a Three.js camera to `PerspectiveCamera`.
|
|
904
|
+
*
|
|
905
|
+
* @param camera - Camera to inspect.
|
|
906
|
+
* @returns `true` when the camera is perspective.
|
|
907
|
+
*/
|
|
618
908
|
#isPerspectiveCamera(camera) {
|
|
619
909
|
return camera.isPerspectiveCamera === true;
|
|
620
910
|
}
|
|
911
|
+
/**
|
|
912
|
+
* Narrows a Three.js camera to `OrthographicCamera`.
|
|
913
|
+
*
|
|
914
|
+
* @param camera - Camera to inspect.
|
|
915
|
+
* @returns `true` when the camera is orthographic.
|
|
916
|
+
*/
|
|
621
917
|
#isOrthographicCamera(camera) {
|
|
622
918
|
return camera.isOrthographicCamera === true;
|
|
623
919
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { GAMEPAD_AXIS, GAMEPAD_BUTTON, GamepadAxisKey, GamepadAxisValue, GamepadButtonKey, GamepadButtonValue } from "./core.js";
|
|
2
|
+
import { GamepadAxisOptions, GamepadInput, GamepadInputEventMap, GamepadInputOptions, GamepadStick } from "./gamepad-input.js";
|
|
2
3
|
import { GamepadControls, GamepadControlsEventMap } from "./gamepad-controls.js";
|
|
3
4
|
import { GamepadArcballControls, GamepadArcballControlsOptions } from "./gamepad-arcball-controls.js";
|
|
4
5
|
import { GamepadDragControls, GamepadDragControlsOptions } from "./gamepad-drag-controls.js";
|
|
@@ -9,4 +10,4 @@ import { GamepadMapControls } from "./gamepad-map-controls.js";
|
|
|
9
10
|
import { GamepadPointerLockControls, GamepadPointerLockControlsOptions } from "./gamepad-pointer-lock-controls.js";
|
|
10
11
|
import { GamepadTrackballControls, GamepadTrackballControlsOptions } from "./gamepad-trackball-controls.js";
|
|
11
12
|
import { GamepadTransformControls, GamepadTransformControlsOptions } from "./gamepad-transform-controls.js";
|
|
12
|
-
export { GAMEPAD_AXIS, GAMEPAD_BUTTON, GamepadArcballControls, GamepadArcballControlsOptions, GamepadAxisKey, GamepadAxisValue, GamepadButtonKey, GamepadButtonValue, GamepadControls, GamepadControlsEventMap, GamepadDragControls, GamepadDragControlsOptions, GamepadFirstPersonControls, GamepadFirstPersonControlsOptions, GamepadFlyControls, GamepadFlyControlsOptions, GamepadMapControls, GamepadOrbitControls, GamepadOrbitControlsOptions, GamepadPointerLockControls, GamepadPointerLockControlsOptions, GamepadTrackballControls, GamepadTrackballControlsOptions, GamepadTransformControls, GamepadTransformControlsOptions };
|
|
13
|
+
export { GAMEPAD_AXIS, GAMEPAD_BUTTON, GamepadArcballControls, GamepadArcballControlsOptions, GamepadAxisKey, GamepadAxisOptions, GamepadAxisValue, GamepadButtonKey, GamepadButtonValue, GamepadControls, GamepadControlsEventMap, GamepadDragControls, GamepadDragControlsOptions, GamepadFirstPersonControls, GamepadFirstPersonControlsOptions, GamepadFlyControls, GamepadFlyControlsOptions, GamepadInput, GamepadInputEventMap, GamepadInputOptions, GamepadMapControls, GamepadOrbitControls, GamepadOrbitControlsOptions, GamepadPointerLockControls, GamepadPointerLockControlsOptions, GamepadStick, GamepadTrackballControls, GamepadTrackballControlsOptions, GamepadTransformControls, GamepadTransformControlsOptions };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
|
|
2
|
+
import { GamepadInput } from "./gamepad-input.js";
|
|
2
3
|
import { GamepadControls } from "./gamepad-controls.js";
|
|
3
4
|
import { GamepadArcballControls } from "./gamepad-arcball-controls.js";
|
|
4
5
|
import { GamepadDragControls } from "./gamepad-drag-controls.js";
|
|
@@ -9,4 +10,4 @@ import { GamepadMapControls } from "./gamepad-map-controls.js";
|
|
|
9
10
|
import { GamepadPointerLockControls } from "./gamepad-pointer-lock-controls.js";
|
|
10
11
|
import { GamepadTrackballControls } from "./gamepad-trackball-controls.js";
|
|
11
12
|
import { GamepadTransformControls } from "./gamepad-transform-controls.js";
|
|
12
|
-
export { GAMEPAD_AXIS, GAMEPAD_BUTTON, GamepadArcballControls, GamepadControls, GamepadDragControls, GamepadFirstPersonControls, GamepadFlyControls, GamepadMapControls, GamepadOrbitControls, GamepadPointerLockControls, GamepadTrackballControls, GamepadTransformControls };
|
|
13
|
+
export { GAMEPAD_AXIS, GAMEPAD_BUTTON, GamepadArcballControls, GamepadControls, GamepadDragControls, GamepadFirstPersonControls, GamepadFlyControls, GamepadInput, GamepadMapControls, GamepadOrbitControls, GamepadPointerLockControls, GamepadTrackballControls, GamepadTransformControls };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "three-gamepad-controls",
|
|
3
3
|
"description": "Gamepad support for Three.js controls.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.12.0",
|
|
5
5
|
"homepage": "https://github.com/luckasnix/three-gamepad-controls#readme",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Kasnix",
|
|
@@ -51,14 +51,14 @@
|
|
|
51
51
|
"@commitlint/config-conventional": "21.0.2",
|
|
52
52
|
"@commitlint/types": "21.0.1",
|
|
53
53
|
"@types/node": "24.13.2",
|
|
54
|
-
"@types/three": "0.184.
|
|
54
|
+
"@types/three": "0.184.0",
|
|
55
55
|
"husky": "9.1.7",
|
|
56
56
|
"three": "0.184.0",
|
|
57
57
|
"tsdown": "0.22.2",
|
|
58
58
|
"typescript": "6.0.3"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
|
-
"@types/three": ">=0.184.
|
|
61
|
+
"@types/three": ">=0.184.0",
|
|
62
62
|
"three": ">=0.184.0"
|
|
63
63
|
},
|
|
64
64
|
"scripts": {
|