@rpgjs/client 5.0.0-alpha.21 → 5.0.0-alpha.23
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/dist/Game/Object.d.ts +111 -0
- package/dist/Game/TransitionManager.d.ts +56 -0
- package/dist/RpgClientEngine.d.ts +306 -9
- package/dist/components/gui/mobile/index.d.ts +8 -0
- package/dist/components/prebuilt/index.d.ts +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +14 -8
- package/dist/index.js.map +1 -1
- package/dist/index10.js +1 -1
- package/dist/index11.js +6 -5
- package/dist/index11.js.map +1 -1
- package/dist/index12.js +2 -2
- package/dist/index13.js +102 -10
- package/dist/index13.js.map +1 -1
- package/dist/index14.js +68 -9
- package/dist/index14.js.map +1 -1
- package/dist/index15.js +10 -224
- package/dist/index15.js.map +1 -1
- package/dist/index16.js +9 -97
- package/dist/index16.js.map +1 -1
- package/dist/index17.js +300 -89
- package/dist/index17.js.map +1 -1
- package/dist/index18.js +63 -80
- package/dist/index18.js.map +1 -1
- package/dist/index19.js +96 -348
- package/dist/index19.js.map +1 -1
- package/dist/index2.js +387 -21
- package/dist/index2.js.map +1 -1
- package/dist/index20.js +361 -5
- package/dist/index20.js.map +1 -1
- package/dist/index21.js +19 -50
- package/dist/index21.js.map +1 -1
- package/dist/index22.js +212 -5
- package/dist/index22.js.map +1 -1
- package/dist/index23.js +6 -395
- package/dist/index23.js.map +1 -1
- package/dist/index24.js +4 -39
- package/dist/index24.js.map +1 -1
- package/dist/index25.js +19 -20
- package/dist/index25.js.map +1 -1
- package/dist/index26.js +44 -2624
- package/dist/index26.js.map +1 -1
- package/dist/index27.js +5 -110
- package/dist/index27.js.map +1 -1
- package/dist/index28.js +394 -65
- package/dist/index28.js.map +1 -1
- package/dist/index29.js +40 -15
- package/dist/index29.js.map +1 -1
- package/dist/index3.js +3 -3
- package/dist/index30.js +21 -23
- package/dist/index30.js.map +1 -1
- package/dist/index31.js +49 -91
- package/dist/index31.js.map +1 -1
- package/dist/index32.js +2624 -32
- package/dist/index32.js.map +1 -1
- package/dist/index33.js +108 -18
- package/dist/index33.js.map +1 -1
- package/dist/index34.js +69 -3
- package/dist/index34.js.map +1 -1
- package/dist/index35.js +17 -331
- package/dist/index35.js.map +1 -1
- package/dist/index36.js +24 -24
- package/dist/index36.js.map +1 -1
- package/dist/index37.js +92 -8
- package/dist/index37.js.map +1 -1
- package/dist/index38.js +37 -7
- package/dist/index38.js.map +1 -1
- package/dist/index39.js +22 -10
- package/dist/index39.js.map +1 -1
- package/dist/index4.js +3 -3
- package/dist/index40.js +140 -6
- package/dist/index40.js.map +1 -1
- package/dist/index41.js +31 -3678
- package/dist/index41.js.map +1 -1
- package/dist/index42.js +3 -185
- package/dist/index42.js.map +1 -1
- package/dist/index43.js +172 -489
- package/dist/index43.js.map +1 -1
- package/dist/index44.js +498 -71
- package/dist/index44.js.map +1 -1
- package/dist/index45.js +331 -2
- package/dist/index45.js.map +1 -1
- package/dist/index46.js +25 -11
- package/dist/index46.js.map +1 -1
- package/dist/index47.js +70 -139
- package/dist/index47.js.map +1 -1
- package/dist/index48.js +9 -9
- package/dist/index48.js.map +1 -1
- package/dist/index49.js +6 -112
- package/dist/index49.js.map +1 -1
- package/dist/index5.js +1 -1
- package/dist/index50.js +3678 -124
- package/dist/index50.js.map +1 -1
- package/dist/index51.js +48 -131
- package/dist/index51.js.map +1 -1
- package/dist/index52.js +17 -109
- package/dist/index52.js.map +1 -1
- package/dist/index53.js +3 -138
- package/dist/index53.js.map +1 -1
- package/dist/index54.js +10 -7
- package/dist/index54.js.map +1 -1
- package/dist/index55.js +107 -48
- package/dist/index55.js.map +1 -1
- package/dist/index56.js +136 -0
- package/dist/index56.js.map +1 -0
- package/dist/index57.js +137 -0
- package/dist/index57.js.map +1 -0
- package/dist/index58.js +112 -0
- package/dist/index58.js.map +1 -0
- package/dist/index59.js +9 -0
- package/dist/index59.js.map +1 -0
- package/dist/index6.js +1 -1
- package/dist/index7.js +1 -1
- package/dist/index8.js +20 -2
- package/dist/index8.js.map +1 -1
- package/dist/index9.js +11 -27
- package/dist/index9.js.map +1 -1
- package/dist/module.d.ts +43 -4
- package/dist/services/keyboardControls.d.ts +11 -1
- package/package.json +11 -10
- package/src/Game/Object.ts +90 -8
- package/src/Game/TransitionManager.ts +75 -0
- package/src/Gui/Gui.ts +5 -31
- package/src/RpgClientEngine.ts +430 -16
- package/src/components/character.ce +212 -11
- package/src/components/gui/mobile/index.ts +24 -0
- package/src/components/gui/mobile/mobile.ce +95 -0
- package/src/components/prebuilt/index.ts +2 -0
- package/src/components/prebuilt/light-halo.ce +217 -0
- package/src/components/scenes/canvas.ce +12 -2
- package/src/components/scenes/draw-map.ce +12 -3
- package/src/components/scenes/transition.ce +60 -0
- package/src/index.ts +7 -1
- package/src/module.ts +66 -2
- package/src/services/keyboardControls.ts +14 -2
package/dist/index2.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import component from './
|
|
2
|
-
import { inject } from './
|
|
3
|
-
import { signal, bootstrapCanvas, Howl } from 'canvasengine';
|
|
4
|
-
import { WebSocketToken } from './
|
|
1
|
+
import component from './index26.js';
|
|
2
|
+
import { inject } from './index6.js';
|
|
3
|
+
import { signal, trigger, bootstrapCanvas, Howl } from 'canvasengine';
|
|
4
|
+
import { WebSocketToken } from './index27.js';
|
|
5
5
|
import { LoadMapToken } from './index7.js';
|
|
6
|
-
import { RpgSound } from './
|
|
7
|
-
import { RpgResource } from './
|
|
6
|
+
import { RpgSound } from './index18.js';
|
|
7
|
+
import { RpgResource } from './index19.js';
|
|
8
8
|
import { Direction, PredictionController, ModulesToken } from '@rpgjs/common';
|
|
9
|
-
import { load } from './
|
|
10
|
-
import { RpgClientMap } from './
|
|
9
|
+
import { load } from './index28.js';
|
|
10
|
+
import { RpgClientMap } from './index29.js';
|
|
11
11
|
import { RpgGui } from './index9.js';
|
|
12
|
-
import { AnimationManager } from './
|
|
12
|
+
import { AnimationManager } from './index30.js';
|
|
13
|
+
import { TransitionManager } from './index31.js';
|
|
13
14
|
import { lastValueFrom } from 'rxjs';
|
|
14
15
|
import { GlobalConfigToken } from './index8.js';
|
|
15
16
|
import * as PIXI from 'pixi.js';
|
|
16
17
|
import { PrebuiltComponentAnimations } from './index12.js';
|
|
17
|
-
import { KeyboardControls } from './index20.js';
|
|
18
18
|
|
|
19
19
|
class RpgClientEngine {
|
|
20
20
|
constructor(context) {
|
|
@@ -25,12 +25,17 @@ class RpgClientEngine {
|
|
|
25
25
|
this.spritesheets = /* @__PURE__ */ new Map();
|
|
26
26
|
this.sounds = /* @__PURE__ */ new Map();
|
|
27
27
|
this.componentAnimations = [];
|
|
28
|
+
this.transitions = [];
|
|
28
29
|
this.particleSettings = {
|
|
29
30
|
emitters: []
|
|
30
31
|
};
|
|
31
32
|
this.playerIdSignal = signal(null);
|
|
32
33
|
this.spriteComponentsBehind = signal([]);
|
|
33
34
|
this.spriteComponentsInFront = signal([]);
|
|
35
|
+
/** ID of the sprite that the camera should follow. null means follow the current player */
|
|
36
|
+
this.cameraFollowTargetId = signal(null);
|
|
37
|
+
/** Trigger for map shake animation */
|
|
38
|
+
this.mapShakeTrigger = trigger();
|
|
34
39
|
this.predictionEnabled = false;
|
|
35
40
|
this.SERVER_CORRECTION_THRESHOLD = 30;
|
|
36
41
|
this.inputFrameCounter = 0;
|
|
@@ -42,11 +47,11 @@ class RpgClientEngine {
|
|
|
42
47
|
this.PING_INTERVAL_MS = 5e3;
|
|
43
48
|
// Send ping every 5 seconds
|
|
44
49
|
this.lastInputTime = 0;
|
|
45
|
-
this.webSocket = inject(
|
|
46
|
-
this.guiService = inject(
|
|
47
|
-
this.loadMapService = inject(
|
|
48
|
-
this.hooks = inject(
|
|
49
|
-
this.globalConfig = inject(
|
|
50
|
+
this.webSocket = inject(WebSocketToken);
|
|
51
|
+
this.guiService = inject(RpgGui);
|
|
52
|
+
this.loadMapService = inject(LoadMapToken);
|
|
53
|
+
this.hooks = inject(ModulesToken);
|
|
54
|
+
this.globalConfig = inject(GlobalConfigToken);
|
|
50
55
|
if (!this.globalConfig) {
|
|
51
56
|
this.globalConfig = {};
|
|
52
57
|
}
|
|
@@ -100,8 +105,8 @@ class RpgClientEngine {
|
|
|
100
105
|
* ```
|
|
101
106
|
*/
|
|
102
107
|
setKeyboardControls(controlInstance) {
|
|
103
|
-
const currentValues = this.context.values["inject:"
|
|
104
|
-
this.context.values["inject:"
|
|
108
|
+
const currentValues = this.context.values["inject:KeyboardControls"];
|
|
109
|
+
this.context.values["inject:KeyboardControls"] = {
|
|
105
110
|
...currentValues,
|
|
106
111
|
values: /* @__PURE__ */ new Map([["__default__", controlInstance]])
|
|
107
112
|
};
|
|
@@ -128,6 +133,7 @@ class RpgClientEngine {
|
|
|
128
133
|
this.hooks.callHooks("client-gui-load", this).subscribe();
|
|
129
134
|
this.hooks.callHooks("client-particles-load", this).subscribe();
|
|
130
135
|
this.hooks.callHooks("client-componentAnimations-load", this).subscribe();
|
|
136
|
+
this.hooks.callHooks("client-transitions-load", this).subscribe();
|
|
131
137
|
this.hooks.callHooks("client-sprite-load", this).subscribe();
|
|
132
138
|
await lastValueFrom(this.hooks.callHooks("client-engine-onStart", this));
|
|
133
139
|
window.addEventListener("resize", () => {
|
|
@@ -164,6 +170,7 @@ class RpgClientEngine {
|
|
|
164
170
|
});
|
|
165
171
|
this.webSocket.on("changeMap", (data) => {
|
|
166
172
|
this.sceneMap.reset();
|
|
173
|
+
this.cameraFollowTargetId.set(null);
|
|
167
174
|
this.loadScene(data.mapId);
|
|
168
175
|
});
|
|
169
176
|
this.webSocket.on("showComponentAnimation", (data) => {
|
|
@@ -187,6 +194,29 @@ class RpgClientEngine {
|
|
|
187
194
|
const { soundId } = data;
|
|
188
195
|
this.stopSound(soundId);
|
|
189
196
|
});
|
|
197
|
+
this.webSocket.on("stopAllSounds", () => {
|
|
198
|
+
this.stopAllSounds();
|
|
199
|
+
});
|
|
200
|
+
this.webSocket.on("cameraFollow", (data) => {
|
|
201
|
+
const { targetId, smoothMove } = data;
|
|
202
|
+
this.setCameraFollow(targetId, smoothMove);
|
|
203
|
+
});
|
|
204
|
+
this.webSocket.on("flash", (data) => {
|
|
205
|
+
const { object, type, duration, cycles, alpha, tint } = data;
|
|
206
|
+
const sprite = object ? this.sceneMap.getObjectById(object) : void 0;
|
|
207
|
+
if (sprite && typeof sprite.flash === "function") {
|
|
208
|
+
sprite.flash({ type, duration, cycles, alpha, tint });
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
this.webSocket.on("shakeMap", (data) => {
|
|
212
|
+
const { intensity, duration, frequency, direction } = data || {};
|
|
213
|
+
this.mapShakeTrigger.start({
|
|
214
|
+
intensity,
|
|
215
|
+
duration,
|
|
216
|
+
frequency,
|
|
217
|
+
direction
|
|
218
|
+
});
|
|
219
|
+
});
|
|
190
220
|
this.webSocket.on("open", () => {
|
|
191
221
|
this.hooks.callHooks("client-engine-onConnected", this, this.socket).subscribe();
|
|
192
222
|
});
|
|
@@ -552,6 +582,64 @@ class RpgClientEngine {
|
|
|
552
582
|
console.warn(`Sound with id "${soundId}" not found or cannot be stopped`);
|
|
553
583
|
}
|
|
554
584
|
}
|
|
585
|
+
/**
|
|
586
|
+
* Stop all currently playing sounds
|
|
587
|
+
*
|
|
588
|
+
* This method stops all sounds that are currently playing.
|
|
589
|
+
* Useful when changing maps to prevent sound overlap.
|
|
590
|
+
*
|
|
591
|
+
* @example
|
|
592
|
+
* ```ts
|
|
593
|
+
* // Stop all sounds
|
|
594
|
+
* engine.stopAllSounds();
|
|
595
|
+
* ```
|
|
596
|
+
*/
|
|
597
|
+
stopAllSounds() {
|
|
598
|
+
this.sounds.forEach((sound) => {
|
|
599
|
+
if (sound && sound.stop) {
|
|
600
|
+
sound.stop();
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Set the camera to follow a specific sprite
|
|
606
|
+
*
|
|
607
|
+
* This method changes which sprite the camera viewport should follow.
|
|
608
|
+
* The camera will smoothly animate to the target sprite if smoothMove options are provided.
|
|
609
|
+
*
|
|
610
|
+
* ## Design
|
|
611
|
+
*
|
|
612
|
+
* The camera follow target is stored in a signal that is read by sprite components.
|
|
613
|
+
* Each sprite checks if it should be followed by comparing its ID with the target ID.
|
|
614
|
+
* When smoothMove options are provided, the viewport animation is handled by CanvasEngine's
|
|
615
|
+
* viewport system.
|
|
616
|
+
*
|
|
617
|
+
* @param targetId - The ID of the sprite to follow. Set to null to follow the current player
|
|
618
|
+
* @param smoothMove - Animation options. Can be a boolean (default: true) or an object with time and ease
|
|
619
|
+
* @param smoothMove.time - Duration of the animation in milliseconds (optional)
|
|
620
|
+
* @param smoothMove.ease - Easing function name from https://easings.net (optional)
|
|
621
|
+
*
|
|
622
|
+
* @example
|
|
623
|
+
* ```ts
|
|
624
|
+
* // Follow another player with default smooth animation
|
|
625
|
+
* engine.setCameraFollow(otherPlayerId, true);
|
|
626
|
+
*
|
|
627
|
+
* // Follow an event with custom smooth animation
|
|
628
|
+
* engine.setCameraFollow(eventId, {
|
|
629
|
+
* time: 1000,
|
|
630
|
+
* ease: "easeInOutQuad"
|
|
631
|
+
* });
|
|
632
|
+
*
|
|
633
|
+
* // Follow without animation (instant)
|
|
634
|
+
* engine.setCameraFollow(targetId, false);
|
|
635
|
+
*
|
|
636
|
+
* // Return to following current player
|
|
637
|
+
* engine.setCameraFollow(null);
|
|
638
|
+
* ```
|
|
639
|
+
*/
|
|
640
|
+
setCameraFollow(targetId, smoothMove) {
|
|
641
|
+
this.cameraFollowTargetId.set(targetId);
|
|
642
|
+
}
|
|
555
643
|
addParticle(particle) {
|
|
556
644
|
this.particleSettings.emitters.push(particle);
|
|
557
645
|
return particle;
|
|
@@ -560,13 +648,38 @@ class RpgClientEngine {
|
|
|
560
648
|
* Add a component to render behind sprites
|
|
561
649
|
* Components added with this method will be displayed with a lower z-index than the sprite
|
|
562
650
|
*
|
|
563
|
-
*
|
|
564
|
-
*
|
|
651
|
+
* Supports multiple formats:
|
|
652
|
+
* 1. Direct component: `ShadowComponent`
|
|
653
|
+
* 2. Configuration object: `{ component: LightHalo, props: {...} }`
|
|
654
|
+
* 3. With dynamic props: `{ component: LightHalo, props: (object) => {...} }`
|
|
655
|
+
* 4. With dependencies: `{ component: HealthBar, dependencies: (object) => [object.hp, object.param.maxHp] }`
|
|
656
|
+
*
|
|
657
|
+
* Components with dependencies will only be displayed when all dependencies are resolved (!= undefined).
|
|
658
|
+
* The object (sprite) is passed to the dependencies function to allow sprite-specific dependency resolution.
|
|
659
|
+
*
|
|
660
|
+
* @param component - The component to add behind sprites, or a configuration object
|
|
661
|
+
* @param component.component - The component function to render
|
|
662
|
+
* @param component.props - Static props object or function that receives the sprite object and returns props
|
|
663
|
+
* @param component.dependencies - Function that receives the sprite object and returns an array of Signals
|
|
664
|
+
* @returns The added component or configuration
|
|
565
665
|
*
|
|
566
666
|
* @example
|
|
567
667
|
* ```ts
|
|
568
668
|
* // Add a shadow component behind all sprites
|
|
569
669
|
* engine.addSpriteComponentBehind(ShadowComponent);
|
|
670
|
+
*
|
|
671
|
+
* // Add a component with static props
|
|
672
|
+
* engine.addSpriteComponentBehind({
|
|
673
|
+
* component: LightHalo,
|
|
674
|
+
* props: { radius: 30 }
|
|
675
|
+
* });
|
|
676
|
+
*
|
|
677
|
+
* // Add a component with dynamic props and dependencies
|
|
678
|
+
* engine.addSpriteComponentBehind({
|
|
679
|
+
* component: HealthBar,
|
|
680
|
+
* props: (object) => ({ hp: object.hp(), maxHp: object.param.maxHp() }),
|
|
681
|
+
* dependencies: (object) => [object.hp, object.param.maxHp]
|
|
682
|
+
* });
|
|
570
683
|
* ```
|
|
571
684
|
*/
|
|
572
685
|
addSpriteComponentBehind(component) {
|
|
@@ -577,13 +690,38 @@ class RpgClientEngine {
|
|
|
577
690
|
* Add a component to render in front of sprites
|
|
578
691
|
* Components added with this method will be displayed with a higher z-index than the sprite
|
|
579
692
|
*
|
|
580
|
-
*
|
|
581
|
-
*
|
|
693
|
+
* Supports multiple formats:
|
|
694
|
+
* 1. Direct component: `HealthBarComponent`
|
|
695
|
+
* 2. Configuration object: `{ component: StatusIndicator, props: {...} }`
|
|
696
|
+
* 3. With dynamic props: `{ component: HealthBar, props: (object) => {...} }`
|
|
697
|
+
* 4. With dependencies: `{ component: HealthBar, dependencies: (object) => [object.hp, object.param.maxHp] }`
|
|
698
|
+
*
|
|
699
|
+
* Components with dependencies will only be displayed when all dependencies are resolved (!= undefined).
|
|
700
|
+
* The object (sprite) is passed to the dependencies function to allow sprite-specific dependency resolution.
|
|
701
|
+
*
|
|
702
|
+
* @param component - The component to add in front of sprites, or a configuration object
|
|
703
|
+
* @param component.component - The component function to render
|
|
704
|
+
* @param component.props - Static props object or function that receives the sprite object and returns props
|
|
705
|
+
* @param component.dependencies - Function that receives the sprite object and returns an array of Signals
|
|
706
|
+
* @returns The added component or configuration
|
|
582
707
|
*
|
|
583
708
|
* @example
|
|
584
709
|
* ```ts
|
|
585
710
|
* // Add a health bar component in front of all sprites
|
|
586
711
|
* engine.addSpriteComponentInFront(HealthBarComponent);
|
|
712
|
+
*
|
|
713
|
+
* // Add a component with static props
|
|
714
|
+
* engine.addSpriteComponentInFront({
|
|
715
|
+
* component: StatusIndicator,
|
|
716
|
+
* props: { type: 'poison' }
|
|
717
|
+
* });
|
|
718
|
+
*
|
|
719
|
+
* // Add a component with dynamic props and dependencies
|
|
720
|
+
* engine.addSpriteComponentInFront({
|
|
721
|
+
* component: HealthBar,
|
|
722
|
+
* props: (object) => ({ hp: object.hp(), maxHp: object.param.maxHp() }),
|
|
723
|
+
* dependencies: (object) => [object.hp, object.param.maxHp]
|
|
724
|
+
* });
|
|
587
725
|
* ```
|
|
588
726
|
*/
|
|
589
727
|
addSpriteComponentInFront(component) {
|
|
@@ -650,6 +788,179 @@ class RpgClientEngine {
|
|
|
650
788
|
}
|
|
651
789
|
return componentAnimation.instance;
|
|
652
790
|
}
|
|
791
|
+
/**
|
|
792
|
+
* Add a transition to the engine
|
|
793
|
+
*
|
|
794
|
+
* Transitions are screen effects that can be displayed during scene changes,
|
|
795
|
+
* map loading, or any other moment where a visual transition is needed.
|
|
796
|
+
* They are displayed on top of the entire canvas and can have custom props
|
|
797
|
+
* that can be functions (similar to ComponentAnimation).
|
|
798
|
+
*
|
|
799
|
+
* @param transition - The transition configuration
|
|
800
|
+
* @param transition.id - Unique identifier for the transition
|
|
801
|
+
* @param transition.component - The component function to render
|
|
802
|
+
* @param transition.props - Optional props to pass to the component (can be a function)
|
|
803
|
+
* @returns The added transition configuration
|
|
804
|
+
*
|
|
805
|
+
* @example
|
|
806
|
+
* ```ts
|
|
807
|
+
* // Add a fade transition
|
|
808
|
+
* engine.addTransition({
|
|
809
|
+
* id: 'fade',
|
|
810
|
+
* component: FadeComponent
|
|
811
|
+
* });
|
|
812
|
+
*
|
|
813
|
+
* // Add a transition with props
|
|
814
|
+
* engine.addTransition({
|
|
815
|
+
* id: 'slide',
|
|
816
|
+
* component: SlideComponent,
|
|
817
|
+
* props: { direction: 'left', duration: 500 }
|
|
818
|
+
* });
|
|
819
|
+
*
|
|
820
|
+
* // Add a transition with function props
|
|
821
|
+
* engine.addTransition({
|
|
822
|
+
* id: 'custom',
|
|
823
|
+
* component: CustomTransition,
|
|
824
|
+
* props: (engine) => ({ width: engine.width(), height: engine.height() })
|
|
825
|
+
* });
|
|
826
|
+
* ```
|
|
827
|
+
*/
|
|
828
|
+
addTransition(transition) {
|
|
829
|
+
const instance = new TransitionManager();
|
|
830
|
+
this.transitions.push({
|
|
831
|
+
id: transition.id,
|
|
832
|
+
component: transition.component,
|
|
833
|
+
props: transition.props,
|
|
834
|
+
instance,
|
|
835
|
+
current: instance.current
|
|
836
|
+
});
|
|
837
|
+
return transition;
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Remove a transition from the engine
|
|
841
|
+
*
|
|
842
|
+
* Removes a transition by its ID. This will not affect any currently
|
|
843
|
+
* running transitions, only prevent new ones from being started.
|
|
844
|
+
*
|
|
845
|
+
* @param id - The unique identifier of the transition to remove
|
|
846
|
+
* @returns true if the transition was found and removed, false otherwise
|
|
847
|
+
*
|
|
848
|
+
* @example
|
|
849
|
+
* ```ts
|
|
850
|
+
* // Remove a transition
|
|
851
|
+
* engine.removeTransition('fade');
|
|
852
|
+
* ```
|
|
853
|
+
*/
|
|
854
|
+
removeTransition(id) {
|
|
855
|
+
const index = this.transitions.findIndex((transition) => transition.id === id);
|
|
856
|
+
if (index !== -1) {
|
|
857
|
+
this.transitions.splice(index, 1);
|
|
858
|
+
return true;
|
|
859
|
+
}
|
|
860
|
+
return false;
|
|
861
|
+
}
|
|
862
|
+
/**
|
|
863
|
+
* Modify an existing transition
|
|
864
|
+
*
|
|
865
|
+
* Updates the component or props of an existing transition. This will
|
|
866
|
+
* not affect any currently running transitions, only future ones.
|
|
867
|
+
*
|
|
868
|
+
* @param id - The unique identifier of the transition to modify
|
|
869
|
+
* @param updates - The updates to apply (component and/or props)
|
|
870
|
+
* @returns true if the transition was found and modified, false otherwise
|
|
871
|
+
*
|
|
872
|
+
* @example
|
|
873
|
+
* ```ts
|
|
874
|
+
* // Update transition props
|
|
875
|
+
* engine.modifyTransition('fade', {
|
|
876
|
+
* props: { duration: 2000, color: 'white' }
|
|
877
|
+
* });
|
|
878
|
+
*
|
|
879
|
+
* // Update transition component
|
|
880
|
+
* engine.modifyTransition('fade', {
|
|
881
|
+
* component: NewFadeComponent
|
|
882
|
+
* });
|
|
883
|
+
* ```
|
|
884
|
+
*/
|
|
885
|
+
modifyTransition(id, updates) {
|
|
886
|
+
const transition = this.transitions.find((transition2) => transition2.id === id);
|
|
887
|
+
if (!transition) {
|
|
888
|
+
return false;
|
|
889
|
+
}
|
|
890
|
+
if (updates.component !== void 0) {
|
|
891
|
+
transition.component = updates.component;
|
|
892
|
+
}
|
|
893
|
+
if (updates.props !== void 0) {
|
|
894
|
+
transition.props = updates.props;
|
|
895
|
+
}
|
|
896
|
+
return true;
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* Get a transition by its ID
|
|
900
|
+
*
|
|
901
|
+
* Retrieves the TransitionManager instance for a specific transition,
|
|
902
|
+
* which can be used to start the transition.
|
|
903
|
+
*
|
|
904
|
+
* @param id - The unique identifier of the transition
|
|
905
|
+
* @returns The TransitionManager instance for the transition
|
|
906
|
+
* @throws Error if the transition is not found
|
|
907
|
+
*
|
|
908
|
+
* @example
|
|
909
|
+
* ```ts
|
|
910
|
+
* // Get a transition and start it
|
|
911
|
+
* const fadeTransition = engine.getTransition('fade');
|
|
912
|
+
* fadeTransition.start({ duration: 1000 });
|
|
913
|
+
* ```
|
|
914
|
+
*/
|
|
915
|
+
getTransition(id) {
|
|
916
|
+
const transition = this.transitions.find((transition2) => transition2.id === id);
|
|
917
|
+
if (!transition) {
|
|
918
|
+
throw new Error(`Transition with id ${id} not found`);
|
|
919
|
+
}
|
|
920
|
+
return transition.instance;
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Start a transition
|
|
924
|
+
*
|
|
925
|
+
* Convenience method to start a transition by its ID. This combines
|
|
926
|
+
* getTransition and start into a single call. The transition will
|
|
927
|
+
* automatically receive an onFinish callback to remove itself when done.
|
|
928
|
+
*
|
|
929
|
+
* @param id - The unique identifier of the transition to start
|
|
930
|
+
* @param props - Additional props to pass to the transition component
|
|
931
|
+
* @returns The created transition object
|
|
932
|
+
*
|
|
933
|
+
* @example
|
|
934
|
+
* ```ts
|
|
935
|
+
* // Start a fade transition
|
|
936
|
+
* engine.startTransition('fade', { duration: 1000, color: 'black' });
|
|
937
|
+
*
|
|
938
|
+
* // Start with onFinish callback
|
|
939
|
+
* engine.startTransition('fade', {
|
|
940
|
+
* duration: 1000,
|
|
941
|
+
* onFinish: () => console.log('Fade complete')
|
|
942
|
+
* });
|
|
943
|
+
* ```
|
|
944
|
+
*/
|
|
945
|
+
startTransition(id, props = {}) {
|
|
946
|
+
const transition = this.transitions.find((t) => t.id === id);
|
|
947
|
+
if (!transition) {
|
|
948
|
+
throw new Error(`Transition with id ${id} not found`);
|
|
949
|
+
}
|
|
950
|
+
let baseProps = {};
|
|
951
|
+
if (transition.props) {
|
|
952
|
+
if (typeof transition.props === "function") {
|
|
953
|
+
baseProps = transition.props(this);
|
|
954
|
+
} else {
|
|
955
|
+
baseProps = transition.props;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
const finalProps = {
|
|
959
|
+
...baseProps,
|
|
960
|
+
...props
|
|
961
|
+
};
|
|
962
|
+
return transition.instance.start(finalProps);
|
|
963
|
+
}
|
|
653
964
|
async processInput({ input }) {
|
|
654
965
|
const timestamp = Date.now();
|
|
655
966
|
let frame;
|
|
@@ -756,6 +1067,61 @@ class RpgClientEngine {
|
|
|
756
1067
|
this.frameOffset = 0;
|
|
757
1068
|
this.inputFrameCounter = 0;
|
|
758
1069
|
}
|
|
1070
|
+
/**
|
|
1071
|
+
* Trigger a flash animation on a sprite
|
|
1072
|
+
*
|
|
1073
|
+
* This method allows you to trigger a flash effect on any sprite from client-side code.
|
|
1074
|
+
* The flash can be configured with various options including type (alpha, tint, or both),
|
|
1075
|
+
* duration, cycles, and color.
|
|
1076
|
+
*
|
|
1077
|
+
* ## Design
|
|
1078
|
+
*
|
|
1079
|
+
* The flash is applied directly to the sprite object using its flash trigger.
|
|
1080
|
+
* This is useful for client-side visual feedback, UI interactions, or local effects
|
|
1081
|
+
* that don't need to be synchronized with the server.
|
|
1082
|
+
*
|
|
1083
|
+
* @param spriteId - The ID of the sprite to flash. If not provided, flashes the current player
|
|
1084
|
+
* @param options - Flash configuration options
|
|
1085
|
+
* @param options.type - Type of flash effect: 'alpha' (opacity), 'tint' (color), or 'both' (default: 'alpha')
|
|
1086
|
+
* @param options.duration - Duration of the flash animation in milliseconds (default: 300)
|
|
1087
|
+
* @param options.cycles - Number of flash cycles (flash on/off) (default: 1)
|
|
1088
|
+
* @param options.alpha - Alpha value when flashing, from 0 to 1 (default: 0.3)
|
|
1089
|
+
* @param options.tint - Tint color when flashing as hex value or color name (default: 0xffffff - white)
|
|
1090
|
+
*
|
|
1091
|
+
* @example
|
|
1092
|
+
* ```ts
|
|
1093
|
+
* // Flash the current player with default settings
|
|
1094
|
+
* engine.flash();
|
|
1095
|
+
*
|
|
1096
|
+
* // Flash a specific sprite with red tint
|
|
1097
|
+
* engine.flash('sprite-id', { type: 'tint', tint: 0xff0000 });
|
|
1098
|
+
*
|
|
1099
|
+
* // Flash with both alpha and tint for dramatic effect
|
|
1100
|
+
* engine.flash(undefined, {
|
|
1101
|
+
* type: 'both',
|
|
1102
|
+
* alpha: 0.5,
|
|
1103
|
+
* tint: 0xff0000,
|
|
1104
|
+
* duration: 200,
|
|
1105
|
+
* cycles: 2
|
|
1106
|
+
* });
|
|
1107
|
+
*
|
|
1108
|
+
* // Quick damage flash on current player
|
|
1109
|
+
* engine.flash(undefined, {
|
|
1110
|
+
* type: 'tint',
|
|
1111
|
+
* tint: 'red',
|
|
1112
|
+
* duration: 150,
|
|
1113
|
+
* cycles: 1
|
|
1114
|
+
* });
|
|
1115
|
+
* ```
|
|
1116
|
+
*/
|
|
1117
|
+
flash(spriteId, options) {
|
|
1118
|
+
const targetId = spriteId || this.playerId;
|
|
1119
|
+
if (!targetId) return;
|
|
1120
|
+
const sprite = this.sceneMap.getObjectById(targetId);
|
|
1121
|
+
if (sprite && typeof sprite.flash === "function") {
|
|
1122
|
+
sprite.flash(options);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
759
1125
|
applyServerAck(ack) {
|
|
760
1126
|
if (this.predictionEnabled && this.prediction) {
|
|
761
1127
|
this.prediction.applyServerAck({
|