@rpgjs/client 3.3.2 → 4.0.0-beta.3

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 (164) hide show
  1. package/LICENSE +19 -0
  2. package/lib/Components/AbstractComponent.d.ts +3 -2
  3. package/lib/Components/AbstractComponent.js +17 -28
  4. package/lib/Components/AbstractComponent.js.map +1 -1
  5. package/lib/Components/BarComponent.d.ts +2 -1
  6. package/lib/Components/BarComponent.js +32 -33
  7. package/lib/Components/BarComponent.js.map +1 -1
  8. package/lib/Components/Component.d.ts +3 -3
  9. package/lib/Components/Component.js +84 -96
  10. package/lib/Components/Component.js.map +1 -1
  11. package/lib/Components/DebugComponent.d.ts +2 -1
  12. package/lib/Components/DebugComponent.js +9 -10
  13. package/lib/Components/DebugComponent.js.map +1 -1
  14. package/lib/Components/ImageComponent.d.ts +2 -1
  15. package/lib/Components/ImageComponent.js +5 -7
  16. package/lib/Components/ImageComponent.js.map +1 -1
  17. package/lib/Components/ShapeComponent.d.ts +2 -1
  18. package/lib/Components/ShapeComponent.js +14 -14
  19. package/lib/Components/ShapeComponent.js.map +1 -1
  20. package/lib/Components/TextComponent.d.ts +3 -2
  21. package/lib/Components/TextComponent.js +10 -9
  22. package/lib/Components/TextComponent.js.map +1 -1
  23. package/lib/Components/TileComponent.d.ts +2 -1
  24. package/lib/Components/TileComponent.js +12 -16
  25. package/lib/Components/TileComponent.js.map +1 -1
  26. package/lib/Effects/Animation.d.ts +10 -9
  27. package/lib/Effects/Animation.js +36 -36
  28. package/lib/Effects/Animation.js.map +1 -1
  29. package/lib/Effects/AnimationCharacter.js +2 -5
  30. package/lib/Effects/AnimationCharacter.js.map +1 -1
  31. package/lib/Effects/Spinner.d.ts +3 -2
  32. package/lib/Effects/Spinner.js +2 -5
  33. package/lib/Effects/Spinner.js.map +1 -1
  34. package/lib/Effects/Timeline.d.ts +1 -1
  35. package/lib/Effects/Timeline.js +6 -10
  36. package/lib/Effects/Timeline.js.map +1 -1
  37. package/lib/Effects/TransitionScene.d.ts +2 -1
  38. package/lib/Effects/TransitionScene.js +3 -7
  39. package/lib/Effects/TransitionScene.js.map +1 -1
  40. package/lib/GameEngine.js +51 -26
  41. package/lib/GameEngine.js.map +1 -1
  42. package/lib/Interfaces/Character.js +1 -2
  43. package/lib/Interfaces/Scene.js +1 -2
  44. package/lib/KeyboardControls.d.ts +2 -1
  45. package/lib/KeyboardControls.js +47 -45
  46. package/lib/KeyboardControls.js.map +1 -1
  47. package/lib/Logger.js +1 -5
  48. package/lib/Logger.js.map +1 -1
  49. package/lib/Presets/AnimationSpritesheet.js +9 -13
  50. package/lib/Presets/AnimationSpritesheet.js.map +1 -1
  51. package/lib/Presets/Scene.js +2 -5
  52. package/lib/Presets/Scene.js.map +1 -1
  53. package/lib/Renderer.d.ts +5 -3
  54. package/lib/Renderer.js +68 -60
  55. package/lib/Renderer.js.map +1 -1
  56. package/lib/Resources.js +1 -5
  57. package/lib/Resources.js.map +1 -1
  58. package/lib/RpgClient.d.ts +3 -2
  59. package/lib/RpgClient.js +1 -2
  60. package/lib/RpgClientEngine.d.ts +2 -1
  61. package/lib/RpgClientEngine.js +192 -176
  62. package/lib/RpgClientEngine.js.map +1 -1
  63. package/lib/RpgGui.js +40 -41
  64. package/lib/RpgGui.js.map +1 -1
  65. package/lib/Scene/EventLayer.d.ts +4 -0
  66. package/lib/Scene/EventLayer.js +8 -0
  67. package/lib/Scene/EventLayer.js.map +1 -0
  68. package/lib/Scene/Map.d.ts +17 -3
  69. package/lib/Scene/Map.js +157 -113
  70. package/lib/Scene/Map.js.map +1 -1
  71. package/lib/Scene/Scene.d.ts +3 -3
  72. package/lib/Scene/Scene.js +24 -20
  73. package/lib/Scene/Scene.js.map +1 -1
  74. package/lib/Scene/SceneData.js +1 -5
  75. package/lib/Scene/SceneData.js.map +1 -1
  76. package/lib/Sound/RpgSound.js +8 -11
  77. package/lib/Sound/RpgSound.js.map +1 -1
  78. package/lib/Sound/Sound.d.ts +2 -2
  79. package/lib/Sound/Sound.js +1 -5
  80. package/lib/Sound/Sound.js.map +1 -1
  81. package/lib/Sound/Sounds.js +4 -8
  82. package/lib/Sound/Sounds.js.map +1 -1
  83. package/lib/Sprite/Character.d.ts +3 -2
  84. package/lib/Sprite/Character.js +15 -16
  85. package/lib/Sprite/Character.js.map +1 -1
  86. package/lib/Sprite/Player.js +2 -9
  87. package/lib/Sprite/Player.js.map +1 -1
  88. package/lib/Sprite/Spritesheet.d.ts +4 -4
  89. package/lib/Sprite/Spritesheet.js +1 -5
  90. package/lib/Sprite/Spritesheet.js.map +1 -1
  91. package/lib/Sprite/Spritesheets.js +4 -8
  92. package/lib/Sprite/Spritesheets.js.map +1 -1
  93. package/lib/Tilemap/CommonLayer.d.ts +2 -1
  94. package/lib/Tilemap/CommonLayer.js +7 -11
  95. package/lib/Tilemap/CommonLayer.js.map +1 -1
  96. package/lib/Tilemap/ImageLayer.js +5 -7
  97. package/lib/Tilemap/ImageLayer.js.map +1 -1
  98. package/lib/Tilemap/Tile.d.ts +5 -5
  99. package/lib/Tilemap/Tile.js +19 -21
  100. package/lib/Tilemap/Tile.js.map +1 -1
  101. package/lib/Tilemap/TileLayer.d.ts +0 -7
  102. package/lib/Tilemap/TileLayer.js +27 -29
  103. package/lib/Tilemap/TileLayer.js.map +1 -1
  104. package/lib/Tilemap/TileSet.d.ts +2 -1
  105. package/lib/Tilemap/TileSet.js +9 -12
  106. package/lib/Tilemap/TileSet.js.map +1 -1
  107. package/lib/Tilemap/index.d.ts +3 -11
  108. package/lib/Tilemap/index.js +22 -61
  109. package/lib/Tilemap/index.js.map +1 -1
  110. package/lib/clientEntryPoint.js +26 -28
  111. package/lib/clientEntryPoint.js.map +1 -1
  112. package/lib/index.js +21 -75
  113. package/lib/index.js.map +1 -1
  114. package/package.json +19 -19
  115. package/src/Components/AbstractComponent.ts +120 -0
  116. package/src/Components/BarComponent.ts +179 -0
  117. package/src/Components/Component.ts +506 -0
  118. package/src/Components/DebugComponent.ts +36 -0
  119. package/src/Components/ImageComponent.ts +30 -0
  120. package/src/Components/ShapeComponent.ts +64 -0
  121. package/src/Components/TextComponent.ts +33 -0
  122. package/src/Components/TileComponent.ts +43 -0
  123. package/src/Effects/Animation.ts +297 -0
  124. package/src/Effects/AnimationCharacter.ts +7 -0
  125. package/src/Effects/Spinner.ts +19 -0
  126. package/src/Effects/Timeline.ts +294 -0
  127. package/src/Effects/TransitionScene.ts +57 -0
  128. package/src/GameEngine.ts +284 -0
  129. package/src/Interfaces/Character.ts +7 -0
  130. package/src/Interfaces/Scene.ts +9 -0
  131. package/src/KeyboardControls.ts +552 -0
  132. package/src/Logger.ts +3 -0
  133. package/src/Presets/AnimationSpritesheet.ts +36 -0
  134. package/src/Presets/Scene.ts +3 -0
  135. package/src/Renderer.ts +263 -0
  136. package/src/Resources.ts +40 -0
  137. package/src/RpgClient.ts +333 -0
  138. package/src/RpgClientEngine.ts +709 -0
  139. package/src/RpgGui.ts +553 -0
  140. package/src/RpgGuiCompiled.ts +43 -0
  141. package/src/Scene/EventLayer.ts +9 -0
  142. package/src/Scene/Map.ts +393 -0
  143. package/src/Scene/Scene.ts +270 -0
  144. package/src/Scene/SceneData.ts +13 -0
  145. package/src/Sound/RpgSound.ts +50 -0
  146. package/src/Sound/Sound.ts +91 -0
  147. package/src/Sound/Sounds.ts +7 -0
  148. package/src/Sprite/Character.ts +149 -0
  149. package/src/Sprite/Player.ts +3 -0
  150. package/src/Sprite/Spritesheet.ts +392 -0
  151. package/src/Sprite/Spritesheets.ts +8 -0
  152. package/src/Tilemap/CommonLayer.ts +20 -0
  153. package/src/Tilemap/ImageLayer.ts +20 -0
  154. package/src/Tilemap/Tile.ts +80 -0
  155. package/src/Tilemap/TileLayer.ts +142 -0
  156. package/src/Tilemap/TileSet.ts +40 -0
  157. package/src/Tilemap/index.ts +173 -0
  158. package/src/clientEntryPoint.ts +141 -0
  159. package/src/index.ts +25 -0
  160. package/src/types/howler.d.ts +73 -0
  161. package/tsconfig.json +30 -0
  162. package/lib/Components/ColorComponent.d.ts +0 -9
  163. package/lib/Components/ColorComponent.js +0 -18
  164. package/lib/Components/ColorComponent.js.map +0 -1
@@ -0,0 +1,43 @@
1
+ import { TileComponentObject } from "@rpgjs/types"
2
+ import { SceneMap } from "../Scene/Map"
3
+ import Tile from "../Tilemap/Tile"
4
+ import TileLayer from "../Tilemap/TileLayer"
5
+ import { AbstractComponent, CellInfo } from "./AbstractComponent"
6
+ import { Container } from "pixi.js"
7
+
8
+ export class TileComponent extends AbstractComponent<TileComponentObject, Container> {
9
+ static readonly id: string = 'tile'
10
+ cacheParams: string[] = []
11
+ gid: number = 0
12
+
13
+ onInit(cell: CellInfo) {
14
+ this.cell = cell
15
+ if (typeof this.value == 'number') {
16
+ this.gid = this.value
17
+ } else {
18
+ this.gid = this.value.gid
19
+ }
20
+ this.updateRender({})
21
+ super.onInit(cell)
22
+ }
23
+
24
+ updateRender(object: any) {
25
+ this.removeChildren()
26
+ const height = typeof this.value != 'number' ? this.getValue(object, this.value.height) : null ?? this.cell?.height ?? 0
27
+ const width = typeof this.value != 'number' ? this.getValue(object, this.value.width) : null ?? this.cell?.width ?? 0
28
+ const scene = this.component.getScene<SceneMap>()
29
+ const tilemap = scene.tilemap
30
+ const tileset = TileLayer.findTileSet(
31
+ this.gid,
32
+ tilemap.tilesets
33
+ )
34
+ if (tileset) {
35
+ const tile = new Tile({
36
+ gid: this.gid
37
+ } as any, tileset)
38
+ tile.width = width ?? 0
39
+ tile.height = height ?? 0
40
+ this.addChild(tile)
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,297 @@
1
+ import { Utils } from '@rpgjs/common'
2
+ import { spritesheets } from '../Sprite/Spritesheets'
3
+ import { SpritesheetOptions, TextureOptions, AnimationFrames, FrameOptions, TransformOptions } from '../Sprite/Spritesheet'
4
+ import { log } from '../Logger'
5
+ import { RpgSound } from '../Sound/RpgSound'
6
+ import { RpgComponent } from '../Components/Component'
7
+ import { Sprite, Container, Texture, Rectangle } from 'pixi.js'
8
+ import { Animation as AnimationEnum } from './AnimationCharacter'
9
+ import { BehaviorSubject, Observable } from 'rxjs'
10
+
11
+ const { isFunction, arrayEquals } = Utils
12
+
13
+ type Image = { image: string }
14
+
15
+ type TextureOptionsMerging = TextureOptions & {
16
+ spriteWidth: number
17
+ spriteHeight: number
18
+ sound?: string
19
+ } & Image & TransformOptions
20
+
21
+ type FrameOptionsMerging = TextureOptionsMerging & FrameOptions
22
+ type SpritesheetOptionsMerging = TextureOptionsMerging & SpritesheetOptions
23
+ type TransformOptionsAsArray = Pick<TransformOptions, 'anchor' | 'scale' | 'skew' | 'pivot'>
24
+
25
+ type AnimationDataFrames = {
26
+ container: Container,
27
+ sprites: FrameOptionsMerging[],
28
+ frames: Texture[][],
29
+ name: string,
30
+ animations: AnimationFrames,
31
+ params: any[],
32
+ data: TextureOptionsMerging
33
+ }
34
+
35
+ export class Animation extends Sprite {
36
+ public attachTo: RpgComponent
37
+ public hitbox: { w: number, h: number }
38
+ public applyTransform: (
39
+ frame: FrameOptionsMerging,
40
+ data: TextureOptionsMerging,
41
+ spritesheet: SpritesheetOptionsMerging
42
+ ) => Partial<FrameOptionsMerging>
43
+ private spritesheet: SpritesheetOptionsMerging
44
+ private currentAnimation: AnimationDataFrames | null = null
45
+ private time: number = 0
46
+ private frameIndex: number = 0
47
+ private animations: Map<string, AnimationDataFrames> = new Map()
48
+ private _animation$: BehaviorSubject<Sprite | null> = new BehaviorSubject(null as any)
49
+ readonly animation$: Observable<Sprite | null> = this._animation$.asObservable()
50
+
51
+ onFinish: () => void
52
+
53
+ constructor(public id: string) {
54
+ super()
55
+ this.spritesheet = spritesheets.get(this.id)
56
+ if (!this.spritesheet) {
57
+ throw log(`Impossible to find the ${this.id} spritesheet. Did you put the right name or create the spritesheet?`)
58
+ }
59
+ this.createAnimations()
60
+ }
61
+
62
+ private createTextures(options: Required<TextureOptionsMerging>): Texture[][] {
63
+ const { width, height, framesHeight, framesWidth, image, offset } = options
64
+ const { baseTexture } = Texture.from(image)
65
+ const spriteWidth = options.spriteWidth
66
+ const spriteHeight = options.spriteHeight
67
+ const frames: Texture[][] = []
68
+ const offsetX = (offset && offset.x) || 0
69
+ const offsetY = (offset && offset.y) || 0
70
+ for (let i = 0; i < framesHeight; i++) {
71
+ frames[i] = []
72
+ for (let j = 0; j < framesWidth; j++) {
73
+ const rectX = j * spriteWidth + offsetX
74
+ const rectY = i * spriteHeight + offsetY
75
+ if (rectY > height) {
76
+ throw log(`Warning, there is a problem with the height of the "${this.id}" spritesheet. When cutting into frames, the frame exceeds the height of the image.`)
77
+ }
78
+ if (rectX > width) {
79
+ throw log(`Warning, there is a problem with the width of the "${this.id}" spritesheet. When cutting into frames, the frame exceeds the width of the image.`)
80
+ }
81
+ frames[i].push(
82
+ new Texture(baseTexture, new Rectangle(rectX, rectY, spriteWidth, spriteHeight))
83
+ )
84
+ }
85
+ }
86
+ return frames
87
+ }
88
+
89
+ private createAnimations() {
90
+ const { textures } = this.spritesheet
91
+ if (!textures) {
92
+ return
93
+ }
94
+ for (let animationName in textures) {
95
+ const props: (keyof TextureOptionsMerging)[] = ['width', 'height', 'framesHeight', 'framesWidth', 'rectWidth', 'rectHeight', 'offset', 'image', 'sound']
96
+ const parentObj = props
97
+ .reduce((prev, val) => ({ ...prev, [val]: this.spritesheet[val] }), {})
98
+ const optionsTextures: TextureOptionsMerging = {
99
+ ...parentObj,
100
+ ...textures[animationName]
101
+ } as any
102
+ const { rectWidth, width = 0, framesWidth = 1, rectHeight, height = 0, framesHeight = 1 } = optionsTextures
103
+ optionsTextures.spriteWidth = rectWidth ? rectWidth : width / framesWidth
104
+ optionsTextures.spriteHeight = rectHeight ? rectHeight : height / framesHeight
105
+ this.animations.set(animationName, {
106
+ container: new Sprite(),
107
+ frames: this.createTextures(optionsTextures as Required<TextureOptionsMerging>),
108
+ name: animationName,
109
+ animations: textures[animationName].animations,
110
+ params: [],
111
+ data: optionsTextures,
112
+ sprites: []
113
+ })
114
+ }
115
+ }
116
+
117
+ private getSpriteSize(name: 'spriteHeight' | 'spriteWidth'): number {
118
+ return this.animations.get(this.currentAnimation?.name || AnimationEnum.Stand)?.data[name] || 0
119
+ }
120
+
121
+ getSpriteHeight(): number {
122
+ return this.getSpriteSize('spriteHeight')
123
+ }
124
+
125
+ getSpriteWidth(): number {
126
+ return this.getSpriteSize('spriteWidth')
127
+ }
128
+
129
+ has(name: string): boolean {
130
+ return this.animations.has(name)
131
+ }
132
+
133
+ get(name: string): AnimationDataFrames {
134
+ return this.animations.get(name) as AnimationDataFrames
135
+ }
136
+
137
+ isPlaying(name?: string): boolean {
138
+ if (!name) return !!this.currentAnimation
139
+ if (this.currentAnimation == null) return false
140
+ return this.currentAnimation.name == name
141
+ }
142
+
143
+ stop() {
144
+ this.currentAnimation = null
145
+ this.parent?.removeChild(this)
146
+ }
147
+
148
+ play(name: string, params: any[] = []) {
149
+ const animParams = this.currentAnimation?.params
150
+
151
+ if (this.isPlaying(name) && arrayEquals(params, animParams || [])) return
152
+
153
+ const animation = this.get(name)
154
+
155
+ if (!animation) {
156
+ throw new Error(`Impossible to play the ${name} animation because it doesn't exist on the ${this.id} spritesheet`)
157
+ }
158
+
159
+ this.removeChildren()
160
+ animation.sprites = []
161
+ this.currentAnimation = animation
162
+ this.currentAnimation.params = params
163
+ this.time = 0
164
+ this.frameIndex = 0
165
+
166
+ let animations: any = animation.animations;
167
+ animations = isFunction(animations) ? (animations as Function)(...params) : animations
168
+
169
+ this.currentAnimation.container = new Container()
170
+
171
+ for (let container of (animations as FrameOptionsMerging[][])) {
172
+ const sprite = new Sprite()
173
+ for (let frame of container) {
174
+ this.currentAnimation.sprites.push(frame)
175
+ }
176
+ this.currentAnimation.container.addChild(sprite)
177
+ }
178
+
179
+ const sound = this.currentAnimation.data.sound
180
+
181
+ if (sound) {
182
+ RpgSound.get(sound).play()
183
+ }
184
+
185
+ this.addChild(this.currentAnimation.container)
186
+ // Updates immediately to avoid flickering
187
+ this.update(1)
188
+ }
189
+
190
+ update(deltaRatio: number) {
191
+ if (!this.isPlaying() || !this.currentAnimation) return
192
+
193
+ const { frames, container, sprites, data } = this.currentAnimation
194
+ let frame = sprites[this.frameIndex]
195
+ const nextFrame = sprites[this.frameIndex + 1]
196
+
197
+ if (this.attachTo) {
198
+ const sprite = this.attachTo
199
+ const pos = sprite?.getPositionsOfGraphic('middle')
200
+ if (pos) {
201
+ container.x = pos.x
202
+ container.y = pos.y
203
+ }
204
+ }
205
+
206
+ for (let _sprite of container.children) {
207
+ const sprite = _sprite as Sprite
208
+
209
+ if (!frame || frame.frameY == undefined || frame.frameX == undefined) {
210
+ continue
211
+ }
212
+
213
+ sprite.texture = frames[frame.frameY][frame.frameX]
214
+
215
+ const getVal = <T extends keyof TransformOptions>(prop: T): TransformOptions[T] | undefined =>
216
+ frame[prop] || data[prop] || this.spritesheet[prop]
217
+
218
+ const applyTransform = <T extends keyof TransformOptionsAsArray>(prop: T): void => {
219
+ const val = getVal<T>(prop)
220
+ if (val) {
221
+ sprite[prop as string].set(...val!)
222
+ }
223
+ }
224
+
225
+ function applyTransformValue<T extends keyof TransformOptions>(prop: T);
226
+ function applyTransformValue<T extends keyof TransformOptions>(prop: string, alias: T);
227
+ function applyTransformValue<T extends keyof TransformOptions>(prop: T, alias?: T): void {
228
+ const optionProp = alias || prop
229
+ const val = getVal<T>(optionProp)
230
+ if (val !== undefined) {
231
+ sprite[prop as string] = val
232
+ }
233
+ }
234
+
235
+ if (this.applyTransform) {
236
+ frame = {
237
+ ...frame,
238
+ ...this.applyTransform(frame, data, this.spritesheet)
239
+ }
240
+
241
+ }
242
+
243
+ const realSize = getVal<'spriteRealSize'>('spriteRealSize')
244
+ const heightOfSprite = typeof realSize == 'number' ? realSize : realSize?.height
245
+ const widthOfSprite = typeof realSize == 'number' ? realSize : realSize?.width
246
+
247
+ const applyAnchorBySize = () => {
248
+ if (heightOfSprite && this.hitbox) {
249
+ const { spriteWidth, spriteHeight } = data
250
+ const w = ((spriteWidth - this.hitbox.w) / 2) / spriteWidth
251
+ const gap = (spriteHeight - heightOfSprite) / 2
252
+ const h = (spriteHeight - this.hitbox.h - gap) / spriteHeight
253
+ sprite.anchor.set(w, h)
254
+ }
255
+ }
256
+
257
+ if (frame.sound) {
258
+ RpgSound.get(frame.sound).play()
259
+ }
260
+
261
+ applyAnchorBySize()
262
+
263
+ applyTransform('anchor')
264
+ applyTransform('scale')
265
+ applyTransform('skew')
266
+ applyTransform('pivot')
267
+
268
+ applyTransformValue('alpha', 'opacity')
269
+ applyTransformValue('x')
270
+ applyTransformValue('y')
271
+ applyTransformValue('angle')
272
+ applyTransformValue('rotation')
273
+ applyTransformValue('visible')
274
+
275
+ this._animation$.next({
276
+ spriteWidth: widthOfSprite || sprite.width,
277
+ spriteHeight: heightOfSprite || sprite.height,
278
+ anchor: sprite.anchor,
279
+ width: getVal<any>('spriteWidth'),
280
+ height: getVal<any>('spriteHeight')
281
+ } as any)
282
+ }
283
+
284
+ if (!nextFrame) {
285
+ this.time = 0
286
+ this.frameIndex = 0
287
+ if (this.onFinish) this.onFinish()
288
+ return
289
+ }
290
+
291
+ this.time += deltaRatio
292
+
293
+ if (this.time >= nextFrame.time) {
294
+ this.frameIndex++
295
+ }
296
+ }
297
+ }
@@ -0,0 +1,7 @@
1
+ export enum Animation {
2
+ Stand = 'stand',
3
+ Walk = 'walk',
4
+ Attack = 'attack',
5
+ Defense = 'defense',
6
+ Skill = 'skill'
7
+ }
@@ -0,0 +1,19 @@
1
+ import { RpgClientEngine } from "../RpgClientEngine";
2
+ import { Graphics, Renderer } from "pixi.js";
3
+
4
+ export class SpinnerGraphic extends Graphics {
5
+ constructor(private clientEngine: RpgClientEngine) {
6
+ super()
7
+ }
8
+
9
+ render(renderer: Renderer) {
10
+ super.render(renderer)
11
+ this.rotation += 0.12;
12
+ const percent = Math.abs(Math.sin(Date.now() / 1000))
13
+ this
14
+ .clear()
15
+ .lineStyle(4, 0xffffff, 1)
16
+ .moveTo(40, 0)
17
+ .arc(0, 0, 40, 0, Math.PI * 2 * percent, false)
18
+ }
19
+ }
@@ -0,0 +1,294 @@
1
+ import { TransformOptions, FrameOptions } from '../Sprite/Spritesheet'
2
+
3
+ export const Ease = {
4
+ linear(t: number, b: number, c: number, d: number): number {
5
+ return c*(t/=d) + b;
6
+ },
7
+ easeInQuad (t: number, b: number, c: number, d: number): number {
8
+ return c*(t/=d)*t + b;
9
+ },
10
+ easeOutQuad (t: number, b: number, c: number, d: number): number {
11
+ return -c *(t/=d)*(t-2) + b;
12
+ },
13
+ easeInOutQuad (t: number, b: number, c: number, d: number): number {
14
+ if ((t/=d/2) < 1) return c/2*t*t + b;
15
+ return -c/2 * ((--t)*(t-2) - 1) + b;
16
+ },
17
+ easeInCubic (t: number, b: number, c: number, d: number): number {
18
+ return c*(t/=d)*t*t + b;
19
+ },
20
+ easeOutCubic (t: number, b: number, c: number, d: number): number {
21
+ return c*((t=t/d-1)*t*t + 1) + b;
22
+ },
23
+ easeInOutCubic (t: number, b: number, c: number, d: number): number {
24
+ if ((t/=d/2) < 1) return c/2*t*t*t + b;
25
+ return c/2*((t-=2)*t*t + 2) + b;
26
+ },
27
+ easeInQuart (t: number, b: number, c: number, d: number): number {
28
+ return c*(t/=d)*t*t*t + b;
29
+ },
30
+ easeOutQuart (t: number, b: number, c: number, d: number): number {
31
+ return -c * ((t=t/d-1)*t*t*t - 1) + b;
32
+ },
33
+ easeInOutQuart (t: number, b: number, c: number, d: number): number {
34
+ if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
35
+ return -c/2 * ((t-=2)*t*t*t - 2) + b;
36
+ },
37
+ easeInQuint (t: number, b: number, c: number, d: number): number {
38
+ return c*(t/=d)*t*t*t*t + b;
39
+ },
40
+ easeOutQuint (t: number, b: number, c: number, d: number): number {
41
+ return c*((t=t/d-1)*t*t*t*t + 1) + b;
42
+ },
43
+ easeInOutQuint (t: number, b: number, c: number, d: number): number {
44
+ if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
45
+ return c/2*((t-=2)*t*t*t*t + 2) + b;
46
+ },
47
+ easeInSine (t: number, b: number, c: number, d: number): number {
48
+ return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
49
+ },
50
+ easeOutSine (t: number, b: number, c: number, d: number): number {
51
+ return c * Math.sin(t/d * (Math.PI/2)) + b;
52
+ },
53
+ easeInOutSine (t: number, b: number, c: number, d: number): number {
54
+ return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
55
+ },
56
+ easeInExpo (t: number, b: number, c: number, d: number): number {
57
+ return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
58
+ },
59
+ easeOutExpo (t: number, b: number, c: number, d: number): number {
60
+ return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
61
+ },
62
+ easeInOutExpo (t: number, b: number, c: number, d: number): number {
63
+ if (t==0) return b;
64
+ if (t==d) return b+c;
65
+ if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
66
+ return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
67
+ },
68
+ easeInCirc (t: number, b: number, c: number, d: number): number {
69
+ return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
70
+ },
71
+ easeOutCirc (t: number, b: number, c: number, d: number): number {
72
+ return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
73
+ },
74
+ easeInOutCirc (t: number, b: number, c: number, d: number): number {
75
+ if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
76
+ return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
77
+ },
78
+ easeInElastic (t: number, b: number, c: number, d: number): number {
79
+ var s=1.70158;var p=0;var a=c;
80
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
81
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
82
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
83
+ return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
84
+ },
85
+ easeOutElastic (t: number, b: number, c: number, d: number): number {
86
+ var s=1.70158;var p=0;var a=c;
87
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
88
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
89
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
90
+ return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
91
+ },
92
+ easeInOutElastic (t: number, b: number, c: number, d: number): number {
93
+ var s=1.70158;var p=0;var a=c;
94
+ if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
95
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
96
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
97
+ if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
98
+ return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
99
+ },
100
+ easeInBack (t: number, b: number, c: number, d: number, s: number): number {
101
+ if (s == undefined) s = 1.70158;
102
+ return c*(t/=d)*t*((s+1)*t - s) + b;
103
+ },
104
+ easeOutBack (t: number, b: number, c: number, d: number, s: number): number {
105
+ if (s == undefined) s = 1.70158;
106
+ return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
107
+ },
108
+ easeInOutBack (t: number, b: number, c: number, d: number, s: number): number {
109
+ if (s == undefined) s = 1.70158;
110
+ if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
111
+ return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
112
+ },
113
+ easeInBounce (t: number, b: number, c: number, d: number): number {
114
+ return c - Ease.easeOutBounce (d-t, 0, c, d) + b;
115
+ },
116
+ easeOutBounce (t: number, b: number, c: number, d: number): number {
117
+ if ((t/=d) < (1/2.75)) {
118
+ return c*(7.5625*t*t) + b;
119
+ } else if (t < (2/2.75)) {
120
+ return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
121
+ } else if (t < (2.5/2.75)) {
122
+ return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
123
+ } else {
124
+ return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
125
+ }
126
+ },
127
+ easeInOutBounce (t: number, b: number, c: number, d: number): number {
128
+ if (t < d/2) return Ease.easeInBounce (t*2, 0, c, d) * .5 + b;
129
+ return Ease.easeOutBounce (t*2-d, 0, c, d) * .5 + c*.5 + b;
130
+ }
131
+ }
132
+
133
+ type EaseType = (t: number, b: number, c: number, d: number) => number
134
+
135
+ export class Timeline {
136
+ private time: number = 0
137
+ private animation: FrameOptions[][] = []
138
+
139
+ /**
140
+ * Allows you to create complex animations more easily. For example, to display a movement with an Easing function
141
+ *
142
+ * ```ts
143
+ * import { Timeline, Ease } from '@rpgjs/client'
144
+ *
145
+ * new Timeline()
146
+ * .add(30, ({ scale }) => [{
147
+ * frameX: 0,
148
+ * frameY: 1,
149
+ * scale: [scale]
150
+ * }], {
151
+ * scale: {
152
+ * from: 0,
153
+ * to: 1,
154
+ * easing: Ease.easeOutBounce
155
+ * }
156
+ * })
157
+ * .add(100)
158
+ * .create()
159
+ * ```
160
+ *
161
+ * Here we say
162
+ *
163
+ * - For a duration of 30 seconds
164
+ * - A function that will be called every 1 frame with the `scale` property defined in transform
165
+ * - An object of transformation. Define the properties of your choice to be passed to the callback function
166
+ * - `to`: the starting value
167
+ * - `from`: the end value
168
+ * - `easing`: An easing function (By default, it is a linear function)
169
+ *
170
+ * Note that if you just put a duration (`add(100)`), it will only put a pause on the animation
171
+ *
172
+ * Easing functions available but you can create your own
173
+ *
174
+ * ```ts
175
+ * function myEase(t: number, b: number, c: number, d: number): number { }
176
+ * ```
177
+ *
178
+ * `t`: current time
179
+ * `b`: start value
180
+ * `c`: end value
181
+ * `d`: duration
182
+ *
183
+ * @title Add Animation in timeline
184
+ * @enum {Function}
185
+ *
186
+ * Ease.linear | linear
187
+ * Ease.easeInQuad | easeInQuad
188
+ * Ease.easeOutQuad | easeOutQuad
189
+ * Ease.easeInOutQuad | easeInOutQuad
190
+ * Ease.easeInCubic | easeInCubic
191
+ * Ease.easeOutCubic | easeOutCubic
192
+ * Ease.easeInOutCubic | easeInOutCubic
193
+ * Ease.easeInQuart | easeInQuart
194
+ * Ease.easeOutQuart | easeOutQuart
195
+ * Ease.easeInOutQuart | easeInOutQuart
196
+ * Ease.easeInQuint | easeInQuint
197
+ * Ease.easeOutQuint | easeOutQuint
198
+ * Ease.easeInOutQuint | easeInOutQuint
199
+ * Ease.easeInSine | easeInSine
200
+ * Ease.easeOutSine | easeOutSine
201
+ * Ease.easeInOutSine | easeInOutSine
202
+ * Ease.easeInExpo | easeInExpo
203
+ * Ease.easeOutExpo | easeOutExpo
204
+ * Ease.easeInOutExpo | easeInOutExpo
205
+ * Ease.easeInCirc | easeInCirc
206
+ * Ease.easeOutCirc | easeOutCirc
207
+ * Ease.easeInOutCirc | easeInOutCirc
208
+ * Ease.easeInElastic | easeInElastic
209
+ * Ease.easeOutElastic | easeOutElastic
210
+ * Ease.easeInOutElastic | easeInOutElastic
211
+ * Ease.easeInBack | easeInBack
212
+ * Ease.easeOutBack | easeOutBack
213
+ * Ease.easeInOutBack | easeInOutBack
214
+ * Ease.easeInBounce | easeInBounce
215
+ * Ease.easeOutBounce | easeOutBounce
216
+ * @method timeline.add(duration,cb?,transform?)
217
+ * @param {number} duration
218
+ * @param { (obj?: number, time?: number) => TransformOptions[] } [cb]
219
+ * @param { [property: string]: { to:number, from: number: easing?: Function } } [transform]
220
+ * @returns {Timeline}
221
+ * @memberof Timeline
222
+ */
223
+ add(duration: number, cb?: (obj?: any, time?: number) => TransformOptions[], transform?: {
224
+ [property: string]: {
225
+ to: number,
226
+ from: number,
227
+ easing?: EaseType
228
+ }
229
+ }): Timeline {
230
+ if (!cb) {
231
+ this.animation.push([{
232
+ time: duration + this.time,
233
+ }])
234
+ this.time += duration
235
+ return this
236
+ }
237
+ for (let i=0 ; i < duration ; i++) {
238
+ let anim
239
+ const obj = {}
240
+ for (let prop in transform) {
241
+ const param = transform[prop]
242
+ const cbEasing = param.easing || Ease.linear
243
+ if (param.to < param.from) {
244
+ obj[prop] = 1 - cbEasing(i, param.to, param.from, duration)
245
+ }
246
+ else {
247
+ obj[prop] = cbEasing(i, param.from, param.to, duration)
248
+ }
249
+ }
250
+ const ret = cb(obj, i)
251
+ anim = ret.map(el => {
252
+ (el as any).time = i + this.time
253
+ return el
254
+ })
255
+ this.animation.push(anim)
256
+ }
257
+ this.time += duration
258
+ return this
259
+ }
260
+
261
+ /**
262
+ * Allows you to create the animation array to assign to the `animations` property in the Spritesheet
263
+ *
264
+ * ```ts
265
+ * import { Spritesheet, Timeline } from '@rpgjs/server'
266
+ *
267
+ * @Spritesheet({
268
+ * id: 'sprite',
269
+ * image: require('./sprite.png'),
270
+ * width: 192,
271
+ * height: 228,
272
+ * framesHeight: 6,
273
+ * framesWidth: 6,
274
+ * anchor: [0.5],
275
+ * textures: {
276
+ * myanim: {
277
+ * animations: new Timeline()
278
+ * .add(SEE THE ADD METHOD)
279
+ * .create()
280
+ * }
281
+ * }
282
+ * })
283
+ * export class MyAnim {}
284
+ * ```
285
+ *
286
+ * @title Create the animation array
287
+ * @method timeline.create()
288
+ * @returns {FrameOptions[][]} The animation array
289
+ * @memberof Timeline
290
+ */
291
+ create(): FrameOptions[][] {
292
+ return this.animation
293
+ }
294
+ }