canvasengine 2.0.0-beta.34 → 2.0.0-beta.35

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.
@@ -1,6 +1,4 @@
1
- import { Directive, registerDirective } from "../engine/directive";
2
- import { Element } from "../engine/reactive";
3
- import { fps2ms } from "../engine/utils";
1
+ import { ControlsBase, ControlOptions, Controls, BoundKey } from "./ControlsBase";
4
2
 
5
3
  export enum Input {
6
4
  Break = 'break',
@@ -144,19 +142,8 @@ export enum Input {
144
142
  Altgr = 'altgr'
145
143
  }
146
144
 
147
- export interface ControlOptions {
148
- repeat?: boolean;
149
- bind: string | string[];
150
- keyUp?: Function;
151
- keyDown?: Function;
152
- delay?: number | {
153
- duration: number;
154
- otherControls?: (string)[];
155
- };
156
- }
157
- export interface Controls {
158
- [controlName: string]: ControlOptions;
159
- }
145
+ // Re-export for backward compatibility
146
+ export type { ControlOptions, Controls, BoundKey };
160
147
 
161
148
  // keyboard handling
162
149
  const keyCodeTable = {
@@ -335,24 +322,35 @@ const inverse = (obj) => {
335
322
 
336
323
  const inverseKeyCodeTable = inverse(keyCodeTable)
337
324
 
338
- type BoundKey = { actionName: string, options: ControlOptions, parameters?: any }
339
-
340
- export class KeyboardControls extends Directive {
325
+ /**
326
+ * Keyboard input controls implementation
327
+ *
328
+ * Handles keyboard input events and maps them to control actions.
329
+ * Supports composite directions (diagonal movement) and key repeat functionality.
330
+ *
331
+ * @example
332
+ * ```ts
333
+ * const keyboardControls = new KeyboardControls();
334
+ * keyboardControls.setInputs({
335
+ * up: {
336
+ * repeat: true,
337
+ * bind: Input.Up,
338
+ * keyDown() {
339
+ * console.log('Up pressed');
340
+ * }
341
+ * }
342
+ * });
343
+ * keyboardControls.start();
344
+ * ```
345
+ */
346
+ export class KeyboardControls extends ControlsBase {
341
347
  private keyState: {
342
348
  [keyName: string]: {
343
349
  isDown: boolean,
344
350
  count: number
345
351
  } | null
346
352
  } = {}
347
- private boundKeys: {
348
- [keyName: string]: BoundKey
349
- } = {}
350
- private stop: boolean = false
351
353
  private lastKeyPressed: number | null = null
352
- private _controlsOptions: Controls = {}
353
- private interval: any
354
- // TODO: This should be dynamic
355
- private serverFps: number = 60
356
354
  private directionState: {
357
355
  up: boolean,
358
356
  down: boolean,
@@ -365,31 +363,26 @@ export class KeyboardControls extends Directive {
365
363
  right: false
366
364
  };
367
365
 
368
- onInit(element: Element) {
369
- const value = element.props.controls.value ?? element.props.controls
370
- if (!value) return
371
- this.setupListeners();
372
- this.setInputs(value)
373
- // The processing is outside the rendering loop because if the FPS are lower (or higher) then the sending to the server would be slower or faster. Here it is constant
374
- this.interval = setInterval(() => {
375
- this.preStep()
376
- }, fps2ms(this.serverFps ?? 60))
377
- }
378
-
379
- onMount(element: Element) {}
380
-
381
- onUpdate(props) {
382
- this.setInputs(props)
366
+ /**
367
+ * Setup keyboard event listeners
368
+ */
369
+ protected setupListeners(): void {
370
+ document.addEventListener('keydown', (e) => { this.onKeyChange(e, true); });
371
+ document.addEventListener('keyup', (e) => { this.onKeyChange(e, false); });
383
372
  }
384
373
 
385
- onDestroy() {
386
- clearInterval(this.interval)
374
+ /**
375
+ * Cleanup keyboard event listeners
376
+ */
377
+ protected cleanup(): void {
387
378
  document.removeEventListener('keydown', (e) => { this.onKeyChange(e, true); });
388
379
  document.removeEventListener('keyup', (e) => { this.onKeyChange(e, false); });
389
380
  }
390
381
 
391
- /** @internal */
392
- preStep() {
382
+ /**
383
+ * Process keyboard inputs each step
384
+ */
385
+ protected preStep() {
393
386
  if (this.stop) return;
394
387
 
395
388
  const direction = this.getDirection();
@@ -411,40 +404,31 @@ export class KeyboardControls extends Directive {
411
404
  }
412
405
  }
413
406
 
414
- private applyInput(keyName: string) {
407
+ /**
408
+ * Apply input for a keyboard key
409
+ * Overrides base implementation to handle key state and repeat logic
410
+ */
411
+ protected applyInput(keyName: string) {
415
412
  const keyState = this.keyState[keyName];
416
413
  if (!keyState) return;
417
414
  const { isDown, count } = keyState;
418
415
  if (isDown) {
419
- const { repeat, keyDown } = this.boundKeys[keyName].options;
416
+ const boundKey = this.boundKeys[keyName];
417
+ if (!boundKey) return;
418
+ const { repeat, keyDown } = boundKey.options;
420
419
  if ((repeat || count == 0)) {
421
- let parameters = this.boundKeys[keyName].parameters;
420
+ let parameters = boundKey.parameters;
422
421
  if (typeof parameters === "function") {
423
422
  parameters = parameters();
424
423
  }
425
424
  if (keyDown) {
426
- keyDown(this.boundKeys[keyName]);
425
+ keyDown(boundKey);
427
426
  }
428
427
  this.keyState[keyName]!.count++;
429
428
  }
430
429
  }
431
430
  }
432
431
 
433
- private setupListeners() {
434
- document.addEventListener('keydown', (e) => { this.onKeyChange(e, true); });
435
- document.addEventListener('keyup', (e) => { this.onKeyChange(e, false); });
436
- }
437
-
438
- private bindKey(keys: Input | Input[], actionName: string, options: ControlOptions, parameters?: object) {
439
- if (!Array.isArray(keys)) keys = [keys] as Input[]
440
- const keyOptions = Object.assign({
441
- repeat: false
442
- }, options);
443
- (keys as Input[]).forEach(keyName => {
444
- this.boundKeys[keyName] = { actionName, options: keyOptions, parameters }
445
- })
446
- }
447
-
448
432
  private applyKeyDown(name: string) {
449
433
  const code = inverseKeyCodeTable[name]
450
434
  const e: any = new Event('keydown')
@@ -534,65 +518,23 @@ export class KeyboardControls extends Directive {
534
518
  }
535
519
 
536
520
  /**
537
- * From the name of the entry, we retrieve the control information
538
- *
539
- * ```ts
540
- * import { Input, inject, KeyboardControls } from '@rpgjs/client'
541
- *
542
- * const controls = inject(KeyboardControls)
543
- * controls.getControl(Input.Enter)
544
-
545
- * if (control) {
546
- * console.log(control.actionName) // action
547
- * }
548
- * ```
549
- * @title Get Control
550
- * @method getControl(inputName)
551
- * @param {string} inputName
552
- * @returns { { actionName: string, options: any } | undefined }
553
- * @memberof KeyboardControls
554
- */
555
- getControl(inputName: string): BoundKey | undefined {
556
- return this.boundKeys[inputName]
557
- }
558
-
559
- /**
560
- * Returns all controls
561
- *
562
- * @method getControls()
563
- * @since 4.2.0
564
- * @returns { { [key: string]: BoundKey } }
565
- * @memberof KeyboardControls
566
- */
567
- getControls(): { [key: string]: BoundKey } {
568
- return this.boundKeys
569
- }
570
-
571
- /**
572
- * Triggers an input according to the name of the control
573
- *
574
- * ```ts
575
- * import { Control, inject, KeyboardControls } from '@rpgjs/client'
521
+ * Apply a control action programmatically
522
+ * Triggers keyboard events to simulate key presses
576
523
  *
577
- * const controls = inject(KeyboardControls)
578
- * controls.applyControl(Control.Action)
579
- * ```
580
- *
581
- * You can put a second parameter or indicate on whether the key is pressed or released
524
+ * @param controlName - Name of the control
525
+ * @param isDown - Whether the key is pressed (true) or released (false)
526
+ * @returns Promise that resolves when the action is complete
527
+ * @example
528
+ * ```ts
529
+ * // Press a key
530
+ * await keyboardControls.applyControl('action', true);
582
531
  *
583
- * ```ts
584
- * import { Control, inject, KeyboardControls } from '@rpgjs/client'
532
+ * // Release a key
533
+ * await keyboardControls.applyControl('action', false);
585
534
  *
586
- * const controls = inject(KeyboardControls)
587
- * controls.applyControl(Control.Up, true) // keydown
588
- * controls.applyControl(Control.Up, false) // keyup
535
+ * // Press and release (default)
536
+ * await keyboardControls.applyControl('action');
589
537
  * ```
590
- * @title Apply Control
591
- * @method applyControl(controlName,isDown)
592
- * @param {string} controlName
593
- * @param {boolean} [isDown]
594
- * @returns {Promise<void>}
595
- * @memberof KeyboardControls
596
538
  */
597
539
  async applyControl(controlName: string | number, isDown?: boolean | undefined): Promise<void> {
598
540
  const control = this._controlsOptions[controlName]
@@ -611,314 +553,12 @@ export class KeyboardControls extends Directive {
611
553
  }
612
554
 
613
555
  /**
614
- * Stop listening to the inputs. Pressing a key won't do anything
615
- *
616
- * @title Stop Inputs
617
- * @method stopInputs()
618
- * @returns {void}
619
- * @memberof KeyboardControls
620
- */
621
- stopInputs() {
622
- this.stop = true
623
- }
624
-
625
- /**
626
- * Listen to the inputs again
627
- *
628
- * @title Listen Inputs
629
- * @method listenInputs()
630
- * @returns {void}
631
- * @memberof KeyboardControls
556
+ * Resume listening to inputs after stopInputs() was called
557
+ * Also resets keyboard state
632
558
  */
633
559
  listenInputs() {
634
- this.stop = false
560
+ super.listenInputs();
635
561
  this.keyState = {}
636
562
  }
637
563
 
638
- /**
639
- * Assign custom inputs to the scene
640
- *
641
- * The object is the following:
642
- *
643
- * * the key of the object is the name of the control. Either it is existing controls (Up, Dow, Left, Right, Action, Back) or customized controls
644
- * * The value is an object representing control information:
645
- * * repeat {boolean} The key can be held down to repeat the action. (false by default)
646
- * * bind {string | string[]} To which key is linked the control
647
- * * method {Function} Function to be triggered. If you do not set this property, the name of the control is sent directly to the server.
648
- * * delay {object|number} (since v3.2.0) Indicates how long (in milliseconds) the player can press the key again to perform the action
649
- * * delay.duration
650
- * * delay.otherControls {string | string[]} Indicates the other controls that will also have the delay at the same time
651
- *
652
- * ```ts
653
- * import { Control, Input, inject, KeyboardControls } from '@rpgjs/client'
654
- *
655
- * const controls = inject(KeyboardControls)
656
- * controls.setInputs({
657
- [Control.Up]: {
658
- repeat: true,
659
- bind: Input.Up
660
- },
661
- [Control.Down]: {
662
- repeat: true,
663
- bind: Input.Down
664
- },
665
- [Control.Right]: {
666
- repeat: true,
667
- bind: Input.Right
668
- },
669
- [Control.Left]: {
670
- repeat: true,
671
- bind: Input.Left
672
- },
673
- [Control.Action]: {
674
- bind: [Input.Space, Input.Enter]
675
- },
676
- [Control.Back]: {
677
- bind: Input.Escape
678
- },
679
-
680
- // The myscustom1 control is sent to the server when the A key is pressed.
681
- mycustom1: {
682
- bind: Input.A
683
- },
684
-
685
- // the myAction method is executed when the B key is pressed
686
- mycustom2: {
687
- bind: Input.B,
688
- method({ actionName }) {
689
- console.log('cool', actionName)
690
- }
691
- },
692
-
693
- // The player can redo the action after 400ms
694
- mycustom3: {
695
- bind: Input.C,
696
- delay: 400 // ms
697
- },
698
-
699
- // The player can redo the action (mycustom4) and the directions after 400ms
700
- mycustom4: {
701
- bind: Input.C,
702
- delay: {
703
- duration: 400,
704
- otherControls: [Control.Up, Control.Down, Control.Left, Control.Right]
705
- }
706
- }
707
- })
708
- *
709
- * ```
710
- * @enum {string} Control
711
- *
712
- * Control.Up | up
713
- * Control.Down | down
714
- * Control.Left | left
715
- * Control.Right | right
716
- * Control.Action | action
717
- * Control.Back | back
718
- *
719
- * @enum {string} Mouse Event
720
- *
721
- * click | Click
722
- * dblclick | Double Click
723
- * mousedown | Mouse Down
724
- * mouseup | Mouse Up
725
- * mouseover | Mouse Over
726
- * mousemove | Mouse Move
727
- * mouseout | Mouse Out
728
- * contextmenu | Context Menu
729
- *
730
- *
731
- * @enum {string} Input
732
- *
733
- * break | Pause
734
- * backspace | Backspace / Delete
735
- * tab | Tab
736
- * clear | Clear
737
- * enter | Enter
738
- * shift | Shift
739
- * ctrl | Control
740
- * alt | Alt
741
- * pause/break | Pause / Break
742
- * caps lock | Caps Lock
743
- * escape | Escape
744
- * conversion | Conversion
745
- * non-conversion | Non-conversion
746
- * space | Space
747
- * page up | Page Up
748
- * page down | Page Down
749
- * end | End
750
- * home | Home
751
- * left | Left Arrow
752
- * up | Up Arrow
753
- * right | Right Arrow
754
- * down | Down Arrow
755
- * select | Select
756
- * print | Print
757
- * execute | Execute
758
- * Print Screen | Print Screen
759
- * insert | Insert
760
- * delete | Delete
761
- * n0 | 0
762
- * n1 | 1
763
- * n2 | 2
764
- * n3 | 3
765
- * n4 | 4
766
- * n5 | 5
767
- * n6 | 6
768
- * n7 | 7
769
- * n8 | 8
770
- * n9 | 9
771
- * : | Colon
772
- * semicolon (firefox), equals | Semicolon (Firefox), Equals
773
- * < | Less Than
774
- * equals (firefox) | Equals (Firefox)
775
- * ß | Eszett
776
- * @ | At
777
- * a | A
778
- * b | B
779
- * c | C
780
- * d | D
781
- * e | E
782
- * f | F
783
- * g | G
784
- * h | H
785
- * i | I
786
- * j | J
787
- * k | K
788
- * l | L
789
- * m | M
790
- * n | N
791
- * o | O
792
- * p | P
793
- * q | Q
794
- * r | R
795
- * s | S
796
- * t | T
797
- * u | U
798
- * v | V
799
- * w | W
800
- * x | X
801
- * y | Y
802
- * z | Z
803
- * Windows Key / Left ⌘ / Chromebook Search key | Windows Key / Left Command ⌘ / Chromebook Search Key
804
- * right window key | Right Windows Key
805
- * Windows Menu / Right ⌘ | Windows Menu / Right Command ⌘
806
- * numpad 0 | Numpad 0
807
- * numpad 1 | Numpad 1
808
- * numpad 2 | Numpad 2
809
- * numpad 3 | Numpad 3
810
- * numpad 4 | Numpad 4
811
- * numpad 5 | Numpad 5
812
- * numpad 6 | Numpad 6
813
- * numpad 7 | Numpad 7
814
- * numpad 8 | Numpad 8
815
- * numpad 9 | Numpad 9
816
- * multiply | Multiply
817
- * add | Add
818
- * numpad period (firefox) | Numpad Period (Firefox)
819
- * subtract | Subtract
820
- * decimal point | Decimal Point
821
- * divide | Divide
822
- * f1 | F1
823
- * f2 | F2
824
- * f3 | F3
825
- * f4 | F4
826
- * f5 | F5
827
- * f6 | F6
828
- * f7 | F7
829
- * f8 | F8
830
- * f9 | F9
831
- * f10 | F10
832
- * f11 | F11
833
- * f12 | F12
834
- * f13 | F13
835
- * f14 | F14
836
- * f15 | F15
837
- * f16 | F16
838
- * f17 | F17
839
- * f18 | F18
840
- * f19 | F19
841
- * f20 | F20
842
- * f21 | F21
843
- * f22 | F22
844
- * f23 | F23
845
- * f24 | F24
846
- * num lock | Num Lock
847
- * scroll lock | Scroll Lock
848
- * ^ | Caret
849
- * ! | Exclamation Point
850
- * # | Hash
851
- * $ | Dollar Sign
852
- * ù | Grave Accent U
853
- * page backward | Page Backward
854
- * page forward | Page Forward
855
- * closing paren (AZERTY) | Closing Parenthesis (AZERTY)
856
- * * | Asterisk
857
- * ~ + * key | Tilde + Asterisk Key
858
- * minus (firefox), mute/unmute | Minus (Firefox), Mute/Unmute
859
- * decrease volume level | Decrease Volume Level
860
- * increase volume level | Increase Volume Level
861
- * next | Next
862
- * previous | Previous
863
- * stop | Stop
864
- * play/pause | Play/Pause
865
- * e-mail | Email
866
- * mute/unmute (firefox) | Mute/Unmute (Firefox)
867
- * decrease volume level (firefox) | Decrease Volume Level (Firefox)
868
- * increase volume level (firefox) | Increase Volume Level (Firefox)
869
- * semi-colon / ñ | Semicolon / ñ
870
- * equal sign | Equal Sign
871
- * comma | Comma
872
- * dash | Dash
873
- * period | Period
874
- * forward slash / ç | Forward Slash / ç
875
- * grave accent / ñ / æ | Grave Accent / ñ / æ
876
- * ?, / or ° | ?, / or °
877
- * numpad period (chrome) | Numpad Period (Chrome)
878
- * open bracket | Open Bracket
879
- * back slash | Backslash
880
- * close bracket / å | Close Bracket / å
881
- * single quote / ø | Single Quote / ø
882
- * \` | Backtick
883
- * left or right ⌘ key (firefox) | Left or Right Command Key (Firefox)
884
- * altgr | AltGr
885
- * < /git > | < /git >
886
- * GNOME Compose Key | GNOME Compose Key
887
- * ç | ç
888
- * XF86Forward | XF86Forward
889
- * XF86Back | XF86Back
890
- * alphanumeric | Alphanumeric
891
- * hiragana/katakana | Hiragana/Katakana
892
- * half-width/full-width | Half-Width/Full-Width
893
- * kanji | Kanji
894
- * toggle touchpad | Toggle Touchpad
895
- *
896
- * @title Set Inputs
897
- * @method setInputs(inputs)
898
- * @param {object} inputs
899
- * @memberof KeyboardControls
900
- */
901
- setInputs(inputs: Controls) {
902
- if (!inputs) return
903
- this.boundKeys = {}
904
- let inputsTransformed: any = {}
905
- for (let control in inputs) {
906
- const option = inputs[control]
907
- const { bind } = option
908
- let inputsKey: any = bind
909
- if (!Array.isArray(inputsKey)) {
910
- inputsKey = [bind]
911
- }
912
- for (let input of inputsKey) {
913
- this.bindKey(input, control, option)
914
- }
915
- }
916
- this._controlsOptions = inputs
917
- }
918
-
919
- get options(): Controls {
920
- return this._controlsOptions
921
- }
922
- }
923
-
924
- registerDirective('controls', KeyboardControls)
564
+ }
@@ -1,7 +1,10 @@
1
- import './KeyboardControls'
2
- import './Scheduler'
3
- import './ViewportFollow'
1
+ export * from './ControlsBase'
2
+ export * from './KeyboardControls'
3
+ export * from './GamepadControls'
4
+ export * from './Controls'
5
+ export * from './Scheduler'
6
+ export * from './ViewportFollow'
4
7
  //import './ViewportCull'
5
- import './Sound'
6
- import './Drag'
7
- import './Transition'
8
+ export * from './Sound'
9
+ export * from './Drag'
10
+ export * from './Transition'
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- import './directives'
2
+ export * from './directives'
3
3
  export * from '@signe/reactive'
4
4
  export { Howler } from 'howler'
5
5
  export * from './components'