@gg-web-engine/mobile-controls 0.0.0-stage → 0.0.78

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.
Files changed (56) hide show
  1. package/README.md +151 -2
  2. package/dist/controls/touch-axis-control.d.ts +38 -0
  3. package/dist/controls/touch-axis-control.js +91 -0
  4. package/dist/controls/touch-button.d.ts +49 -0
  5. package/dist/controls/touch-button.js +111 -0
  6. package/dist/controls/touch-control.d.ts +76 -0
  7. package/dist/controls/touch-control.js +151 -0
  8. package/dist/controls/touch-dpad.d.ts +27 -0
  9. package/dist/controls/touch-dpad.js +61 -0
  10. package/dist/controls/touch-look-area.d.ts +35 -0
  11. package/dist/controls/touch-look-area.js +61 -0
  12. package/dist/controls/touch-stick.d.ts +37 -0
  13. package/dist/controls/touch-stick.js +71 -0
  14. package/dist/icons.d.ts +19 -0
  15. package/dist/icons.js +20 -0
  16. package/dist/index.d.ts +15 -0
  17. package/dist/index.js +15 -0
  18. package/dist/inputs/tilt.input.d.ts +40 -0
  19. package/dist/inputs/tilt.input.js +106 -0
  20. package/dist/layouts/car.layout.d.ts +31 -0
  21. package/dist/layouts/car.layout.js +99 -0
  22. package/dist/layouts/character-2d.layout.d.ts +15 -0
  23. package/dist/layouts/character-2d.layout.js +60 -0
  24. package/dist/layouts/character.layout.d.ts +25 -0
  25. package/dist/layouts/character.layout.js +87 -0
  26. package/dist/layouts/free-camera.layout.d.ts +16 -0
  27. package/dist/layouts/free-camera.layout.js +73 -0
  28. package/dist/mobile-controls-layout.d.ts +54 -0
  29. package/dist/mobile-controls-layout.js +47 -0
  30. package/dist/mobile-controls.entity.d.ts +112 -0
  31. package/dist/mobile-controls.entity.js +274 -0
  32. package/dist/styles.d.ts +16 -0
  33. package/dist/styles.js +158 -0
  34. package/package.json +68 -4
  35. package/src/controls/touch-axis-control.ts +105 -0
  36. package/src/controls/touch-button.ts +136 -0
  37. package/src/controls/touch-control.ts +204 -0
  38. package/src/controls/touch-dpad.ts +78 -0
  39. package/src/controls/touch-look-area.ts +78 -0
  40. package/src/controls/touch-stick.ts +100 -0
  41. package/src/icons.ts +23 -0
  42. package/src/index.ts +15 -0
  43. package/src/inputs/tilt.input.ts +128 -0
  44. package/src/layouts/car.layout.ts +139 -0
  45. package/src/layouts/character-2d.layout.ts +85 -0
  46. package/src/layouts/character.layout.ts +125 -0
  47. package/src/layouts/free-camera.layout.ts +103 -0
  48. package/src/mobile-controls-layout.ts +86 -0
  49. package/src/mobile-controls.entity.ts +350 -0
  50. package/src/styles.ts +160 -0
  51. package/test/helpers.ts +38 -0
  52. package/test/mobile-controls.spec.ts +204 -0
  53. package/test/tilt.input.spec.ts +95 -0
  54. package/test/touch-axis-controls.spec.ts +172 -0
  55. package/test/touch-button.spec.ts +162 -0
  56. package/tsconfig.json +12 -0
@@ -0,0 +1,15 @@
1
+ import { PlayerCharacterController2d } from '@gg-web-engine/core';
2
+ import { LayoutCustomization, MobileControlsLayoutFactory } from '../mobile-controls-layout';
3
+ export type Character2dLayoutControlId = 'move-left' | 'move-right' | 'move' | 'jump' | 'run' | 'crouch';
4
+ export type Character2dLayoutOptions = LayoutCustomization<PlayerCharacterController2d<any>, Character2dLayoutControlId> & {
5
+ /**
6
+ * How the character is moved: `'buttons'` (default) - a left and a right button, `'stick'` - an
7
+ * analog stick moving sideways.
8
+ */
9
+ movement?: 'buttons' | 'stick';
10
+ };
11
+ /**
12
+ * The built-in layout for `PlayerCharacterController2d`: left/right on the left, actions on the
13
+ * right.
14
+ */
15
+ export declare function character2dLayout(options?: Character2dLayoutOptions): MobileControlsLayoutFactory<PlayerCharacterController2d<any>>;
@@ -0,0 +1,60 @@
1
+ import { TouchButton } from '../controls/touch-button';
2
+ import { TouchStick } from '../controls/touch-stick';
3
+ import { MobileControlsIcons } from '../icons';
4
+ import { LayoutBuilder } from '../mobile-controls-layout';
5
+ /**
6
+ * The built-in layout for `PlayerCharacterController2d`: left/right on the left, actions on the
7
+ * right.
8
+ */
9
+ export function character2dLayout(options = {}) {
10
+ return (controller, context) => {
11
+ const b = new LayoutBuilder(options);
12
+ const direction = controller.directionsInput;
13
+ if ((options.movement || 'buttons') === 'buttons') {
14
+ b.add('move-left', () => new TouchButton({
15
+ id: 'move-left',
16
+ label: 'Move left',
17
+ content: b.icon('move-left', MobileControlsIcons.left),
18
+ placement: b.placement('move-left', { left: 4, bottom: 4, width: 10, height: 10 }),
19
+ }).bindDirection(direction, { x: -1 }));
20
+ b.add('move-right', () => new TouchButton({
21
+ id: 'move-right',
22
+ label: 'Move right',
23
+ content: b.icon('move-right', MobileControlsIcons.right),
24
+ placement: b.placement('move-right', { left: 16, bottom: 4, width: 10, height: 10 }),
25
+ }).bindDirection(direction, { x: 1 }));
26
+ }
27
+ else {
28
+ b.add('move', () => new TouchStick({
29
+ id: 'move',
30
+ label: 'Move',
31
+ axes: 'x',
32
+ placement: b.placement('move', { left: 4, bottom: 3 }),
33
+ }).bindDirection(direction));
34
+ }
35
+ b.add('jump', () => new TouchButton({
36
+ id: 'jump',
37
+ label: 'Jump',
38
+ content: b.icon('jump', MobileControlsIcons.jump),
39
+ placement: b.placement('jump', { right: 4, bottom: 4, width: 10, height: 10 }),
40
+ }).bindKey(controller.keyboard, controller.options.jumpKey));
41
+ b.add('run', () => new TouchButton({
42
+ id: 'run',
43
+ label: 'Run',
44
+ mode: 'toggle',
45
+ content: b.icon('run', MobileControlsIcons.run),
46
+ placement: b.placement('run', { right: 16, bottom: 4, width: 8, height: 8 }),
47
+ }).bindKey(controller.keyboard, controller.options.runKey));
48
+ b.add('crouch', () => {
49
+ var _a;
50
+ return new TouchButton({
51
+ id: 'crouch',
52
+ label: 'Crouch',
53
+ mode: ((_a = controller.character) === null || _a === void 0 ? void 0 : _a.options.crouchMode) === 'toggle' ? 'hold' : 'toggle',
54
+ content: b.icon('crouch', MobileControlsIcons.crouch),
55
+ placement: b.placement('crouch', { right: 5, bottom: 16, width: 8, height: 8 }),
56
+ }).bindKey(controller.keyboard, controller.options.crouchKey);
57
+ });
58
+ return b.finish(controller, context);
59
+ };
60
+ }
@@ -0,0 +1,25 @@
1
+ import { PlayerCharacterController } from '@gg-web-engine/core';
2
+ import { LayoutCustomization, MobileControlsLayoutFactory } from '../mobile-controls-layout';
3
+ export type CharacterLayoutControlId = 'look' | 'look-stick' | 'move' | 'jump' | 'run' | 'crouch' | 'view';
4
+ export type CharacterLayoutOptions = LayoutCustomization<PlayerCharacterController<any>, CharacterLayoutControlId> & {
5
+ /**
6
+ * How the character is moved: `'stick'` (default) - an analog stick that appears under the left
7
+ * thumb wherever it lands, `'dpad'` - a directional pad in the corner.
8
+ */
9
+ movement?: 'stick' | 'dpad';
10
+ /**
11
+ * How the view is turned: `'drag'` (default) - by dragging anywhere the other controls are not,
12
+ * `'stick'` - with a second stick on the right, `false` - not by this layout.
13
+ */
14
+ look?: 'drag' | 'stick' | false;
15
+ /**
16
+ * Multiplies the turning: of a drag, on top of the controller's `mouseSensitivity` (3 by default,
17
+ * a finger covers much less distance than a mouse), or of the look stick's speed.
18
+ */
19
+ lookSensitivity?: number;
20
+ };
21
+ /**
22
+ * The built-in layout for `PlayerCharacterController`: movement on the left, actions on the right,
23
+ * looking around by dragging over the rest of the screen.
24
+ */
25
+ export declare function characterLayout(options?: CharacterLayoutOptions): MobileControlsLayoutFactory<PlayerCharacterController<any>>;
@@ -0,0 +1,87 @@
1
+ import { TouchButton } from '../controls/touch-button';
2
+ import { TouchDPad } from '../controls/touch-dpad';
3
+ import { TouchLookArea } from '../controls/touch-look-area';
4
+ import { TouchStick } from '../controls/touch-stick';
5
+ import { MobileControlsIcons } from '../icons';
6
+ import { LayoutBuilder } from '../mobile-controls-layout';
7
+ /**
8
+ * The built-in layout for `PlayerCharacterController`: movement on the left, actions on the right,
9
+ * looking around by dragging over the rest of the screen.
10
+ */
11
+ export function characterLayout(options = {}) {
12
+ return (controller, context) => {
13
+ var _a;
14
+ const b = new LayoutBuilder(options);
15
+ const look = (_a = options.look) !== null && _a !== void 0 ? _a : 'drag';
16
+ if (look === 'drag') {
17
+ b.add('look', () => {
18
+ var _a;
19
+ return new TouchLookArea({
20
+ id: 'look',
21
+ placement: b.placement('look', { left: '0', top: '0', width: '100%', height: '100%' }),
22
+ }).bindMouse(controller.mouseInput, (_a = options.lookSensitivity) !== null && _a !== void 0 ? _a : 3);
23
+ });
24
+ }
25
+ if ((options.movement || 'stick') === 'stick') {
26
+ b.add('move', () => new TouchStick({
27
+ id: 'move',
28
+ label: 'Move',
29
+ mode: 'floating',
30
+ placement: b.placement('move', { left: '0', bottom: '0', width: '45%', height: '75%' }),
31
+ }).bindDirection(controller.directionsInput));
32
+ }
33
+ else {
34
+ b.add('move', () => new TouchDPad({
35
+ id: 'move',
36
+ label: 'Move',
37
+ placement: b.placement('move', { left: 4, bottom: 4 }),
38
+ }).bindDirection(controller.directionsInput));
39
+ }
40
+ // with a look stick in the corner the action buttons move into a row above it
41
+ const stick = look === 'stick';
42
+ if (stick) {
43
+ b.add('look-stick', () => {
44
+ var _a;
45
+ return new TouchStick({
46
+ id: 'look-stick',
47
+ label: 'Look',
48
+ placement: b.placement('look-stick', { right: 4, bottom: 3 }),
49
+ }).bindLook(controller.mouseInput, 900 * ((_a = options.lookSensitivity) !== null && _a !== void 0 ? _a : 1));
50
+ });
51
+ }
52
+ b.add('jump', () => new TouchButton({
53
+ id: 'jump',
54
+ label: 'Jump',
55
+ content: b.icon('jump', MobileControlsIcons.jump),
56
+ placement: b.placement('jump', stick ? { right: 4, bottom: 20, width: 8, height: 8 } : { right: 4, bottom: 5, width: 10, height: 10 }),
57
+ }).bindKey(controller.keyboard, controller.options.jumpKey));
58
+ b.add('run', () => new TouchButton({
59
+ id: 'run',
60
+ label: 'Run',
61
+ mode: 'toggle',
62
+ content: b.icon('run', MobileControlsIcons.run),
63
+ placement: b.placement('run', stick ? { right: 14, bottom: 20, width: 8, height: 8 } : { right: 16, bottom: 4, width: 8, height: 8 }),
64
+ }).bindKey(controller.keyboard, controller.options.runKey));
65
+ b.add('crouch', () => {
66
+ var _a;
67
+ return new TouchButton({
68
+ id: 'crouch',
69
+ label: 'Crouch',
70
+ // a crouch that lasts while its key is held gets a latching button instead of a parked finger
71
+ mode: ((_a = controller.character) === null || _a === void 0 ? void 0 : _a.options.crouchMode) === 'toggle' ? 'hold' : 'toggle',
72
+ content: b.icon('crouch', MobileControlsIcons.crouch),
73
+ placement: b.placement('crouch', stick ? { right: 24, bottom: 20, width: 8, height: 8 } : { right: 5, bottom: 17, width: 8, height: 8 }),
74
+ }).bindKey(controller.keyboard, controller.options.crouchKey);
75
+ });
76
+ const toggleViewKey = controller.options.toggleViewKey;
77
+ if (toggleViewKey) {
78
+ b.add('view', () => new TouchButton({
79
+ id: 'view',
80
+ label: 'Switch view',
81
+ content: b.icon('view', MobileControlsIcons.view),
82
+ placement: b.placement('view', { right: 4, top: 4, width: 6.5, height: 6.5 }),
83
+ }).bindKey(controller.keyboard, toggleViewKey));
84
+ }
85
+ return b.finish(controller, context);
86
+ };
87
+ }
@@ -0,0 +1,16 @@
1
+ import { FreeCameraController } from '@gg-web-engine/core';
2
+ import { LayoutCustomization, MobileControlsLayoutFactory } from '../mobile-controls-layout';
3
+ export type FreeCameraLayoutControlId = 'look' | 'look-stick' | 'move' | 'ascend' | 'descend' | 'boost';
4
+ export type FreeCameraLayoutOptions = LayoutCustomization<FreeCameraController, FreeCameraLayoutControlId> & {
5
+ /** How the camera is moved - see `CharacterLayoutOptions.movement`. `'stick'` by default. */
6
+ movement?: 'stick' | 'dpad';
7
+ /** How the camera is turned - see `CharacterLayoutOptions.look`. `'drag'` by default. */
8
+ look?: 'drag' | 'stick' | false;
9
+ /** Multiplies the turning - see `CharacterLayoutOptions.lookSensitivity`. */
10
+ lookSensitivity?: number;
11
+ };
12
+ /**
13
+ * The built-in layout for `FreeCameraController`: flying on the left, up/down/boost on the right,
14
+ * looking around by dragging over the rest of the screen.
15
+ */
16
+ export declare function freeCameraLayout(options?: FreeCameraLayoutOptions): MobileControlsLayoutFactory<FreeCameraController>;
@@ -0,0 +1,73 @@
1
+ import { TouchButton } from '../controls/touch-button';
2
+ import { TouchDPad } from '../controls/touch-dpad';
3
+ import { TouchLookArea } from '../controls/touch-look-area';
4
+ import { TouchStick } from '../controls/touch-stick';
5
+ import { MobileControlsIcons } from '../icons';
6
+ import { LayoutBuilder } from '../mobile-controls-layout';
7
+ /**
8
+ * The built-in layout for `FreeCameraController`: flying on the left, up/down/boost on the right,
9
+ * looking around by dragging over the rest of the screen.
10
+ */
11
+ export function freeCameraLayout(options = {}) {
12
+ return (controller, context) => {
13
+ var _a;
14
+ const b = new LayoutBuilder(options);
15
+ const look = (_a = options.look) !== null && _a !== void 0 ? _a : 'drag';
16
+ if (look === 'drag') {
17
+ b.add('look', () => {
18
+ var _a;
19
+ return new TouchLookArea({
20
+ id: 'look',
21
+ placement: b.placement('look', { left: '0', top: '0', width: '100%', height: '100%' }),
22
+ }).bindMouse(controller.mouseInput, (_a = options.lookSensitivity) !== null && _a !== void 0 ? _a : 3);
23
+ });
24
+ }
25
+ if ((options.movement || 'stick') === 'stick') {
26
+ b.add('move', () => new TouchStick({
27
+ id: 'move',
28
+ label: 'Move',
29
+ mode: 'floating',
30
+ placement: b.placement('move', { left: '0', bottom: '0', width: '45%', height: '75%' }),
31
+ }).bindDirection(controller.directionsInput));
32
+ }
33
+ else {
34
+ b.add('move', () => new TouchDPad({
35
+ id: 'move',
36
+ label: 'Move',
37
+ placement: b.placement('move', { left: 4, bottom: 4 }),
38
+ }).bindDirection(controller.directionsInput));
39
+ }
40
+ const stick = look === 'stick';
41
+ if (stick) {
42
+ b.add('look-stick', () => {
43
+ var _a;
44
+ return new TouchStick({
45
+ id: 'look-stick',
46
+ label: 'Look',
47
+ placement: b.placement('look-stick', { right: 4, bottom: 3 }),
48
+ }).bindLook(controller.mouseInput, 900 * ((_a = options.lookSensitivity) !== null && _a !== void 0 ? _a : 1));
49
+ });
50
+ }
51
+ // the keys `FreeCameraController` moves up/down and boosts with are fixed
52
+ b.add('ascend', () => new TouchButton({
53
+ id: 'ascend',
54
+ label: 'Up',
55
+ content: b.icon('ascend', MobileControlsIcons.up),
56
+ placement: b.placement('ascend', stick ? { right: 4, bottom: 20, width: 8, height: 8 } : { right: 4, bottom: 15, width: 9, height: 9 }),
57
+ }).bindKey(controller.keyboard, 'KeyE'));
58
+ b.add('descend', () => new TouchButton({
59
+ id: 'descend',
60
+ label: 'Down',
61
+ content: b.icon('descend', MobileControlsIcons.down),
62
+ placement: b.placement('descend', stick ? { right: 14, bottom: 20, width: 8, height: 8 } : { right: 4, bottom: 4, width: 9, height: 9 }),
63
+ }).bindKey(controller.keyboard, 'KeyQ'));
64
+ b.add('boost', () => new TouchButton({
65
+ id: 'boost',
66
+ label: 'Boost',
67
+ mode: 'toggle',
68
+ content: b.icon('boost', MobileControlsIcons.run),
69
+ placement: b.placement('boost', stick ? { right: 24, bottom: 20, width: 8, height: 8 } : { right: 15, bottom: 4, width: 8, height: 8 }),
70
+ }).bindKey(controller.keyboard, 'ShiftLeft'));
71
+ return b.finish(controller, context);
72
+ };
73
+ }
@@ -0,0 +1,54 @@
1
+ import { GgWorld, IEntity } from '@gg-web-engine/core';
2
+ import { ControlPlacement, TouchControl } from './controls/touch-control';
3
+ import type { MobileControls } from './mobile-controls.entity';
4
+ export type MobileControlsLayoutContext = {
5
+ world: GgWorld<any, any>;
6
+ /** The overlay the layout is built for. */
7
+ controls: MobileControls;
8
+ };
9
+ /**
10
+ * One piece of a layout: a `TouchControl`, or anything else that lives as long as the layout does (a
11
+ * `TiltInput` wired to the controller, a subscription) and is ended through `dispose`.
12
+ */
13
+ export type MobileControlsLayoutItem = TouchControl | {
14
+ dispose(): void;
15
+ };
16
+ /**
17
+ * Builds the on-screen controls for one controller entity, already bound to it. Called every time
18
+ * the controller becomes active; the returned items are disposed when it stops being active or
19
+ * leaves the world. The controls are stacked in the returned order, the last one on top.
20
+ */
21
+ export type MobileControlsLayoutFactory<T extends IEntity = IEntity> = (controller: T, context: MobileControlsLayoutContext) => MobileControlsLayoutItem[];
22
+ /**
23
+ * What every built-in layout lets an app adjust without replacing the layout. `Id` are the ids of
24
+ * the controls that layout can contain.
25
+ */
26
+ export type LayoutCustomization<T extends IEntity, Id extends string> = {
27
+ /** Moves/resizes a control. Merged over that control's default placement, edge by edge. */
28
+ placements?: {
29
+ [id in Id]?: ControlPlacement;
30
+ };
31
+ /** Replaces what a button shows: markup (an inline SVG, plain text) or a DOM node. */
32
+ icons?: {
33
+ [id in Id]?: string | Node;
34
+ };
35
+ /** Leaves controls out of the layout. */
36
+ hide?: Id[];
37
+ /** Adds controls of the app's own to the layout. */
38
+ extra?: MobileControlsLayoutFactory<T>;
39
+ };
40
+ /**
41
+ * Applies a `LayoutCustomization` while a built-in layout is put together.
42
+ */
43
+ export declare class LayoutBuilder<T extends IEntity, Id extends string> {
44
+ private readonly customization;
45
+ readonly result: MobileControlsLayoutItem[];
46
+ constructor(customization: LayoutCustomization<T, Id>);
47
+ /** Whether the control with this id is to be built at all. */
48
+ has(id: Id): boolean;
49
+ placement(id: Id, defaults: ControlPlacement): ControlPlacement;
50
+ icon(id: Id, defaults: string): string | Node;
51
+ /** Adds the control `create` makes, unless the app hid it. */
52
+ add(id: Id, create: () => TouchControl): void;
53
+ finish(controller: T, context: MobileControlsLayoutContext): MobileControlsLayoutItem[];
54
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Applies a `LayoutCustomization` while a built-in layout is put together.
3
+ */
4
+ export class LayoutBuilder {
5
+ constructor(customization) {
6
+ this.customization = customization;
7
+ this.result = [];
8
+ }
9
+ /** Whether the control with this id is to be built at all. */
10
+ has(id) {
11
+ return !(this.customization.hide || []).includes(id);
12
+ }
13
+ placement(id, defaults) {
14
+ var _a;
15
+ const custom = (_a = this.customization.placements) === null || _a === void 0 ? void 0 : _a[id];
16
+ if (!custom) {
17
+ return defaults;
18
+ }
19
+ // an edge given by the app takes over from the opposite default one instead of stretching between
20
+ const merged = Object.assign(Object.assign({}, defaults), custom);
21
+ if (custom.left !== undefined && custom.right === undefined)
22
+ delete merged.right;
23
+ if (custom.right !== undefined && custom.left === undefined)
24
+ delete merged.left;
25
+ if (custom.top !== undefined && custom.bottom === undefined)
26
+ delete merged.bottom;
27
+ if (custom.bottom !== undefined && custom.top === undefined)
28
+ delete merged.top;
29
+ return merged;
30
+ }
31
+ icon(id, defaults) {
32
+ var _a, _b;
33
+ return (_b = (_a = this.customization.icons) === null || _a === void 0 ? void 0 : _a[id]) !== null && _b !== void 0 ? _b : defaults;
34
+ }
35
+ /** Adds the control `create` makes, unless the app hid it. */
36
+ add(id, create) {
37
+ if (this.has(id)) {
38
+ this.result.push(create());
39
+ }
40
+ }
41
+ finish(controller, context) {
42
+ if (this.customization.extra) {
43
+ this.result.push(...this.customization.extra(controller, context));
44
+ }
45
+ return this.result;
46
+ }
47
+ }
@@ -0,0 +1,112 @@
1
+ import { GgWorld, IEntity, TickOrder } from '@gg-web-engine/core';
2
+ import { TouchControl } from './controls/touch-control';
3
+ import { CarLayoutOptions } from './layouts/car.layout';
4
+ import { Character2dLayoutOptions } from './layouts/character-2d.layout';
5
+ import { CharacterLayoutOptions } from './layouts/character.layout';
6
+ import { FreeCameraLayoutOptions } from './layouts/free-camera.layout';
7
+ import { MobileControlsLayoutFactory } from './mobile-controls-layout';
8
+ /**
9
+ * Whether the device is operated by touch first (a phone, a tablet) - what `enabled: 'auto'` goes by.
10
+ * A laptop that merely has a touch screen next to its mouse does not count.
11
+ */
12
+ export declare function isTouchFirstDevice(): boolean;
13
+ export type MobileControlsOptions = {
14
+ /**
15
+ * `'auto'` (default): the overlay exists only on a touch-first device (`isTouchFirstDevice`).
16
+ * `true`: always, e.g. to try the controls with a mouse. `false`: never.
17
+ */
18
+ enabled: boolean | 'auto';
19
+ /**
20
+ * The element the overlay is added to. `null` (default) puts it on `document.body`, covering the
21
+ * viewport - right for a game filling the page. For a canvas that takes a part of the page, or one
22
+ * that enters fullscreen through the Fullscreen API, pass an element wrapping the canvas (it has to
23
+ * be positioned, e.g. `position: relative`): the overlay then covers exactly that element.
24
+ */
25
+ container: HTMLElement | null;
26
+ /** Extra CSS class names for the overlay element, e.g. one overriding its `--gg-mc-*` properties. */
27
+ className: string;
28
+ /** Whether to add the default stylesheet to the page. `true` by default. */
29
+ injectStyles: boolean;
30
+ /**
31
+ * Options of the built-in layout for `GgCarHandlingController` and a bare
32
+ * `CarHandlingController`, or `false` to have none.
33
+ */
34
+ car: CarLayoutOptions | false;
35
+ /** Options of the built-in layout for `PlayerCharacterController`, or `false` to have none. */
36
+ character: CharacterLayoutOptions | false;
37
+ /** Options of the built-in layout for `PlayerCharacterController2d`, or `false` to have none. */
38
+ character2d: Character2dLayoutOptions | false;
39
+ /** Options of the built-in layout for `FreeCameraController`, or `false` to have none. */
40
+ freeCamera: FreeCameraLayoutOptions | false;
41
+ };
42
+ type ControllerClass<T extends IEntity> = abstract new (...args: any[]) => T;
43
+ /**
44
+ * An overlay of on-screen touch controls over the game canvas. Add it to a world once, and it shows
45
+ * the controls matching whichever input controller is active in that world at the moment, swapping
46
+ * them as controllers are activated, deactivated, spawned and removed:
47
+ *
48
+ * ```ts
49
+ * world.addEntity(new MobileControls());
50
+ * ```
51
+ *
52
+ * Out of the box it knows the car controllers (`GgCarHandlingController`,
53
+ * `CarHandlingController`), `PlayerCharacterController`, `PlayerCharacterController2d` and
54
+ * `FreeCameraController`. Each of those layouts is adjusted through
55
+ * its options (see `MobileControlsOptions`), replaced by `registerLayout`, and any other controller
56
+ * class - including an app's own - gets a layout the same way. Controls that belong to no controller
57
+ * (pause, a menu button) are added with `addControls`.
58
+ */
59
+ export declare class MobileControls extends IEntity {
60
+ static readonly entityTypeName: string;
61
+ readonly tickOrder = TickOrder.INPUT_CONTROLLERS;
62
+ readonly options: MobileControlsOptions;
63
+ /** The overlay element. Created up front, attached to the page only while the overlay is shown. */
64
+ readonly element: HTMLElement;
65
+ private readonly registrations;
66
+ private readonly tracked;
67
+ private readonly layouts;
68
+ private readonly ownControls;
69
+ private _enabled;
70
+ private _visible;
71
+ get enabled(): boolean | 'auto';
72
+ /** See `MobileControlsOptions.enabled`. */
73
+ set enabled(value: boolean | 'auto');
74
+ get visible(): boolean;
75
+ /**
76
+ * Hides the overlay without disabling it, for the moments touch controls are in the way (a menu,
77
+ * a cutscene). Everything held is released.
78
+ */
79
+ set visible(value: boolean);
80
+ /** Whether the overlay is on the page right now. */
81
+ get shown(): boolean;
82
+ /** The controllers that currently have their controls on screen. */
83
+ get activeControllers(): IEntity[];
84
+ constructor(options?: Partial<MobileControlsOptions>);
85
+ /**
86
+ * Sets the layout shown while a controller of `controllerClass` (or of a subclass) is active,
87
+ * replacing a layout registered for the same class before; `null` leaves that class without one.
88
+ * Of several registered classes a controller is an instance of, the one registered last wins.
89
+ */
90
+ registerLayout<T extends IEntity>(controllerClass: ControllerClass<T>, factory: MobileControlsLayoutFactory<T> | null): void;
91
+ /**
92
+ * Adds controls that stay on screen whichever controller is active, on top of the layouts.
93
+ */
94
+ addControls(...controls: TouchControl[]): void;
95
+ /** Removes controls added by `addControls` and disposes them. */
96
+ removeControls(...controls: TouchControl[]): void;
97
+ /**
98
+ * Builds the layout of `controller` anew - after something its layout was built from has changed
99
+ * (the car it drives, an option), since a layout is otherwise built once per activation.
100
+ */
101
+ refresh(controller?: IEntity): void;
102
+ onSpawned(world: GgWorld<any, any>): void;
103
+ onRemoved(): void;
104
+ dispose(): void;
105
+ /** Returns every control on screen to its untouched state. */
106
+ releaseAll(): void;
107
+ private findFactory;
108
+ private rescan;
109
+ private sync;
110
+ private disposeLayout;
111
+ }
112
+ export {};