@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.
- package/LICENSE +19 -0
- package/lib/Components/AbstractComponent.d.ts +3 -2
- package/lib/Components/AbstractComponent.js +17 -28
- package/lib/Components/AbstractComponent.js.map +1 -1
- package/lib/Components/BarComponent.d.ts +2 -1
- package/lib/Components/BarComponent.js +32 -33
- package/lib/Components/BarComponent.js.map +1 -1
- package/lib/Components/Component.d.ts +3 -3
- package/lib/Components/Component.js +84 -96
- package/lib/Components/Component.js.map +1 -1
- package/lib/Components/DebugComponent.d.ts +2 -1
- package/lib/Components/DebugComponent.js +9 -10
- package/lib/Components/DebugComponent.js.map +1 -1
- package/lib/Components/ImageComponent.d.ts +2 -1
- package/lib/Components/ImageComponent.js +5 -7
- package/lib/Components/ImageComponent.js.map +1 -1
- package/lib/Components/ShapeComponent.d.ts +2 -1
- package/lib/Components/ShapeComponent.js +14 -14
- package/lib/Components/ShapeComponent.js.map +1 -1
- package/lib/Components/TextComponent.d.ts +3 -2
- package/lib/Components/TextComponent.js +10 -9
- package/lib/Components/TextComponent.js.map +1 -1
- package/lib/Components/TileComponent.d.ts +2 -1
- package/lib/Components/TileComponent.js +12 -16
- package/lib/Components/TileComponent.js.map +1 -1
- package/lib/Effects/Animation.d.ts +10 -9
- package/lib/Effects/Animation.js +36 -36
- package/lib/Effects/Animation.js.map +1 -1
- package/lib/Effects/AnimationCharacter.js +2 -5
- package/lib/Effects/AnimationCharacter.js.map +1 -1
- package/lib/Effects/Spinner.d.ts +3 -2
- package/lib/Effects/Spinner.js +2 -5
- package/lib/Effects/Spinner.js.map +1 -1
- package/lib/Effects/Timeline.d.ts +1 -1
- package/lib/Effects/Timeline.js +6 -10
- package/lib/Effects/Timeline.js.map +1 -1
- package/lib/Effects/TransitionScene.d.ts +2 -1
- package/lib/Effects/TransitionScene.js +3 -7
- package/lib/Effects/TransitionScene.js.map +1 -1
- package/lib/GameEngine.js +51 -26
- package/lib/GameEngine.js.map +1 -1
- package/lib/Interfaces/Character.js +1 -2
- package/lib/Interfaces/Scene.js +1 -2
- package/lib/KeyboardControls.d.ts +2 -1
- package/lib/KeyboardControls.js +47 -45
- package/lib/KeyboardControls.js.map +1 -1
- package/lib/Logger.js +1 -5
- package/lib/Logger.js.map +1 -1
- package/lib/Presets/AnimationSpritesheet.js +9 -13
- package/lib/Presets/AnimationSpritesheet.js.map +1 -1
- package/lib/Presets/Scene.js +2 -5
- package/lib/Presets/Scene.js.map +1 -1
- package/lib/Renderer.d.ts +5 -3
- package/lib/Renderer.js +68 -60
- package/lib/Renderer.js.map +1 -1
- package/lib/Resources.js +1 -5
- package/lib/Resources.js.map +1 -1
- package/lib/RpgClient.d.ts +3 -2
- package/lib/RpgClient.js +1 -2
- package/lib/RpgClientEngine.d.ts +2 -1
- package/lib/RpgClientEngine.js +192 -176
- package/lib/RpgClientEngine.js.map +1 -1
- package/lib/RpgGui.js +40 -41
- package/lib/RpgGui.js.map +1 -1
- package/lib/Scene/EventLayer.d.ts +4 -0
- package/lib/Scene/EventLayer.js +8 -0
- package/lib/Scene/EventLayer.js.map +1 -0
- package/lib/Scene/Map.d.ts +17 -3
- package/lib/Scene/Map.js +157 -113
- package/lib/Scene/Map.js.map +1 -1
- package/lib/Scene/Scene.d.ts +3 -3
- package/lib/Scene/Scene.js +24 -20
- package/lib/Scene/Scene.js.map +1 -1
- package/lib/Scene/SceneData.js +1 -5
- package/lib/Scene/SceneData.js.map +1 -1
- package/lib/Sound/RpgSound.js +8 -11
- package/lib/Sound/RpgSound.js.map +1 -1
- package/lib/Sound/Sound.d.ts +2 -2
- package/lib/Sound/Sound.js +1 -5
- package/lib/Sound/Sound.js.map +1 -1
- package/lib/Sound/Sounds.js +4 -8
- package/lib/Sound/Sounds.js.map +1 -1
- package/lib/Sprite/Character.d.ts +3 -2
- package/lib/Sprite/Character.js +15 -16
- package/lib/Sprite/Character.js.map +1 -1
- package/lib/Sprite/Player.js +2 -9
- package/lib/Sprite/Player.js.map +1 -1
- package/lib/Sprite/Spritesheet.d.ts +4 -4
- package/lib/Sprite/Spritesheet.js +1 -5
- package/lib/Sprite/Spritesheet.js.map +1 -1
- package/lib/Sprite/Spritesheets.js +4 -8
- package/lib/Sprite/Spritesheets.js.map +1 -1
- package/lib/Tilemap/CommonLayer.d.ts +2 -1
- package/lib/Tilemap/CommonLayer.js +7 -11
- package/lib/Tilemap/CommonLayer.js.map +1 -1
- package/lib/Tilemap/ImageLayer.js +5 -7
- package/lib/Tilemap/ImageLayer.js.map +1 -1
- package/lib/Tilemap/Tile.d.ts +5 -5
- package/lib/Tilemap/Tile.js +19 -21
- package/lib/Tilemap/Tile.js.map +1 -1
- package/lib/Tilemap/TileLayer.d.ts +0 -7
- package/lib/Tilemap/TileLayer.js +27 -29
- package/lib/Tilemap/TileLayer.js.map +1 -1
- package/lib/Tilemap/TileSet.d.ts +2 -1
- package/lib/Tilemap/TileSet.js +9 -12
- package/lib/Tilemap/TileSet.js.map +1 -1
- package/lib/Tilemap/index.d.ts +3 -11
- package/lib/Tilemap/index.js +22 -61
- package/lib/Tilemap/index.js.map +1 -1
- package/lib/clientEntryPoint.js +26 -28
- package/lib/clientEntryPoint.js.map +1 -1
- package/lib/index.js +21 -75
- package/lib/index.js.map +1 -1
- package/package.json +19 -19
- package/src/Components/AbstractComponent.ts +120 -0
- package/src/Components/BarComponent.ts +179 -0
- package/src/Components/Component.ts +506 -0
- package/src/Components/DebugComponent.ts +36 -0
- package/src/Components/ImageComponent.ts +30 -0
- package/src/Components/ShapeComponent.ts +64 -0
- package/src/Components/TextComponent.ts +33 -0
- package/src/Components/TileComponent.ts +43 -0
- package/src/Effects/Animation.ts +297 -0
- package/src/Effects/AnimationCharacter.ts +7 -0
- package/src/Effects/Spinner.ts +19 -0
- package/src/Effects/Timeline.ts +294 -0
- package/src/Effects/TransitionScene.ts +57 -0
- package/src/GameEngine.ts +284 -0
- package/src/Interfaces/Character.ts +7 -0
- package/src/Interfaces/Scene.ts +9 -0
- package/src/KeyboardControls.ts +552 -0
- package/src/Logger.ts +3 -0
- package/src/Presets/AnimationSpritesheet.ts +36 -0
- package/src/Presets/Scene.ts +3 -0
- package/src/Renderer.ts +263 -0
- package/src/Resources.ts +40 -0
- package/src/RpgClient.ts +333 -0
- package/src/RpgClientEngine.ts +709 -0
- package/src/RpgGui.ts +553 -0
- package/src/RpgGuiCompiled.ts +43 -0
- package/src/Scene/EventLayer.ts +9 -0
- package/src/Scene/Map.ts +393 -0
- package/src/Scene/Scene.ts +270 -0
- package/src/Scene/SceneData.ts +13 -0
- package/src/Sound/RpgSound.ts +50 -0
- package/src/Sound/Sound.ts +91 -0
- package/src/Sound/Sounds.ts +7 -0
- package/src/Sprite/Character.ts +149 -0
- package/src/Sprite/Player.ts +3 -0
- package/src/Sprite/Spritesheet.ts +392 -0
- package/src/Sprite/Spritesheets.ts +8 -0
- package/src/Tilemap/CommonLayer.ts +20 -0
- package/src/Tilemap/ImageLayer.ts +20 -0
- package/src/Tilemap/Tile.ts +80 -0
- package/src/Tilemap/TileLayer.ts +142 -0
- package/src/Tilemap/TileSet.ts +40 -0
- package/src/Tilemap/index.ts +173 -0
- package/src/clientEntryPoint.ts +141 -0
- package/src/index.ts +25 -0
- package/src/types/howler.d.ts +73 -0
- package/tsconfig.json +30 -0
- package/lib/Components/ColorComponent.d.ts +0 -9
- package/lib/Components/ColorComponent.js +0 -18
- package/lib/Components/ColorComponent.js.map +0 -1
package/src/Scene/Map.ts
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import { RpgCommonMap, RpgPlugin, HookClient, RpgShape, Utils, RpgCommonPlayer } from '@rpgjs/common'
|
|
2
|
+
import TileMap from '../Tilemap'
|
|
3
|
+
import { Viewport } from 'pixi-viewport'
|
|
4
|
+
import { Scene, SceneObservableData, SceneSpriteLogic } from './Scene'
|
|
5
|
+
import { spritesheets } from '../Sprite/Spritesheets'
|
|
6
|
+
import { RpgSound } from '../Sound/RpgSound'
|
|
7
|
+
import { GameEngineClient } from '../GameEngine'
|
|
8
|
+
import { TiledLayerType, TiledMap } from '@rpgjs/tiled'
|
|
9
|
+
import { RpgComponent } from '../Components/Component'
|
|
10
|
+
import { CameraOptions } from '@rpgjs/types'
|
|
11
|
+
import { Assets, Container, Point, IRenderer, DisplayObjectEvents, utils, FederatedPointerEvent } from 'pixi.js'
|
|
12
|
+
import { EventLayer } from './EventLayer'
|
|
13
|
+
|
|
14
|
+
interface MapObject extends TiledMap {
|
|
15
|
+
id: number
|
|
16
|
+
sounds: string | string[] | undefined
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class SceneMap extends Scene {
|
|
20
|
+
static readonly EVENTS_LAYER_DEFAULT: string = 'events-layer-default'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get the tilemap
|
|
24
|
+
*
|
|
25
|
+
* @prop {PIXI.Container} [tilemap]
|
|
26
|
+
* @memberof RpgSceneMap
|
|
27
|
+
* */
|
|
28
|
+
public tilemap: TileMap
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The viewport of the map
|
|
32
|
+
*
|
|
33
|
+
* It automatically follows the sprite representing the player but you can attach it to something else
|
|
34
|
+
*
|
|
35
|
+
* > Do not change the size of the viewport
|
|
36
|
+
*
|
|
37
|
+
* @prop {PIXI.Viewport} viewport
|
|
38
|
+
* @memberof RpgSceneMap
|
|
39
|
+
* */
|
|
40
|
+
public viewport: Viewport | undefined
|
|
41
|
+
private players: object = {}
|
|
42
|
+
private isLoaded: boolean = false
|
|
43
|
+
private gameMap: RpgCommonMap | undefined
|
|
44
|
+
private eventsLayers: {
|
|
45
|
+
[eventLayerName: string]: Container
|
|
46
|
+
} = {}
|
|
47
|
+
private defaultLayer: Container | undefined
|
|
48
|
+
|
|
49
|
+
shapes = {}
|
|
50
|
+
|
|
51
|
+
constructor(
|
|
52
|
+
public game: GameEngineClient,
|
|
53
|
+
private renderer: IRenderer,
|
|
54
|
+
private options: { screenWidth?: number, screenHeight?: number, drawMap?: boolean } = {}) {
|
|
55
|
+
super(game)
|
|
56
|
+
if (options.drawMap === undefined) this.options.drawMap = true
|
|
57
|
+
this.onInit()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private constructMethods() {
|
|
61
|
+
[
|
|
62
|
+
'getTileIndex',
|
|
63
|
+
'getTileByIndex',
|
|
64
|
+
'getTileOriginPosition',
|
|
65
|
+
'getTileByPosition',
|
|
66
|
+
'getLayerByName'
|
|
67
|
+
].forEach(method => this[method] = (this.gameMap as any)[method].bind(this.gameMap));
|
|
68
|
+
[
|
|
69
|
+
'heightPx',
|
|
70
|
+
'widthPx',
|
|
71
|
+
'zTileHeight',
|
|
72
|
+
'tileHeight',
|
|
73
|
+
'tileWidth',
|
|
74
|
+
'data',
|
|
75
|
+
'layers'
|
|
76
|
+
].forEach(prop => this[prop] = (this.gameMap as any)[prop])
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** @internal */
|
|
81
|
+
async load(obj: MapObject, prevObj: MapObject, isUpdate = false): Promise<Viewport> {
|
|
82
|
+
let { sounds } = obj
|
|
83
|
+
const { clientEngine } = this.game
|
|
84
|
+
|
|
85
|
+
if (sounds) {
|
|
86
|
+
if (!Utils.isArray(sounds)) sounds = obj.sounds = <string[]>[sounds]
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this.gameMap = new RpgCommonMap()
|
|
90
|
+
this.gameMap.load(obj)
|
|
91
|
+
this.gameMap.clearCacheTilesets()
|
|
92
|
+
this.constructMethods()
|
|
93
|
+
|
|
94
|
+
RpgCommonMap.bufferClient.set(obj.id, this.gameMap)
|
|
95
|
+
|
|
96
|
+
this.tilemap = new TileMap(this.gameMap.getData(), this.game.renderer)
|
|
97
|
+
|
|
98
|
+
// TODO: Remove this
|
|
99
|
+
Assets.reset()
|
|
100
|
+
|
|
101
|
+
let nbLoad = 0
|
|
102
|
+
|
|
103
|
+
const objects = this.game.world.getObjectsOfGroup()
|
|
104
|
+
|
|
105
|
+
for (let { object } of Object.values(objects) as any[]) {
|
|
106
|
+
if (Utils.isInstanceOf(object, RpgCommonPlayer) && object) {
|
|
107
|
+
(object as RpgCommonPlayer).updateInVirtualGrid()
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const assets: string[] = []
|
|
112
|
+
for (let tileset of this.tilemap.tilesets) {
|
|
113
|
+
let spritesheet = spritesheets.get(tileset.name)
|
|
114
|
+
if (!spritesheet) {
|
|
115
|
+
clientEngine.addSpriteSheet(tileset.image.source, tileset.name)
|
|
116
|
+
spritesheet = spritesheets.get(tileset.name)
|
|
117
|
+
}
|
|
118
|
+
if (spritesheet?.resource) {
|
|
119
|
+
continue
|
|
120
|
+
}
|
|
121
|
+
Assets.add(tileset.name, spritesheet.image)
|
|
122
|
+
assets.push(tileset.name)
|
|
123
|
+
nbLoad++
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (nbLoad > 0) {
|
|
127
|
+
const assetsLoaded = await Assets.load(assets)
|
|
128
|
+
for (let assetName in assetsLoaded) {
|
|
129
|
+
if (!assetsLoaded[assetName]) console.log(assetName, assetsLoaded[assetName])
|
|
130
|
+
const spritesheet = spritesheets.get(assetName)
|
|
131
|
+
if (spritesheet) spritesheet.resource = assetsLoaded[assetName]
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
RpgPlugin.emit(HookClient.SceneMapLoading, Assets)
|
|
136
|
+
|
|
137
|
+
this.tilemap.load({
|
|
138
|
+
drawTiles: this.options.drawMap,
|
|
139
|
+
isUpdate
|
|
140
|
+
})
|
|
141
|
+
this.viewport = new Viewport({
|
|
142
|
+
screenWidth: this.options.screenWidth,
|
|
143
|
+
screenHeight: this.options.screenHeight,
|
|
144
|
+
worldWidth: obj.width * obj.tilewidth,
|
|
145
|
+
worldHeight: obj.height * obj.tileheight,
|
|
146
|
+
noTicker: true,
|
|
147
|
+
events: this.renderer.events
|
|
148
|
+
})
|
|
149
|
+
this.tilemap.addChild(this.animationLayer)
|
|
150
|
+
this.viewport.clamp({ direction: 'all' })
|
|
151
|
+
this.viewport.addChild(this.tilemap, ...this.createEventLayers(obj))
|
|
152
|
+
this.isLoaded = true
|
|
153
|
+
if (prevObj.sounds && prevObj.sounds instanceof Array) {
|
|
154
|
+
prevObj.sounds.forEach(soundId => {
|
|
155
|
+
const continueSound = (<string[]>obj.sounds || []).find(id => id == soundId)
|
|
156
|
+
if (!continueSound) RpgSound.stop(soundId)
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
if (sounds) (<string[]>sounds).forEach(soundId => RpgSound.play(soundId))
|
|
160
|
+
if (this.onLoad) this.onLoad()
|
|
161
|
+
|
|
162
|
+
return this.viewport
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
createEventLayers(map: MapObject): Container[] {
|
|
166
|
+
const containers: Container[] = []
|
|
167
|
+
map.layers.forEach((layerData) => {
|
|
168
|
+
if (layerData.type !== TiledLayerType.ObjectGroup) return
|
|
169
|
+
if (this.eventsLayers[layerData.name]) {
|
|
170
|
+
containers.push(this.eventsLayers[layerData.name])
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
const layer = new EventLayer()
|
|
174
|
+
this.defaultLayer = this.eventsLayers[layerData.name] = layer
|
|
175
|
+
containers.push(layer)
|
|
176
|
+
})
|
|
177
|
+
if (containers.length == 0) {
|
|
178
|
+
if (!this.defaultLayer) {
|
|
179
|
+
this.defaultLayer = new EventLayer()
|
|
180
|
+
}
|
|
181
|
+
containers.push(this.defaultLayer)
|
|
182
|
+
}
|
|
183
|
+
this.cameraFollowSprite(this.game.playerId)
|
|
184
|
+
return containers
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
getEventLayer(objectName?: string): Container | undefined {
|
|
188
|
+
for (let layerData of this.data.layers) {
|
|
189
|
+
if (layerData.type != TiledLayerType.ObjectGroup) {
|
|
190
|
+
continue
|
|
191
|
+
}
|
|
192
|
+
if (!layerData.objects) {
|
|
193
|
+
continue
|
|
194
|
+
}
|
|
195
|
+
for (let object of layerData.objects) {
|
|
196
|
+
if (object.name == objectName) {
|
|
197
|
+
return this.eventsLayers[layerData.name]
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return this.defaultLayer
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** @internal */
|
|
205
|
+
changeTile(x: number, y: number, layers: {
|
|
206
|
+
[layerName: string]: object
|
|
207
|
+
}) {
|
|
208
|
+
for (let layerName in layers) {
|
|
209
|
+
const layerInfo = layers[layerName]
|
|
210
|
+
this.gameMap?.setTile(x, y, layerName, layerInfo)
|
|
211
|
+
this.tilemap.changeTile(x, y, layerName)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** @internal */
|
|
216
|
+
draw(t: number, deltaTime: number, deltaRatio: number, frame: number) {
|
|
217
|
+
if (!this.isLoaded) {
|
|
218
|
+
return
|
|
219
|
+
}
|
|
220
|
+
super.draw(t, deltaTime, deltaRatio, frame)
|
|
221
|
+
this.tilemap.drawAnimateTile(frame)
|
|
222
|
+
this.viewport?.update(deltaTime)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// @internal
|
|
226
|
+
updateTilesOverlayAllSprites() {
|
|
227
|
+
const objects = this.objects
|
|
228
|
+
for (let [id, sprite] of objects) {
|
|
229
|
+
this.updateTilesOverlay(sprite)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private updateTilesOverlay(sprite: RpgComponent) {
|
|
234
|
+
if (!this.gameMap) return sprite
|
|
235
|
+
const { tileWidth, tileHeight } = this.gameMap
|
|
236
|
+
const { tilesOverlay }: any = sprite
|
|
237
|
+
const bounds = sprite.parent.getLocalBounds()
|
|
238
|
+
const width = Math.ceil(bounds.width / tileWidth) * tileWidth
|
|
239
|
+
const height = Math.ceil(bounds.height / tileHeight) * tileHeight
|
|
240
|
+
const _x = bounds.x
|
|
241
|
+
const _y = bounds.y
|
|
242
|
+
|
|
243
|
+
const addTile = (x, y) => {
|
|
244
|
+
const tiles = this.tilemap.createOverlayTiles(x, y, sprite)
|
|
245
|
+
if (tiles.length) tilesOverlay.addChild(...tiles)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
tilesOverlay.removeChildren()
|
|
249
|
+
|
|
250
|
+
for (let i = _x; i <= _x + width; i += tileWidth) {
|
|
251
|
+
for (let j = _y; j <= _y + height; j += tileHeight) {
|
|
252
|
+
addTile(i, j)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return sprite
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
onUpdateObject(logic: SceneSpriteLogic, sprite: RpgComponent, moving: boolean): RpgComponent {
|
|
259
|
+
const { paramsChanged } = logic
|
|
260
|
+
if (!this.gameMap) return sprite
|
|
261
|
+
if (moving || (paramsChanged && (paramsChanged.width || paramsChanged.height))) {
|
|
262
|
+
this.updateTilesOverlay(sprite)
|
|
263
|
+
}
|
|
264
|
+
return sprite
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** @internal */
|
|
268
|
+
setPlayerPosition(id: string, { x, y }: { x: number, y: number }) {
|
|
269
|
+
this.players[id].x = x
|
|
270
|
+
this.players[id].y = y
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** @internal */
|
|
274
|
+
updateScene(obj: SceneObservableData) { }
|
|
275
|
+
|
|
276
|
+
addObject(obj: RpgCommonPlayer | RpgShape, id: string): RpgComponent {
|
|
277
|
+
const wrapper = new Container()
|
|
278
|
+
const inner = new Container()
|
|
279
|
+
const tilesOverlay = new Container()
|
|
280
|
+
const component = new RpgComponent(obj, this)
|
|
281
|
+
|
|
282
|
+
component.tilesOverlay = tilesOverlay
|
|
283
|
+
inner.addChild(component)
|
|
284
|
+
wrapper.addChild(inner, tilesOverlay)
|
|
285
|
+
|
|
286
|
+
this.objects.set(id, component)
|
|
287
|
+
this.getEventLayer(obj.id)?.addChild(wrapper)
|
|
288
|
+
if (component.isCurrentPlayer) this.cameraFollowSprite(id)
|
|
289
|
+
component.onInit()
|
|
290
|
+
return component
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
removeObject(id: string) {
|
|
294
|
+
let sprite = this.objects.get(id)
|
|
295
|
+
if (sprite) {
|
|
296
|
+
this.objects.delete(id)
|
|
297
|
+
RpgPlugin.emit(HookClient.SceneRemoveSprite, [this, sprite], true)
|
|
298
|
+
RpgPlugin.emit(HookClient.RemoveSprite, sprite)
|
|
299
|
+
sprite.destroy()
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
getShape(name: string): RpgShape | undefined {
|
|
304
|
+
return this.game.getShape(name)?.object
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
getShapes(): RpgShape[] {
|
|
308
|
+
const shapes = Object.values(this.game.getShapes())
|
|
309
|
+
return shapes.map(shape => shape.object)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
cameraFollowSprite(id: string, options: CameraOptions = {}) {
|
|
313
|
+
const sprite = this.getSprite(id)
|
|
314
|
+
const follow = () => {
|
|
315
|
+
if (sprite) this.viewport?.follow(sprite)
|
|
316
|
+
}
|
|
317
|
+
if (options.smoothMove) {
|
|
318
|
+
this.viewport?.plugins.remove('follow')
|
|
319
|
+
let moreOptions = {}
|
|
320
|
+
if (typeof options.smoothMove != 'boolean') {
|
|
321
|
+
moreOptions = options.smoothMove
|
|
322
|
+
}
|
|
323
|
+
this.viewport?.animate({
|
|
324
|
+
position: new Point(sprite?.x, sprite?.y),
|
|
325
|
+
...moreOptions,
|
|
326
|
+
callbackOnComplete: follow
|
|
327
|
+
})
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
follow()
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Listen to the events of the smile on the stage
|
|
336
|
+
*
|
|
337
|
+
* @title Listen mouse event
|
|
338
|
+
* @method on(eventName,callback)
|
|
339
|
+
* @since 3.0.0-beta.4
|
|
340
|
+
* @param {string} eventName Name of the event (see PIXI documentation). Name often used in the codes
|
|
341
|
+
* - click
|
|
342
|
+
* - mousedown
|
|
343
|
+
* - mouseup
|
|
344
|
+
* - mousemove
|
|
345
|
+
* - pointerdown
|
|
346
|
+
* - pointermove
|
|
347
|
+
* - pointerup
|
|
348
|
+
* - (etc...)
|
|
349
|
+
* @param {(position: { x: number, y: number }, ev?: PIXI.InteractionEvent ) => any} callback
|
|
350
|
+
* @example
|
|
351
|
+
* ```ts
|
|
352
|
+
* sceneMap.on('pointerdown', (position) => {
|
|
353
|
+
* console.log(position)
|
|
354
|
+
* })
|
|
355
|
+
* ```
|
|
356
|
+
* @returns {void}
|
|
357
|
+
* @memberof RpgSceneMap
|
|
358
|
+
*/
|
|
359
|
+
on(eventName: keyof DisplayObjectEvents, cb: (position: { x: number, y: number }, ev?: any) => any) {
|
|
360
|
+
if (!this.viewport) return
|
|
361
|
+
this.viewport.eventMode = 'static'
|
|
362
|
+
this.viewport.on(eventName, (...args) => {
|
|
363
|
+
const ev: FederatedPointerEvent = args[0] as any
|
|
364
|
+
const pos = ev.getLocalPosition(this.viewport as Viewport)
|
|
365
|
+
cb(pos, ev)
|
|
366
|
+
})
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export interface SceneMap {
|
|
371
|
+
data: any;
|
|
372
|
+
tileWidth: number;
|
|
373
|
+
tileHeight: number;
|
|
374
|
+
layers: any[];
|
|
375
|
+
widthPx: number;
|
|
376
|
+
heightPx: number;
|
|
377
|
+
zTileHeight: number
|
|
378
|
+
getShapes(): RpgShape[];
|
|
379
|
+
getShape(name: string): RpgShape | undefined;
|
|
380
|
+
getPositionByShape(filter: (shape: RpgShape) => {}): {
|
|
381
|
+
x: number;
|
|
382
|
+
y: number;
|
|
383
|
+
z: number;
|
|
384
|
+
} | null;
|
|
385
|
+
getTileIndex(x: number, y: number, [z]?: [number]): number;
|
|
386
|
+
getTileByIndex(tileIndex: number, zPlayer?: [number, number]): any;
|
|
387
|
+
getTileOriginPosition(x: number, y: number): {
|
|
388
|
+
x: number;
|
|
389
|
+
y: number;
|
|
390
|
+
};
|
|
391
|
+
getTileByPosition(x: number, y: number, z?: [number, number]): any;
|
|
392
|
+
getLayerByName(name: string): any
|
|
393
|
+
}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { RpgPlugin, HookClient, DefaultInput } from '@rpgjs/common'
|
|
2
|
+
import { KeyboardControls } from '../KeyboardControls'
|
|
3
|
+
import RpgSprite from '../Sprite/Character'
|
|
4
|
+
import { Animation } from '../Effects/Animation'
|
|
5
|
+
import { BehaviorSubject, Observable } from 'rxjs'
|
|
6
|
+
import { RpgGui } from '../RpgGui'
|
|
7
|
+
import { GameEngineClient } from '../GameEngine'
|
|
8
|
+
import { RpgComponent } from '../Components/Component'
|
|
9
|
+
import { Controls } from '@rpgjs/types'
|
|
10
|
+
import { Container } from 'pixi.js'
|
|
11
|
+
|
|
12
|
+
export type SceneObservableData = {
|
|
13
|
+
data: {
|
|
14
|
+
[key: string]: any
|
|
15
|
+
},
|
|
16
|
+
partial: {
|
|
17
|
+
[key: string]: any
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface SceneSpriteLogic {
|
|
22
|
+
paramsChanged: {
|
|
23
|
+
[key: string]: any
|
|
24
|
+
} | null,
|
|
25
|
+
prevParamsChanged: object
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export abstract class Scene {
|
|
29
|
+
protected objects: Map<string, RpgComponent> = new Map()
|
|
30
|
+
protected animationLayer: Container = new Container()
|
|
31
|
+
|
|
32
|
+
private controls: KeyboardControls
|
|
33
|
+
private animations: Animation[] = []
|
|
34
|
+
|
|
35
|
+
private _data: BehaviorSubject<SceneObservableData> = new BehaviorSubject({
|
|
36
|
+
data: {},
|
|
37
|
+
partial: {}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
constructor(public game: GameEngineClient) {
|
|
41
|
+
const { globalConfig } = this.game.clientEngine
|
|
42
|
+
this.controls = this.game.clientEngine.controls
|
|
43
|
+
const mergeInputs = {
|
|
44
|
+
...DefaultInput,
|
|
45
|
+
...(globalConfig.inputs || {})
|
|
46
|
+
}
|
|
47
|
+
this.controls.setInputs(this.inputs || mergeInputs)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Listen to all the synchronized values of the scene with the server
|
|
52
|
+
*
|
|
53
|
+
* ```ts
|
|
54
|
+
* import { RpgClient, RpgModule, RpgSceneMap, RpgSprite } from '@rpgjs/client'
|
|
55
|
+
*
|
|
56
|
+
* @RpgModule<RpgClient>({
|
|
57
|
+
scenes: {
|
|
58
|
+
map: {
|
|
59
|
+
onAfterLoading(scene: RpgSceneMap, sprite: RpgSprite) {
|
|
60
|
+
scene.valuesChange.subscribe((obj) => {
|
|
61
|
+
console.log(obj.data, obj.partial)
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
export default class RpgClientModuleEngine {}
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* - `data` represents all the current data of the scene (`users`, `events` and others)
|
|
71
|
+
* - `partial` represents only the data that has changed on the scene
|
|
72
|
+
*
|
|
73
|
+
* > In the class, you can also use the onChanges hook
|
|
74
|
+
*
|
|
75
|
+
*
|
|
76
|
+
* @prop {Observable<{ data: object, partial: object }>} [valuesChange]
|
|
77
|
+
* @readonly
|
|
78
|
+
* @memberof RpgScene
|
|
79
|
+
*/
|
|
80
|
+
get valuesChange(): Observable<SceneObservableData> {
|
|
81
|
+
return this._data.asObservable()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private triggerSpriteChanges(logic: SceneSpriteLogic, sprite: RpgComponent, moving: boolean) {
|
|
85
|
+
if (this.onUpdateObject) this.onUpdateObject(logic, sprite, moving)
|
|
86
|
+
RpgPlugin.emit(HookClient.UpdateSprite, [sprite, logic], true)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** @internal */
|
|
90
|
+
update(obj?: SceneObservableData) {
|
|
91
|
+
if (!obj) {
|
|
92
|
+
this.updateScene(this._data.value)
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
this.updateScene(obj)
|
|
96
|
+
RpgPlugin.emit(HookClient.SceneOnChanges, [this, obj], true)
|
|
97
|
+
this._data.next(obj)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** @internal */
|
|
101
|
+
draw(t: number, deltaTime: number, deltaRatio: number, frame: number) {
|
|
102
|
+
const logicObjects = {
|
|
103
|
+
...this.game.world.getObjects(),
|
|
104
|
+
...this.game.events,
|
|
105
|
+
...this.game.getShapes()
|
|
106
|
+
}
|
|
107
|
+
const renderObjects = this.objects
|
|
108
|
+
const sizeLogic = Object.values(logicObjects).length
|
|
109
|
+
for (let key in logicObjects) {
|
|
110
|
+
const val: SceneSpriteLogic = logicObjects[key].object
|
|
111
|
+
const valueChanged = logicObjects[key].paramsChanged
|
|
112
|
+
if (!renderObjects.has(key)) {
|
|
113
|
+
const sprite = this.addObject(val, key)
|
|
114
|
+
this.triggerSpriteChanges(val, sprite, true)
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
const object = renderObjects.get(key)
|
|
118
|
+
if (!object?.update) return
|
|
119
|
+
const ret = object.update(val, valueChanged, t, deltaRatio)
|
|
120
|
+
this.triggerSpriteChanges(val, object, ret.moving)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (sizeLogic < renderObjects.size) {
|
|
124
|
+
renderObjects.forEach((val, key) => {
|
|
125
|
+
if (!logicObjects[key]) {
|
|
126
|
+
this.removeObject(key)
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
for (let animation of this.animations) {
|
|
131
|
+
animation.update(deltaRatio)
|
|
132
|
+
}
|
|
133
|
+
this.onDraw(t)
|
|
134
|
+
RpgGui.update(logicObjects)
|
|
135
|
+
RpgPlugin.emit(HookClient.SceneDraw, this)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
abstract onUpdateObject(logic: SceneSpriteLogic, sprite: RpgComponent, moving: boolean): void
|
|
139
|
+
abstract addObject(obj, id: string): RpgComponent
|
|
140
|
+
abstract removeObject(id: string)
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Display an animation on the scene
|
|
144
|
+
*
|
|
145
|
+
* The object is the following:
|
|
146
|
+
* * `graphic`: Spritesheet id
|
|
147
|
+
* * `animationName`: The name of the animation
|
|
148
|
+
* * `attachTo`: Define a sprite. The animation will follow this sprite (optional)
|
|
149
|
+
* * `x`: Position X (0 by default)
|
|
150
|
+
* * `y`: Position Y (0 by default)
|
|
151
|
+
* * `loop`: Display the animation in a loop (false by default)
|
|
152
|
+
*
|
|
153
|
+
* ```ts
|
|
154
|
+
* import { RpgClient, RpgModule, RpgSceneMap, RpgSprite } from '@rpgjs/client'
|
|
155
|
+
*
|
|
156
|
+
|
|
157
|
+
* @RpgModule<RpgClient>({
|
|
158
|
+
scenes: {
|
|
159
|
+
map: {
|
|
160
|
+
onAfterLoading(scene: RpgSceneMap, sprite: RpgSprite) {
|
|
161
|
+
const animation = scene.showAnimation({
|
|
162
|
+
graphic: 'my-spritesheet',
|
|
163
|
+
animationName: 'my-anim'
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
export default class RpgClientModuleEngine {}
|
|
170
|
+
* ```
|
|
171
|
+
*
|
|
172
|
+
* The return is an animation containing two methods:
|
|
173
|
+
* * `play()`: Play the animation (Already the case when calling the method)
|
|
174
|
+
* * `stop()`: Stop the animation
|
|
175
|
+
*
|
|
176
|
+
* They have a hook:
|
|
177
|
+
*
|
|
178
|
+
* `onFinish`: Triggered when the animation is finished
|
|
179
|
+
*
|
|
180
|
+
* ```ts
|
|
181
|
+
* animation.onFinish = () => {
|
|
182
|
+
* console.log('finish !')
|
|
183
|
+
* }
|
|
184
|
+
* ```
|
|
185
|
+
*
|
|
186
|
+
* @title Show Animation
|
|
187
|
+
* @method scene.showAnimation(object)
|
|
188
|
+
* @param {object} object
|
|
189
|
+
* @returns {Animation}
|
|
190
|
+
* @memberof RpgScene
|
|
191
|
+
*/
|
|
192
|
+
showAnimation({
|
|
193
|
+
graphic,
|
|
194
|
+
animationName,
|
|
195
|
+
attachTo,
|
|
196
|
+
x = 0,
|
|
197
|
+
y = 0,
|
|
198
|
+
loop = false,
|
|
199
|
+
replaceGraphic = false
|
|
200
|
+
}: {
|
|
201
|
+
graphic: string,
|
|
202
|
+
animationName: string,
|
|
203
|
+
attachTo?: RpgComponent,
|
|
204
|
+
x?: number,
|
|
205
|
+
y?: number,
|
|
206
|
+
loop?: boolean,
|
|
207
|
+
replaceGraphic?: boolean
|
|
208
|
+
}): Animation | undefined {
|
|
209
|
+
if (replaceGraphic && attachTo) {
|
|
210
|
+
attachTo.showAnimation(graphic, animationName)
|
|
211
|
+
return
|
|
212
|
+
}
|
|
213
|
+
const animation = new Animation(graphic)
|
|
214
|
+
this.animationLayer.addChild(animation)
|
|
215
|
+
if (!loop) {
|
|
216
|
+
animation.onFinish = () => {
|
|
217
|
+
animation.stop()
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (attachTo) {
|
|
221
|
+
animation.attachTo = attachTo
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
animation.x = x
|
|
225
|
+
animation.y = y
|
|
226
|
+
}
|
|
227
|
+
animation.play(animationName)
|
|
228
|
+
this.animations.push(animation)
|
|
229
|
+
return animation
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Retrieve a sprite according to its identifier
|
|
234
|
+
*
|
|
235
|
+
* @title Get Sprite
|
|
236
|
+
* @method scene.getSprite(id)
|
|
237
|
+
* @param {string} id
|
|
238
|
+
* @returns {RpgSprite | undefined}
|
|
239
|
+
* @memberof RpgScene
|
|
240
|
+
*/
|
|
241
|
+
getSprite(id: string) { return this.getPlayer(id) }
|
|
242
|
+
getPlayer(id: string): RpgComponent | undefined {
|
|
243
|
+
return this.objects.get(id)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Retrieve a sprite that the player controls
|
|
248
|
+
*
|
|
249
|
+
* @title Get Current Player
|
|
250
|
+
* @method scene.getCurrentPlayer()
|
|
251
|
+
* @returns {RpgSprite | undefined}
|
|
252
|
+
* @memberof RpgScene
|
|
253
|
+
*/
|
|
254
|
+
getCurrentPlayer(): RpgSprite | RpgComponent | undefined {
|
|
255
|
+
return this.objects.get(this.game.playerId)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Hooks
|
|
259
|
+
onInit() {}
|
|
260
|
+
onLoad() {}
|
|
261
|
+
onChanges(obj) {}
|
|
262
|
+
onDraw(t: number) {}
|
|
263
|
+
onAddSprite(sprite: RpgSprite) {}
|
|
264
|
+
onRemoveSprite(sprite: RpgSprite) {}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export interface Scene {
|
|
268
|
+
inputs: Controls,
|
|
269
|
+
updateScene(obj: SceneObservableData)
|
|
270
|
+
}
|