@rpgjs/client 5.0.0-alpha.0 → 5.0.0-alpha.10

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 (114) hide show
  1. package/dist/Game/AnimationManager.d.ts +8 -0
  2. package/dist/RpgClient.d.ts +99 -68
  3. package/dist/RpgClientEngine.d.ts +86 -4
  4. package/dist/components/animations/index.d.ts +4 -0
  5. package/dist/components/index.d.ts +2 -1
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.js +2 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/index10.js +1 -1
  10. package/dist/index11.js +4 -4
  11. package/dist/index11.js.map +1 -1
  12. package/dist/index12.js +6 -2
  13. package/dist/index12.js.map +1 -1
  14. package/dist/index13.js +2 -2
  15. package/dist/index13.js.map +1 -1
  16. package/dist/index14.js +95 -35
  17. package/dist/index14.js.map +1 -1
  18. package/dist/index15.js +45 -186
  19. package/dist/index15.js.map +1 -1
  20. package/dist/index16.js +187 -5
  21. package/dist/index16.js.map +1 -1
  22. package/dist/index17.js +5 -383
  23. package/dist/index17.js.map +1 -1
  24. package/dist/index18.js +384 -28
  25. package/dist/index18.js.map +1 -1
  26. package/dist/index19.js +24 -17
  27. package/dist/index19.js.map +1 -1
  28. package/dist/index2.js +147 -25
  29. package/dist/index2.js.map +1 -1
  30. package/dist/index20.js +16 -2413
  31. package/dist/index20.js.map +1 -1
  32. package/dist/index21.js +2395 -88
  33. package/dist/index21.js.map +1 -1
  34. package/dist/index22.js +108 -103
  35. package/dist/index22.js.map +1 -1
  36. package/dist/index23.js +95 -57
  37. package/dist/index23.js.map +1 -1
  38. package/dist/index24.js +62 -12
  39. package/dist/index24.js.map +1 -1
  40. package/dist/index25.js +18 -37
  41. package/dist/index25.js.map +1 -1
  42. package/dist/index26.js +25 -3
  43. package/dist/index26.js.map +1 -1
  44. package/dist/index27.js +87 -314
  45. package/dist/index27.js.map +1 -1
  46. package/dist/index28.js +37 -21
  47. package/dist/index28.js.map +1 -1
  48. package/dist/index29.js +3 -9
  49. package/dist/index29.js.map +1 -1
  50. package/dist/index3.js +2 -2
  51. package/dist/index30.js +317 -6
  52. package/dist/index30.js.map +1 -1
  53. package/dist/index31.js +24 -171
  54. package/dist/index31.js.map +1 -1
  55. package/dist/index32.js +7 -497
  56. package/dist/index32.js.map +1 -1
  57. package/dist/index33.js +8 -9
  58. package/dist/index33.js.map +1 -1
  59. package/dist/index34.js +9 -4400
  60. package/dist/index34.js.map +1 -1
  61. package/dist/index35.js +4397 -85
  62. package/dist/index35.js.map +1 -1
  63. package/dist/index36.js +310 -55
  64. package/dist/index36.js.map +1 -1
  65. package/dist/index37.js +169 -15
  66. package/dist/index37.js.map +1 -1
  67. package/dist/index38.js +496 -15
  68. package/dist/index38.js.map +1 -1
  69. package/dist/index39.js +61 -0
  70. package/dist/index39.js.map +1 -0
  71. package/dist/index4.js +18 -5
  72. package/dist/index4.js.map +1 -1
  73. package/dist/index40.js +20 -0
  74. package/dist/index40.js.map +1 -0
  75. package/dist/index41.js +82 -0
  76. package/dist/index41.js.map +1 -0
  77. package/dist/index5.js +2 -1
  78. package/dist/index5.js.map +1 -1
  79. package/dist/index6.js +1 -1
  80. package/dist/index7.js +10 -2
  81. package/dist/index7.js.map +1 -1
  82. package/dist/index8.js +24 -6
  83. package/dist/index8.js.map +1 -1
  84. package/dist/index9.js +2 -2
  85. package/dist/presets/animation.d.ts +31 -0
  86. package/dist/presets/index.d.ts +102 -0
  87. package/dist/presets/lpc.d.ts +89 -0
  88. package/dist/services/loadMap.d.ts +123 -2
  89. package/dist/services/mmorpg.d.ts +7 -3
  90. package/package.json +14 -12
  91. package/src/Game/{EffectManager.ts → AnimationManager.ts} +2 -2
  92. package/src/Game/Object.ts +69 -0
  93. package/src/RpgClient.ts +101 -67
  94. package/src/RpgClientEngine.ts +159 -24
  95. package/src/components/{effects → animations}/animation.ce +3 -5
  96. package/src/components/{effects → animations}/index.ts +1 -1
  97. package/src/components/character.ce +74 -33
  98. package/src/components/index.ts +2 -1
  99. package/src/components/scenes/draw-map.ce +6 -23
  100. package/src/components/scenes/event-layer.ce +3 -3
  101. package/src/core/setup.ts +2 -0
  102. package/src/index.ts +1 -1
  103. package/src/module.ts +23 -5
  104. package/src/presets/animation.ts +46 -0
  105. package/src/presets/index.ts +5 -1
  106. package/src/presets/lpc.ts +108 -0
  107. package/src/services/loadMap.ts +131 -2
  108. package/src/services/mmorpg.ts +20 -4
  109. package/tsconfig.json +1 -1
  110. package/vite.config.ts +1 -1
  111. package/dist/Game/EffectManager.d.ts +0 -5
  112. package/dist/components/effects/index.d.ts +0 -4
  113. package/src/components/scenes/element-map.ce +0 -23
  114. /package/src/components/{effects → animations}/hit.ce +0 -0
@@ -7,10 +7,11 @@ import { Hooks, ModulesToken } from "@rpgjs/common";
7
7
  import { load } from "@signe/sync";
8
8
  import { RpgClientMap } from "./Game/Map"
9
9
  import { RpgGui } from "./Gui/Gui";
10
- import { EffectManager } from "./Game/EffectManager";
11
- import { lastValueFrom } from "rxjs";
10
+ import { AnimationManager } from "./Game/AnimationManager";
11
+ import { lastValueFrom, Observable } from "rxjs";
12
12
  import { GlobalConfigToken } from "./module";
13
- import { ClientIo } from "@signe/room";
13
+ import * as PIXI from "pixi.js";
14
+ import { PrebuiltComponentAnimations } from "./components/animations";
14
15
 
15
16
  export class RpgClientEngine<T = any> {
16
17
  private guiService: RpgGui;
@@ -22,17 +23,21 @@ export class RpgClientEngine<T = any> {
22
23
  public globalConfig: T;
23
24
  public sceneComponent: any;
24
25
  stopProcessingInput = false;
25
-
26
26
  width = signal("100%");
27
27
  height = signal("100%");
28
28
  spritesheets: Map<string, any> = new Map();
29
29
  sounds: Map<string, any> = new Map();
30
- effects: any[] = [];
30
+ componentAnimations: any[] = [];
31
31
  particleSettings: {
32
32
  emitters: any[]
33
33
  } = {
34
34
  emitters: []
35
35
  }
36
+ renderer: PIXI.Renderer;
37
+ tick: Observable<number>;
38
+ playerIdSignal = signal<string | null>(null);
39
+ spriteComponentsBehind = signal<any[]>([]);
40
+ spriteComponentsInFront = signal<any[]>([]);
36
41
 
37
42
  constructor(public context: Context) {
38
43
  this.webSocket = inject(context, WebSocketToken);
@@ -40,20 +45,37 @@ export class RpgClientEngine<T = any> {
40
45
  this.loadMapService = inject(context, LoadMapToken);
41
46
  this.hooks = inject<Hooks>(context, ModulesToken);
42
47
  this.globalConfig = inject(context, GlobalConfigToken)
48
+
49
+ this.addComponentAnimation({
50
+ id: "animation",
51
+ component: PrebuiltComponentAnimations.Animation
52
+ })
43
53
  }
44
54
 
45
55
  async start() {
46
56
  this.selector = document.body.querySelector("#rpg") as HTMLElement;
47
57
 
48
- await bootstrapCanvas(this.selector, Canvas);
58
+ const { app, canvasElement } = await bootstrapCanvas(this.selector, Canvas);
59
+ this.renderer = app.renderer as PIXI.Renderer;
60
+ this.tick = canvasElement?.propObservables?.context['tick'].observable
49
61
 
50
62
  await lastValueFrom(this.hooks.callHooks("client-engine-onStart", this));
51
63
 
64
+ // wondow is resize
65
+ window.addEventListener('resize', () => {
66
+ this.hooks.callHooks("client-engine-onWindowResize", this).subscribe();
67
+ })
68
+
69
+ this.tick.subscribe((tick) => {
70
+ this.hooks.callHooks("client-engine-onStep", this, tick).subscribe();
71
+ })
72
+
52
73
  this.hooks.callHooks("client-spritesheets-load", this).subscribe();
53
74
  this.hooks.callHooks("client-sounds-load", this).subscribe();
54
75
  this.hooks.callHooks("client-gui-load", this).subscribe();
55
76
  this.hooks.callHooks("client-particles-load", this).subscribe();
56
- this.hooks.callHooks("client-effects-load", this).subscribe();
77
+ this.hooks.callHooks("client-componentAnimations-load", this).subscribe();
78
+ this.hooks.callHooks("client-sprite-load", this).subscribe();
57
79
 
58
80
 
59
81
  await this.webSocket.connection(() => {
@@ -64,6 +86,8 @@ export class RpgClientEngine<T = any> {
64
86
 
65
87
  private initListeners() {
66
88
  this.webSocket.on("sync", (data) => {
89
+ if (data.pId) this.playerIdSignal.set(data.pId)
90
+ this.hooks.callHooks("client-sceneMap-onChanges", this.sceneMap, { partial: data }).subscribe();
67
91
  load(this.sceneMap, data, true);
68
92
  });
69
93
 
@@ -71,14 +95,32 @@ export class RpgClientEngine<T = any> {
71
95
  this.loadScene(data.mapId);
72
96
  });
73
97
 
74
- this.webSocket.on("showEffect", (data) => {
75
- const { params, object, id } = data;
76
- if (!object) {
77
- throw new Error("Object not found");
98
+ this.webSocket.on("showComponentAnimation", (data) => {
99
+ const { params, object, position, id } = data;
100
+ if (!object && position === undefined) {
101
+ throw new Error("Please provide an object or x and y coordinates");
78
102
  }
79
- const player = this.sceneMap.getObjectById(object);
80
- this.getEffect(id).displayEffect(params, player)
103
+ const player = object ? this.sceneMap.getObjectById(object) : undefined;
104
+ this.getComponentAnimation(id).displayEffect(params, player || position)
81
105
  });
106
+
107
+ this.webSocket.on("setAnimation", (data) => {
108
+ const { animationName, nbTimes, object } = data;
109
+ const player = this.sceneMap.getObjectById(object);
110
+ player.setAnimation(animationName, nbTimes)
111
+ })
112
+
113
+ this.webSocket.on('open', () => {
114
+ this.hooks.callHooks("client-engine-onConnected", this, this.socket).subscribe();
115
+ })
116
+
117
+ this.webSocket.on('close', () => {
118
+ this.hooks.callHooks("client-engine-onDisconnected", this, this.socket).subscribe();
119
+ })
120
+
121
+ this.webSocket.on('error', (error) => {
122
+ this.hooks.callHooks("client-engine-onConnectError", this, error, this.socket).subscribe();
123
+ })
82
124
  }
83
125
 
84
126
  private async loadScene(mapId: string) {
@@ -108,34 +150,127 @@ export class RpgClientEngine<T = any> {
108
150
  return particle;
109
151
  }
110
152
 
111
- addEffect(effect: {
153
+ /**
154
+ * Add a component to render behind sprites
155
+ * Components added with this method will be displayed with a lower z-index than the sprite
156
+ *
157
+ * @param component - The component to add behind sprites
158
+ * @returns The added component
159
+ *
160
+ * @example
161
+ * ```ts
162
+ * // Add a shadow component behind all sprites
163
+ * engine.addSpriteComponentBehind(ShadowComponent);
164
+ * ```
165
+ */
166
+ addSpriteComponentBehind(component: any) {
167
+ this.spriteComponentsBehind.update((components: any[]) => [...components, component])
168
+ return component
169
+ }
170
+
171
+ /**
172
+ * Add a component to render in front of sprites
173
+ * Components added with this method will be displayed with a higher z-index than the sprite
174
+ *
175
+ * @param component - The component to add in front of sprites
176
+ * @returns The added component
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * // Add a health bar component in front of all sprites
181
+ * engine.addSpriteComponentInFront(HealthBarComponent);
182
+ * ```
183
+ */
184
+ addSpriteComponentInFront(component: any) {
185
+ this.spriteComponentsInFront.update((components: any[]) => [...components, component])
186
+ return component
187
+ }
188
+
189
+ /**
190
+ * Add a component animation to the engine
191
+ *
192
+ * Component animations are temporary visual effects that can be displayed
193
+ * on sprites or objects, such as hit indicators, spell effects, or status animations.
194
+ *
195
+ * @param componentAnimation - The component animation configuration
196
+ * @param componentAnimation.id - Unique identifier for the animation
197
+ * @param componentAnimation.component - The component function to render
198
+ * @returns The added component animation configuration
199
+ *
200
+ * @example
201
+ * ```ts
202
+ * // Add a hit animation component
203
+ * engine.addComponentAnimation({
204
+ * id: 'hit',
205
+ * component: HitComponent
206
+ * });
207
+ *
208
+ * // Add an explosion effect component
209
+ * engine.addComponentAnimation({
210
+ * id: 'explosion',
211
+ * component: ExplosionComponent
212
+ * });
213
+ * ```
214
+ */
215
+ addComponentAnimation(componentAnimation: {
112
216
  component: any,
113
217
  id: string
114
218
  }) {
115
- const instance = new EffectManager()
116
- this.effects.push({
117
- id: effect.id,
118
- component: effect.component,
219
+ const instance = new AnimationManager()
220
+ this.componentAnimations.push({
221
+ id: componentAnimation.id,
222
+ component: componentAnimation.component,
119
223
  instance: instance,
120
224
  current: instance.current
121
225
  })
122
- return effect;
226
+ return componentAnimation;
123
227
  }
124
228
 
125
- getEffect(id: string): EffectManager {
126
- const effect = this.effects.find((effect) => effect.id === id)
127
- if (!effect) {
128
- throw new Error(`Effect with id ${id} not found`)
229
+ /**
230
+ * Get a component animation by its ID
231
+ *
232
+ * Retrieves the EffectManager instance for a specific component animation,
233
+ * which can be used to display the animation on sprites or objects.
234
+ *
235
+ * @param id - The unique identifier of the component animation
236
+ * @returns The EffectManager instance for the animation
237
+ * @throws Error if the component animation is not found
238
+ *
239
+ * @example
240
+ * ```ts
241
+ * // Get the hit animation and display it
242
+ * const hitAnimation = engine.getComponentAnimation('hit');
243
+ * hitAnimation.displayEffect({ text: "Critical!" }, player);
244
+ * ```
245
+ */
246
+ getComponentAnimation(id: string): AnimationManager {
247
+ const componentAnimation = this.componentAnimations.find((componentAnimation) => componentAnimation.id === id)
248
+ if (!componentAnimation) {
249
+ throw new Error(`Component animation with id ${id} not found`)
129
250
  }
130
- return effect.instance
251
+ return componentAnimation.instance
131
252
  }
132
253
 
133
254
  processInput({ input }: { input: number }) {
255
+ this.hooks.callHooks("client-engine-onInput", this, { input, playerId: this.playerId }).subscribe();
134
256
  this.webSocket.emit('move', { input })
135
257
  }
136
258
 
137
259
  processAction({ action }: { action: number }) {
138
260
  if (this.stopProcessingInput) return;
261
+ this.hooks.callHooks("client-engine-onInput", this, { input: 'action', playerId: this.playerId }).subscribe();
139
262
  this.webSocket.emit('action', { action })
140
263
  }
264
+
265
+ get PIXI() {
266
+ return PIXI
267
+ }
268
+
269
+ get socket() {
270
+ return this.webSocket
271
+ }
272
+
273
+ get playerId() {
274
+ return this.playerIdSignal()
275
+ }
141
276
  }
@@ -1,19 +1,17 @@
1
1
  <Sprite sheet x y anchor={0.5} />
2
2
 
3
3
  <script>
4
- import { signal } from "canvasengine";
5
4
  import { RpgClientEngine } from "../../RpgClientEngine";
6
5
  import { inject } from "../../core/inject";
7
6
 
8
- const { x, y, name, onFinish } = defineProps();
7
+ const { x, y, animationName, graphic, onFinish } = defineProps();
9
8
 
10
9
  const client = inject(RpgClientEngine);
11
10
  const spritesheets = client.spritesheets;
12
11
 
13
12
  const sheet = {
14
- definition: spritesheets.get(name()),
15
- playing: 'default',
13
+ definition: spritesheets.get(graphic()),
14
+ playing: animationName() ?? 'default',
16
15
  onFinish
17
16
  };
18
-
19
17
  </script>
@@ -1,7 +1,7 @@
1
1
  import Hit from "./hit.ce";
2
2
  import Animation from "./animation.ce";
3
3
 
4
- export const PrebuiltEffects = {
4
+ export const PrebuiltComponentAnimations = {
5
5
  Hit,
6
6
  Animation
7
7
  }
@@ -1,52 +1,57 @@
1
1
  <Container x y zIndex={y} viewportFollow={isMe} controls>
2
+ @for (component of componentsBehind) {
3
+ <Container>
4
+ <component object />
5
+ </Container>
6
+ }
2
7
  <Particle emit={@emitParticleTrigger} settings={@particleSettings} zIndex={1000} name={particleName} />
3
- @for (graphicId of graphics) {
4
- <Sprite sheet={@sheet(@graphicId)} direction tint />
5
- }
6
- <!-- <Ellipse
7
- x={shadow.@x}
8
- y={shadow.@y}
9
- width={shadow.@width}
10
- height={shadow.@height}
11
- color="black"
12
- blur={10}
13
- alpha={0.5}
14
- /> -->
8
+ <Container>
9
+ @for (graphicId of graphics) {
10
+ <Sprite sheet={@sheet(@graphicId)} direction tint hitbox />
11
+ }
12
+ </Container>
13
+ @for (component of componentsInFront) {
14
+ <Container>
15
+ <component object />
16
+ </Container>
17
+ }
15
18
  </Container>
16
19
 
17
20
  <script>
18
- import { signal, effect, mount, computed } from "canvasengine";
21
+ import { signal, effect, mount, computed, tick } from "canvasengine";
19
22
  import { Particle } from "@canvasengine/presets";
20
- import { GameEngineToken } from "@rpgjs/common";
23
+ import { GameEngineToken, ModulesToken } from "@rpgjs/common";
21
24
  import { RpgClientEngine } from "../RpgClientEngine";
22
25
  import { inject } from "../core/inject";
23
26
  import { Direction } from "@rpgjs/common";
24
27
  import Hit from "./effects/hit.ce";
25
28
 
26
- const { object, id, isMe } = defineProps();
27
-
29
+ const { object, id } = defineProps();
30
+
28
31
  const client = inject(RpgClientEngine);
32
+ const hooks = inject(ModulesToken);
29
33
 
30
34
  const spritesheets = client.spritesheets;
35
+ const playerId = client.playerId;
36
+ const componentsBehind = client.spriteComponentsBehind;
37
+ const componentsInFront = client.spriteComponentsInFront;
38
+ const isMe = computed(() => id() === playerId);
39
+
40
+ const {
41
+ x,
42
+ y,
43
+ tint,
44
+ direction,
45
+ animationName,
46
+ animationCurrentIndex,
47
+ emitParticleTrigger,
48
+ particleName,
49
+ graphics,
50
+ hitbox
51
+ } = object;
31
52
 
32
- const x = object.x;
33
- const y = object.y;
34
- const tint = object.tint;
35
- const direction = object.direction;
36
- const animationName = object.animationName;
37
- const emitParticleTrigger = object.emitParticleTrigger;
38
53
  const particleSettings = client.particleSettings;
39
- const particleName = object.particleName;
40
- const graphics = object.graphics;
41
54
 
42
- const hitbox = object.hitbox;
43
- const widthShadow = 10;
44
- const shadow = computed(() => ({
45
- x: hitbox().w / 2,
46
- y: hitbox().h - (hitbox().h / 2),
47
- width: hitbox().w + widthShadow,
48
- height: hitbox().h,
49
- }))
50
55
  const canControls = () => isMe() && object.canMove()
51
56
  const keyboardControls = client.globalConfig.keyboardControls;
52
57
 
@@ -84,7 +89,7 @@
84
89
  keyDown() {
85
90
  if (canControls()) {
86
91
  client.processAction({ action: 'action' })
87
- // particleName.set('hit')
92
+ // particleName.set('hit')
88
93
  // emitParticleTrigger.start()
89
94
  // object.flash('red')
90
95
  }
@@ -99,6 +104,42 @@
99
104
  params: {
100
105
  direction
101
106
  },
107
+ onFinish() {
108
+ animationCurrentIndex.update(index => index + 1)
109
+ }
102
110
  };
103
111
  }
112
+
113
+ // Track animation changes to reset animation state when needed
114
+ let previousAnimationName = animationName();
115
+ effect(() => {
116
+ const currentAnimationName = animationName();
117
+
118
+ // If animation changed externally (not through setAnimation), reset the state
119
+ if (currentAnimationName !== previousAnimationName && object.animationIsPlaying && object.animationIsPlaying()) {
120
+ // Check if this is a movement animation (walk, stand) that should interrupt custom animations
121
+ const movementAnimations = ['walk', 'stand'];
122
+ if (movementAnimations.includes(currentAnimationName)) {
123
+ if (typeof object.resetAnimationState === 'function') {
124
+ object.resetAnimationState();
125
+ }
126
+ }
127
+ }
128
+
129
+ previousAnimationName = currentAnimationName;
130
+ });
131
+
132
+ mount((element) => {
133
+ hooks.callHooks("client-sprite-onInit", element.componentInstance)
134
+ hooks.callHooks("client-sceneMap-onAddSprite", client.sceneMap, element.componentInstance)
135
+
136
+ return () => {
137
+ hooks.callHooks("client-sprite-onDestroy", element.componentInstance)
138
+ hooks.callHooks("client-sceneMap-onRemoveSprite", client.sceneMap, element.componentInstance)
139
+ }
140
+ })
141
+
142
+ tick(() => {
143
+ hooks.callHooks("client-sprite-onUpdate")
144
+ })
104
145
  </script>
@@ -1,3 +1,4 @@
1
1
  import EventLayerComponent from "./scenes/event-layer.ce";
2
+ import CharacterComponent from "./character.ce";
2
3
 
3
- export { EventLayerComponent }
4
+ export { EventLayerComponent, CharacterComponent }
@@ -1,28 +1,12 @@
1
1
  <Container sound={backgroundMusic} >
2
2
  <Container sound={backgroundAmbientSound} />
3
3
 
4
- <!-- <Sprite image={map.@fullImage} scale /> -->
5
-
6
- <sceneComponent() data={map.@data} />
4
+ <sceneComponent() data={map.@data} params={map.@params} />
7
5
 
8
- <!-- <Container sortableChildren={true}>
9
- @for (obj of middleLayer) {
10
- <ElementMap ...obj image={map.@gridImage} scale />
11
- }
12
-
13
- @for ((event,id) of events) {
14
- <Character id={id} object={event} isMe={false} />
15
- }
16
-
17
- @for ((player,id) of players) {
18
- <Character id={id} object={player} isMe={true} />
19
- }
20
- </Container> -->
21
-
22
- @for (effect of effects) {
6
+ @for (componentAnimation of componentAnimations) {
23
7
  <Container>
24
- @for (animation of effect.current) {
25
- <effect.component ...animation />
8
+ @for (animation of componentAnimation.current) {
9
+ <componentAnimation.component ...animation />
26
10
  }
27
11
  </Container>
28
12
  }
@@ -34,17 +18,16 @@
34
18
  import { RpgClientEngine } from "../../RpgClientEngine";
35
19
 
36
20
  const engine = inject(RpgClientEngine);
37
- const effects = engine.effects
21
+ const componentAnimations = engine.componentAnimations
38
22
  const map = engine.sceneMap.data
39
23
  const sceneComponent = computed(() => map()?.component)
24
+ const sceneParams = map()?.params
40
25
  const mapParams = map().params
41
26
  const animations = engine.sceneMap.animations
42
27
  const backgroundMusic = { src: mapParams?.backgroundMusic, autoplay: true, loop: true }
43
28
  const backgroundAmbientSound = { src: mapParams?.backgroundAmbientSound, autoplay: true, loop: true }
44
29
 
45
30
  const data = signal(map().data)
46
- // const middleLayer = computed(() => data().filter(obj => obj.layer === 1))
47
- // const topLayer = computed(() => data().filter(obj => obj.layer === 2))
48
31
 
49
32
  const scale = mapParams?.scale || 1
50
33
  const worldWidth = (mapParams?.width || 2048) * scale
@@ -1,15 +1,15 @@
1
1
  <Container sortableChildren={true}>
2
2
  @for ((event,id) of events) {
3
- <Character id={id} object={event} isMe={false} />
3
+ <Character id={id} object={event} />
4
4
  }
5
5
 
6
6
  @for ((player,id) of players) {
7
- <Character id={id} object={player} isMe={true} />
7
+ <Character id={id} object={player} />
8
8
  }
9
9
  </Container>
10
10
 
11
11
  <script>
12
- import { effect, signal, computed, mount } from 'canvasengine'
12
+ import { effect, signal } from 'canvasengine'
13
13
  import { inject } from "../../core/inject";
14
14
  import { RpgClientEngine } from "../../RpgClientEngine";
15
15
  import Character from "../character.ce";
package/src/core/setup.ts CHANGED
@@ -6,8 +6,10 @@ interface SetupOptions {
6
6
  providers: Providers;
7
7
  }
8
8
 
9
+
9
10
  export async function startGame(options: SetupOptions) {
10
11
  const context = new Context();
12
+ context['side'] = 'client'
11
13
  setInject(context);
12
14
 
13
15
  await injector(context, options.providers);
package/src/index.ts CHANGED
@@ -8,6 +8,6 @@ export * from "./services/loadMap";
8
8
  export * from "./module";
9
9
  export * from "./Gui/Gui";
10
10
  export * from "./components/gui";
11
- export * from "./components/effects";
11
+ export * from "./components/animations";
12
12
  export * from "./presets";
13
13
  export * from "./components";
package/src/module.ts CHANGED
@@ -43,12 +43,12 @@ export function provideClientModules(modules: RpgClient[]) {
43
43
  },
44
44
  };
45
45
  }
46
- if (module.effects) {
47
- const effects = [...module.effects];
48
- module.effects = {
46
+ if (module.componentAnimations) {
47
+ const componentAnimations = [...module.componentAnimations];
48
+ module.componentAnimations = {
49
49
  load: (engine: RpgClientEngine) => {
50
- effects.forEach((effect) => {
51
- engine.addEffect(effect);
50
+ componentAnimations.forEach((componentAnimation) => {
51
+ engine.addComponentAnimation(componentAnimation);
52
52
  });
53
53
  },
54
54
  };
@@ -63,6 +63,24 @@ export function provideClientModules(modules: RpgClient[]) {
63
63
  },
64
64
  };
65
65
  }
66
+ if (module.sprite) {
67
+ const sprite = {...module.sprite};
68
+ module.sprite = {
69
+ ...sprite,
70
+ load: (engine: RpgClientEngine) => {
71
+ if (sprite.componentsBehind) {
72
+ sprite.componentsBehind.forEach((component) => {
73
+ engine.addSpriteComponentBehind(component);
74
+ });
75
+ }
76
+ if (sprite.componentsInFront) {
77
+ sprite.componentsInFront.forEach((component) => {
78
+ engine.addSpriteComponentInFront(component);
79
+ });
80
+ }
81
+ },
82
+ };
83
+ }
66
84
  return module;
67
85
  });
68
86
  return modules
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Creates an animation spritesheet preset with automatic frame generation
3
+ *
4
+ * This function generates animation frames based on the provided width and height dimensions.
5
+ * It creates a sequence of frames that progresses through the spritesheet from left to right,
6
+ * top to bottom, with each frame having a 10ms time increment.
7
+ *
8
+ * @param {number} framesWidth - The number of frames horizontally in the spritesheet
9
+ * @param {number} framesHeight - The number of frames vertically in the spritesheet
10
+ * @returns {Object} Animation preset configuration object
11
+ *
12
+ * @example
13
+ * ```javascript
14
+ * // For a 4x4 spritesheet
15
+ * const preset = AnimationSpritesheetPreset(4, 4);
16
+ * // This will generate 16 frames with coordinates from (0,0) to (3,3)
17
+ * ```
18
+ */
19
+ export const AnimationSpritesheetPreset = (framesWidth: number, framesHeight: number) => {
20
+
21
+ const animations: Array<{ time: number; frameX: number; frameY: number }> = [];
22
+
23
+ for (let y = 0; y < framesHeight; y++) {
24
+ for (let x = 0; x < framesWidth; x++) {
25
+ const frameIndex = y * framesWidth + x;
26
+ animations.push({
27
+ time: frameIndex * 10,
28
+ frameX: x,
29
+ frameY: y
30
+ });
31
+ }
32
+ }
33
+
34
+ return {
35
+ framesWidth,
36
+ framesHeight,
37
+ textures: {
38
+ default: {
39
+ animations: () => [
40
+ animations
41
+ ],
42
+ }
43
+ }
44
+ };
45
+ };
46
+
@@ -1,5 +1,9 @@
1
+ import { AnimationSpritesheetPreset } from "./animation";
2
+ import { LPCSpritesheetPreset } from "./lpc";
1
3
  import { RMSpritesheet } from "./rmspritesheet";
2
4
 
3
5
  export const Presets = {
4
- RMSpritesheet
6
+ RMSpritesheet,
7
+ LPCSpritesheetPreset,
8
+ AnimationSpritesheetPreset
5
9
  }