@rpgjs/common 3.3.2 → 4.0.0-beta.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 (80) hide show
  1. package/LICENSE +19 -0
  2. package/lib/AbstractObject.d.ts +3 -2
  3. package/lib/AbstractObject.js +296 -323
  4. package/lib/AbstractObject.js.map +1 -1
  5. package/lib/Color.js +1 -5
  6. package/lib/Color.js.map +1 -1
  7. package/lib/Event.js +2 -6
  8. package/lib/Event.js.map +1 -1
  9. package/lib/EventEmitter.js +3 -7
  10. package/lib/EventEmitter.js.map +1 -1
  11. package/lib/Game.js +73 -85
  12. package/lib/Game.js.map +1 -1
  13. package/lib/Hit.js +21 -28
  14. package/lib/Hit.js.map +1 -1
  15. package/lib/Logger.js +2 -7
  16. package/lib/Logger.js.map +1 -1
  17. package/lib/Map.d.ts +1 -0
  18. package/lib/Map.js +29 -53
  19. package/lib/Map.js.map +1 -1
  20. package/lib/Module.d.ts +2 -2
  21. package/lib/Module.js +84 -97
  22. package/lib/Module.js.map +1 -1
  23. package/lib/Player.d.ts +1 -0
  24. package/lib/Player.js +4 -7
  25. package/lib/Player.js.map +1 -1
  26. package/lib/Plugin.d.ts +4 -3
  27. package/lib/Plugin.js +14 -14
  28. package/lib/Plugin.js.map +1 -1
  29. package/lib/Scheduler.js +14 -21
  30. package/lib/Scheduler.js.map +1 -1
  31. package/lib/Shape.d.ts +1 -1
  32. package/lib/Shape.js +39 -52
  33. package/lib/Shape.js.map +1 -1
  34. package/lib/Utils.d.ts +4 -1
  35. package/lib/Utils.js +38 -53
  36. package/lib/Utils.js.map +1 -1
  37. package/lib/Vector2d.js +3 -8
  38. package/lib/Vector2d.js.map +1 -1
  39. package/lib/VirtualGrid.d.ts +1 -1
  40. package/lib/VirtualGrid.js +5 -12
  41. package/lib/VirtualGrid.js.map +1 -1
  42. package/lib/Worker.js +2 -10
  43. package/lib/Worker.js.map +1 -1
  44. package/lib/WorldMaps.d.ts +3 -1
  45. package/lib/WorldMaps.js +29 -15
  46. package/lib/WorldMaps.js.map +1 -1
  47. package/lib/gui/PrebuiltGui.js +2 -5
  48. package/lib/gui/PrebuiltGui.js.map +1 -1
  49. package/lib/index.d.ts +3 -1
  50. package/lib/index.js +24 -69
  51. package/lib/index.js.map +1 -1
  52. package/lib/transports/io.js +5 -9
  53. package/lib/transports/io.js.map +1 -1
  54. package/lib/workers/move.js +26 -42
  55. package/lib/workers/move.js.map +1 -1
  56. package/package.json +9 -11
  57. package/src/AbstractObject.ts +915 -0
  58. package/src/Color.ts +29 -0
  59. package/src/DefaultInput.ts +26 -0
  60. package/src/Event.ts +3 -0
  61. package/src/EventEmitter.ts +52 -0
  62. package/src/Game.ts +150 -0
  63. package/src/Hit.ts +70 -0
  64. package/src/Logger.ts +7 -0
  65. package/src/Map.ts +335 -0
  66. package/src/Module.ts +108 -0
  67. package/src/Player.ts +30 -0
  68. package/src/Plugin.ts +91 -0
  69. package/src/Scheduler.ts +88 -0
  70. package/src/Shape.ts +300 -0
  71. package/src/Utils.ts +168 -0
  72. package/src/Vector2d.ts +70 -0
  73. package/src/VirtualGrid.ts +78 -0
  74. package/src/Worker.ts +17 -0
  75. package/src/WorldMaps.ts +204 -0
  76. package/src/gui/PrebuiltGui.ts +27 -0
  77. package/src/index.ts +24 -0
  78. package/src/transports/io.ts +91 -0
  79. package/src/workers/move.ts +61 -0
  80. package/tsconfig.json +25 -0
package/src/Module.ts ADDED
@@ -0,0 +1,108 @@
1
+ import { RpgPlugin, HookServer, HookClient } from './Plugin'
2
+ import { isArray, isClass, isFunction, isPromise } from './Utils'
3
+ import { warning } from './Logger'
4
+
5
+ enum Side {
6
+ Server = 'server',
7
+ Client = 'client'
8
+ }
9
+
10
+ type ModuleSide = {
11
+ client?: any,
12
+ server?: any
13
+ }
14
+
15
+ export type ModuleType = ModuleSide | [ModuleSide, {
16
+ client?: any,
17
+ server?: any
18
+ }]
19
+
20
+ export function RpgModule<T>(options: T) {
21
+ return (target) => {
22
+ for (let key in options) {
23
+ target.prototype[key] = options[key]
24
+ }
25
+ }
26
+ }
27
+
28
+ export async function loadModules(modules, obj, middleware?: Function): Promise<{ playerProps: any }> {
29
+ const { side, relations } = obj
30
+ let playerProps = {}
31
+ for (let module of modules) {
32
+ if (!module) continue
33
+ let plug: any = []
34
+ if (!isArray(module)) {
35
+ plug = [module]
36
+ }
37
+ else {
38
+ plug = module
39
+ }
40
+ const [moduleClassSides, options] = plug
41
+ const moduleClass = moduleClassSides[side]
42
+ if (!moduleClass) continue
43
+ let mod
44
+ if (options && side == Side.Client && options[Side.Server]) {
45
+ warning(`Data that may be sensitive (normally visible only on the server side) are made optional and visible on the client side.\nInstead, import the configuration with the server! flag into an import. Example: \n\nimport config from 'server!./config\n\n'`, options[Side.Server])
46
+ }
47
+ if (options && !isClass(moduleClass) && isFunction(moduleClass)) {
48
+ mod = new (moduleClass(options[side]))()
49
+ }
50
+ else if (isClass(moduleClass)) {
51
+ mod = new moduleClass()
52
+ }
53
+ else {
54
+ mod = moduleClass
55
+ }
56
+ if (middleware) {
57
+ mod = middleware(mod)
58
+ if (isPromise(mod)) {
59
+ mod = await mod
60
+ }
61
+ }
62
+ const { imports, maps, spritesheets, sounds, gui, scenes, engine, database, worldMaps, scalability, events } = mod
63
+ if (imports) {
64
+ await loadModules(imports, obj)
65
+ }
66
+ if (maps) {
67
+ RpgPlugin.on(HookServer.AddMap, () => maps)
68
+ }
69
+ if (events) {
70
+ RpgPlugin.on(HookServer.AddEvent, () => events)
71
+ }
72
+ if (worldMaps) {
73
+ RpgPlugin.on(HookServer.AddWorldMaps, () => worldMaps)
74
+ }
75
+ if (database) {
76
+ RpgPlugin.on(HookServer.AddDatabase, () => database)
77
+ }
78
+ if (spritesheets) {
79
+ RpgPlugin.on(HookClient.AddSpriteSheet, () => spritesheets)
80
+ }
81
+ if (sounds) {
82
+ RpgPlugin.on(HookClient.AddSound, () => sounds)
83
+ }
84
+ if (gui) {
85
+ RpgPlugin.on(HookClient.AddGui, () => gui)
86
+ }
87
+ const player = side == Side.Server ? mod.player : mod.sprite
88
+ const loadRelations = (hook, relatioName) => {
89
+ if (hook) {
90
+ for (let method in relations[relatioName]) {
91
+ const hookName = relations[relatioName][method]
92
+ if (hook[method]) RpgPlugin.on(hookName, hook[method])
93
+ }
94
+ }
95
+ }
96
+ loadRelations(player, 'player')
97
+ if (player && player.props) {
98
+ playerProps = Object.assign(playerProps, player.props)
99
+ }
100
+ loadRelations(engine, 'engine')
101
+ if (scalability) loadRelations(scalability._hooks, 'scalability')
102
+ if (scenes) loadRelations(scenes.map, 'sceneMap')
103
+ }
104
+
105
+ return {
106
+ playerProps
107
+ }
108
+ }
package/src/Player.ts ADDED
@@ -0,0 +1,30 @@
1
+ import { PendingMove } from '@rpgjs/types'
2
+ import { AbstractObject } from './AbstractObject'
3
+
4
+ export const LiteralDirection = {
5
+ 1: 'up',
6
+ 2: 'right',
7
+ 3: 'down',
8
+ 4: 'left'
9
+ }
10
+
11
+ export class RpgCommonPlayer extends AbstractObject {
12
+ events: any[] = []
13
+ layerName: string = ''
14
+ data: any = {}
15
+ pendingMove: PendingMove = []
16
+ inputsTimestamp: {
17
+ [inputName: string]: number
18
+ } = {}
19
+
20
+ /**
21
+ * Display/Hide the GUI attached to this sprite
22
+ *
23
+ * @prop {boolean} guiDisplay
24
+ * @since 3.0.0-beta.5
25
+ * @memberof RpgSprite
26
+ * */
27
+ guiDisplay: boolean
28
+ }
29
+
30
+ export default AbstractObject
package/src/Plugin.ts ADDED
@@ -0,0 +1,91 @@
1
+ import { EventEmitter } from './EventEmitter'
2
+ import { isArray } from './Utils'
3
+
4
+ type PluginFunction = (obj: any, options?: any) => void
5
+ type PluginSides = { client: null | PluginFunction, server: null | PluginFunction }
6
+ export type Plugin = PluginSides | [PluginSides, any]
7
+
8
+ export enum HookServer {
9
+ Start = 'Server.Start',
10
+ Step = "Server.Step",
11
+ PlayerConnected = 'Server.onConnected',
12
+ PlayerDisconnected = 'Server.onDisconnected',
13
+ AddMap = 'Server.AddMap',
14
+ AddEvent = 'Server.AddEvent',
15
+ AddWorldMaps = 'Server.AddWorldMaps',
16
+ AddDatabase = 'Server.AddDatabase',
17
+ PlayerInput = 'Server.onInput',
18
+ PlayerJoinMap = 'Server.onJoinMap',
19
+ PlayerLeaveMap = 'Server.onLeaveMap',
20
+ PlayerLevelUp = 'Server.onLevelUp',
21
+ PlayerDead = 'Server.onDead',
22
+ PlayerInShape = 'Server.onInShape',
23
+ PlayerOutShape = 'Server.onOutShape',
24
+ PlayerMove = 'Server.PlayerMove',
25
+ PlayerCanChangeMap = 'Server.PlayerCanChangeMap',
26
+ ScalabilityPlayerConnected = 'Server.ScalabilityPlayerConnected',
27
+ ScalabilityChangeServer = 'Server.ScalabilityChangeServer'
28
+ }
29
+
30
+ export enum HookClient {
31
+ Start = 'Client.Start',
32
+ Step = 'Client.Step',
33
+ Connected = 'Client.Connected',
34
+ Disconnect = 'Client.Disconnect',
35
+ ConnectedError = 'Client.ConnectedError',
36
+
37
+ AddSpriteSheet = 'Client.AddSpriteSheet',
38
+ AddGui = 'Client.AddGui',
39
+ AddSound = 'Client.AddSound',
40
+ SendInput = 'Client.SendInput',
41
+
42
+ BeforeSceneLoading = 'Client.BeforeSceneLoading',
43
+ AfterSceneLoading = 'Client.AfterSceneLoading',
44
+ SceneMapLoading = 'Client.SceneMapLoading',
45
+ SceneAddSprite = 'Client.SceneAddSprite',
46
+ SceneOnChanges = 'Client.SceneOnChanges',
47
+ SceneDraw = 'Client.SceneDraw',
48
+ SceneRemoveSprite = 'Client.SceneRemoveSprite',
49
+
50
+ AddSprite = 'Client.AddSprite',
51
+ RemoveSprite = 'Client.RemoveSprite',
52
+ UpdateSprite = 'Client.UpdateSprite',
53
+ ChangesSprite = 'Client.ChangesSprite',
54
+ WindowResize = 'Client.WindowResize',
55
+ SpriteMove = 'Client.SpriteMove'
56
+ }
57
+
58
+ /**
59
+ * @deprecated
60
+ */
61
+ export class PluginSystem extends EventEmitter {
62
+ private loadPlugins(plugins: Plugin[], shared: any, type: string) {
63
+ if (!plugins) return
64
+ for (let plugin of plugins) {
65
+ if (!plugin) continue
66
+ let plug: any = []
67
+ if (!isArray(plugin)) {
68
+ plug = [plugin]
69
+ }
70
+ else {
71
+ plug = plugin
72
+ }
73
+ const [side, options] = plug
74
+ if (!side[type]) continue
75
+ side[type]({
76
+ RpgPlugin,
77
+ ...shared
78
+ }, options)
79
+ }
80
+ }
81
+
82
+ loadServerPlugins(plugins, shared) {
83
+ this.loadPlugins(plugins, shared, 'server')
84
+ }
85
+
86
+ loadClientPlugins(plugins, shared) {
87
+ this.loadPlugins(plugins, shared, 'client')
88
+ }
89
+ }
90
+
91
+ export const RpgPlugin = new PluginSystem()
@@ -0,0 +1,88 @@
1
+ import { Tick } from '@rpgjs/types';
2
+ import { BehaviorSubject, Observable } from 'rxjs';
3
+ import { EventEmitter } from './EventEmitter';
4
+ import Utils from './Utils';
5
+
6
+ export class Scheduler extends EventEmitter {
7
+ private maxFps?: number
8
+ private fps: number = 60
9
+ private deltaTime: number = 0
10
+ public frame: number = 0
11
+ private timestamp: number = 0
12
+ private requestedDelay: number = 0
13
+ private lastTimestamp: number = 0
14
+ private _tick: BehaviorSubject<Tick> = new BehaviorSubject({
15
+ timestamp: 0,
16
+ deltaTime: 0,
17
+ frame: 0,
18
+ deltaRatio: 0
19
+ })
20
+
21
+ get tick(): Observable<Tick> {
22
+ return this._tick.asObservable()
23
+ }
24
+
25
+ nextTick(timestamp: number) {
26
+ this.lastTimestamp = this.lastTimestamp || this.timestamp // first
27
+ this.deltaTime = Utils.preciseNow() - this.timestamp
28
+ this.timestamp = timestamp
29
+ this._tick.next({
30
+ timestamp: this.timestamp,
31
+ deltaTime: this.deltaTime,
32
+ frame: this.frame,
33
+ deltaRatio: ~~this.deltaTime / ~~Utils.fps2ms(this.fps)
34
+ })
35
+ this.lastTimestamp = this.timestamp
36
+ this.frame++
37
+ }
38
+
39
+ /**
40
+ * start the schedule
41
+ * @return {Scheduler} returns this scheduler instance
42
+ */
43
+ start(options: {
44
+ maxFps?: number
45
+ fps?: number,
46
+ delay?: number
47
+ }) {
48
+ if (options.maxFps) this.maxFps = options.maxFps
49
+ if (options.fps) this.fps = options.fps
50
+ if (options.delay) this.requestedDelay = options.delay
51
+ const requestAnimationFrame = (fn: (timestamp: number) => void) => {
52
+ if (Utils.isBrowser()) {
53
+ window.requestAnimationFrame(fn.bind(this))
54
+ }
55
+ else {
56
+ setTimeout(() => {
57
+ this.requestedDelay = 0
58
+ fn(Utils.preciseNow())
59
+ }, Utils.fps2ms(this.fps) + this.requestedDelay)
60
+ }
61
+ }
62
+
63
+ if (!this.maxFps) {
64
+ const loop = (timestamp: number) => {
65
+ requestAnimationFrame(loop)
66
+ this.nextTick(timestamp)
67
+ }
68
+ requestAnimationFrame(loop)
69
+ }
70
+ else {
71
+ const msInterval = Utils.fps2ms(this.maxFps)
72
+ let now = Utils.preciseNow()
73
+ let then = Utils.preciseNow()
74
+ const loop = (timestamp: number) => {
75
+ requestAnimationFrame(loop)
76
+ now = Utils.preciseNow()
77
+ const elapsed = now - then
78
+ if (elapsed > msInterval) {
79
+ then = now - (elapsed % msInterval)
80
+ this.nextTick(timestamp)
81
+ }
82
+ }
83
+ requestAnimationFrame(loop)
84
+ }
85
+
86
+ return this;
87
+ }
88
+ }
package/src/Shape.ts ADDED
@@ -0,0 +1,300 @@
1
+ import { RpgCommonPlayer } from './Player'
2
+ import { Hit, HitType } from './Hit'
3
+ import { TiledObjectClass } from '@rpgjs/tiled'
4
+ import { PlayerType } from '@rpgjs/types'
5
+ import { Vector2d } from './Vector2d'
6
+ import { AbstractObject } from './AbstractObject'
7
+
8
+ export enum ShapePositioning {
9
+ Default = 'default',
10
+ Center = 'center'
11
+ }
12
+
13
+ type ShapeObject = TiledObjectClass & {
14
+ onIn?(player: RpgCommonPlayer)
15
+ onOut?(player: RpgCommonPlayer)
16
+ fixEvent?: RpgCommonPlayer,
17
+ positioning?: ShapePositioning
18
+ }
19
+
20
+ export class RpgShape extends TiledObjectClass {
21
+ _hitbox: any
22
+ type: string = HitType.Box
23
+ class: string = ''
24
+ /**
25
+ * Get/Set name
26
+ * @title name
27
+ * @prop { string } name
28
+ * @memberof Shape
29
+ */
30
+ name: string = ''
31
+ fixEvent?: RpgCommonPlayer
32
+ private playersIn: {
33
+ [playerid: string]: boolean
34
+ } = {}
35
+ private onIn: (player: RpgCommonPlayer) => void
36
+ private onOut: (player: RpgCommonPlayer) => void
37
+ clientContainer: any = null
38
+ /**
39
+ * Get/Set positioning
40
+ * @title positioning
41
+ * @prop { ShapePositioning } positioning
42
+ * @default default
43
+ * @memberof Shape
44
+ */
45
+ positioning?: ShapePositioning = ShapePositioning.Default
46
+ components: any[] = []
47
+
48
+ constructor(obj: ShapeObject) {
49
+ super()
50
+ Reflect.deleteProperty(obj, 'id')
51
+ this.set(obj)
52
+ }
53
+
54
+ private setPos(type: string, val: number) {
55
+ if (!this.hitbox.pos) return
56
+ if (this.isShapePosition()) {
57
+ this.hitbox[type] = val
58
+ }
59
+ else {
60
+ this.hitbox.pos[type] = val
61
+ }
62
+ }
63
+
64
+ get hasCollision(): boolean {
65
+ return this.getProperty<boolean, boolean>('collision', false)
66
+ }
67
+
68
+ // alias
69
+ get id(): any {
70
+ return this.name
71
+ }
72
+
73
+ get hitbox() {
74
+ if (this.fixEvent) {
75
+ this._hitbox.pos.x = this.fixEvent.position.x
76
+ this._hitbox.pos.y = this.fixEvent.position.y
77
+ switch (this.positioning) {
78
+ case ShapePositioning.Center:
79
+ this._hitbox.pos.x -= this._hitbox.w / 2 - this.fixEvent.hitbox.w / 2
80
+ this._hitbox.pos.y -= this._hitbox.h / 2 - this.fixEvent.hitbox.h / 2
81
+ break
82
+ }
83
+ }
84
+ return this._hitbox
85
+ }
86
+
87
+ set hitbox(val) {
88
+ this._hitbox = val
89
+ }
90
+
91
+ /**
92
+ * Get/Set width
93
+ * @title width
94
+ * @prop { number } width
95
+ * @since 3.0.0-beta.5
96
+ * @memberof Shape
97
+ */
98
+ get width(): number {
99
+ return this.hitbox.w || 0
100
+ }
101
+
102
+ set width(val: number) {
103
+ this.setPos('w', val)
104
+ }
105
+
106
+ /**
107
+ * Get/Set height
108
+ * @title height
109
+ * @prop { number } height
110
+ * @since 3.0.0-beta.5
111
+ * @memberof Shape
112
+ */
113
+ get height(): number {
114
+ return this.hitbox.h || 0
115
+ }
116
+
117
+ set height(val: number) {
118
+ this.setPos('h', val)
119
+ }
120
+
121
+ /**
122
+ * Get/Set x
123
+ * @title x
124
+ * @prop { number } x
125
+ * @memberof Shape
126
+ */
127
+ get x(): number {
128
+ return this.hitbox.x || this.hitbox.pos.x
129
+ }
130
+
131
+ set x(val: number) {
132
+ this.setPos('x', val)
133
+ }
134
+
135
+ get z(): number | undefined {
136
+ return this.getProperty<number>('z')
137
+ }
138
+
139
+ /**
140
+ * Get/Set y
141
+ * @title y
142
+ * @prop { number } y
143
+ * @memberof Shape
144
+ */
145
+ get y(): number {
146
+ return this.hitbox.y || this.hitbox.pos.y
147
+ }
148
+
149
+ set y(val: number) {
150
+ this.setPos('y', val)
151
+ }
152
+
153
+ get position(): Vector2d {
154
+ return new Vector2d(this.x, this.y, this.z)
155
+ }
156
+
157
+ /**
158
+ * Get/Set properties
159
+
160
+ * @title Properties
161
+ * @prop { object } Properties
162
+ * @memberof Shape
163
+ */
164
+
165
+ isEvent(): boolean {
166
+ return this.type == PlayerType.Event
167
+ }
168
+
169
+ set(obj: ShapeObject) {
170
+ const hit = Hit.getHitbox(obj)
171
+ Object.assign(this, hit)
172
+ const objClone = { ...obj };
173
+ // Delete dimension and position because already managed and given by the hitbox above
174
+ ['width', 'height', 'x', 'y'].forEach((prop) => Reflect.deleteProperty(objClone, prop))
175
+ Object.assign(this, objClone)
176
+ const findPoint = (prop: string, isMin: boolean) => {
177
+ return this.hitbox.points.sort((a, b) => isMin ? a[prop] - b[prop] : b[prop] - a[prop])[0][prop]
178
+ }
179
+ if (this.type == HitType.Polygon) {
180
+ this.hitbox.minX = findPoint('x', true)
181
+ this.hitbox.maxX = findPoint('x', false)
182
+ this.hitbox.minY = findPoint('y', true)
183
+ this.hitbox.maxY = findPoint('y', false)
184
+ }
185
+ this.positioning = obj.positioning
186
+ this.fixEvent = obj.fixEvent
187
+ this.setComponent()
188
+ }
189
+
190
+ setComponent() {
191
+ const color = this.getProperty<string>('color')
192
+ const image = this.getProperty<string>('image')
193
+ if (color) {
194
+ this.components = [{
195
+ id: 'shape', value: {
196
+ fill: color
197
+ }
198
+ }]
199
+ return
200
+ }
201
+ if (image) {
202
+ this.components = [{ id: 'image', value: image }]
203
+ return
204
+ }
205
+ if (this.text) {
206
+ this.components = [{ id: 'text', value: this.text.text }]
207
+ return
208
+ }
209
+ if (this.gid) {
210
+ this.components = [{ id: 'tile', value: this.gid }]
211
+ return
212
+ }
213
+ }
214
+
215
+ getType() {
216
+ return this.class || this.type
217
+ }
218
+
219
+ async in(player: AbstractObject): Promise<boolean> {
220
+ if (!this.playerIsIn(player)) {
221
+ this.playersIn[player.id] = true
222
+ player.inShapes[this.name] = this
223
+ await player.execMethod('onInShape', [this])
224
+ await player.execMethod('onIn', [player], this)
225
+ return true
226
+ }
227
+ return false
228
+ }
229
+
230
+ async out(player: AbstractObject): Promise<boolean> {
231
+ if (this.playerIsIn(player)) {
232
+ delete this.playersIn[player.id]
233
+ delete player.inShapes[this.name]
234
+ await player.execMethod('onOutShape', [this])
235
+ await player.execMethod('onOut', [player], this)
236
+ return true
237
+ }
238
+ return false
239
+ }
240
+
241
+ /**
242
+ * Whether the player is in this shape
243
+ *
244
+ * @title Player is in this shape ?
245
+ * @method shape.playerIsIn(player)
246
+ * @returns {boolean}
247
+ * @memberof Shape
248
+ */
249
+ playerIsIn(player: AbstractObject): boolean {
250
+ return !!this.playersIn[player.id]
251
+ }
252
+
253
+ isShapePosition(): boolean {
254
+ return this.type !== HitType.Box && this.type !== HitType.Circle && this.type !== HitType.Polygon
255
+ }
256
+
257
+ /**
258
+ * Recover the player with the shape. You must have used the `attachShape()` method on the player
259
+ *
260
+ * @title Get Player Owner
261
+ * @method shape.getPlayerOwner()
262
+ * @returns {RpgPlayer | undefined}
263
+ * @memberof Shape
264
+ */
265
+ getPlayerOwner(): RpgCommonPlayer | undefined {
266
+ return this.fixEvent
267
+ }
268
+
269
+ /**
270
+ * We get the rectangle of a shape (box, circle and polygon). We use in the grid system to recover a shape.
271
+ * Generally we add a margin (size of a tile) to detect if the player enters or leaves a shape
272
+ * @param margin
273
+ * @returns { minX: number, minY: number, maxX: number, maxY: number }
274
+ */
275
+ getSizeBox(margin: number = 0): { minX: number, minY: number, maxX: number, maxY: number } {
276
+ if (this.type == HitType.Circle) {
277
+ const radius = this.hitbox.r
278
+ return {
279
+ minX: this.x - radius - margin,
280
+ maxX: this.x + radius + margin,
281
+ minY: this.y - radius - margin,
282
+ maxY: this.y + radius + margin
283
+ }
284
+ }
285
+ if (this.type == HitType.Polygon) {
286
+ return {
287
+ minX: this.x + this.hitbox.minX - margin,
288
+ maxX: this.x + this.hitbox.maxX + margin,
289
+ minY: this.y + this.hitbox.minY - margin,
290
+ maxY: this.y + this.hitbox.maxY + margin
291
+ }
292
+ }
293
+ return {
294
+ minX: this.x - margin,
295
+ maxX: this.x + this.width + margin,
296
+ minY: this.y - margin,
297
+ maxY: this.y + this.height + margin
298
+ }
299
+ }
300
+ }