@makefully/platypus 4.1.4 → 4.1.6
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/CHANGELOG.md +20 -0
- package/README.md +4 -2
- package/lib/platypus.js +1 -1
- package/package.json +7 -2
- package/src/AABB.js +685 -0
- package/src/ActionState.js +121 -0
- package/src/AssetManager.js +206 -0
- package/src/CollisionData.js +96 -0
- package/src/CollisionDataContainer.js +127 -0
- package/src/CollisionShape.js +315 -0
- package/src/Component.js +231 -0
- package/src/Data.js +64 -0
- package/src/DataMap.js +204 -0
- package/src/Entity.js +404 -0
- package/src/EntityLinker.js +113 -0
- package/src/EventHandler.js +115 -0
- package/src/EventHandlerList.js +251 -0
- package/src/Game.js +840 -0
- package/src/Gamepad.js +175 -0
- package/src/ID3CaptionPlayer.js +61 -0
- package/src/Messenger.js +365 -0
- package/src/PIXIAnimation.js +622 -0
- package/src/RandomSet.js +140 -0
- package/src/SFXPlayer.js +120 -0
- package/src/StateMap.js +252 -0
- package/src/Storage.js +152 -0
- package/src/TickerClient.js +48 -0
- package/src/TickerServer.js +23 -0
- package/src/TimeEvent.js +50 -0
- package/src/TimeEventList.js +100 -0
- package/src/VOPlayer.js +684 -0
- package/src/Vector.js +702 -0
- package/src/components/AIChaser.js +161 -0
- package/src/components/AIPacer.js +107 -0
- package/src/components/AudioMusic.js +151 -0
- package/src/components/AudioSFX.js +673 -0
- package/src/components/AudioVO.js +301 -0
- package/src/components/CollisionBasic.js +826 -0
- package/src/components/CollisionFilter.js +74 -0
- package/src/components/CollisionGroup.js +448 -0
- package/src/components/CollisionTiles.js +608 -0
- package/src/components/ComponentSwitcher.js +173 -0
- package/src/components/ControllerInput.js +65 -0
- package/src/components/Counter.js +165 -0
- package/src/components/EntityCamera.js +215 -0
- package/src/components/EntityContainer.js +549 -0
- package/src/components/EntityController.js +541 -0
- package/src/components/HandlerCamera.js +1052 -0
- package/src/components/HandlerCollision.js +1318 -0
- package/src/components/HandlerController.js +291 -0
- package/src/components/HandlerLogic.js +394 -0
- package/src/components/HandlerRender.js +217 -0
- package/src/components/Interactive.js +502 -0
- package/src/components/LevelBuilder.js +524 -0
- package/src/components/LogicAngularMovement.js +154 -0
- package/src/components/LogicAttachment.js +265 -0
- package/src/components/LogicButton.js +466 -0
- package/src/components/LogicCarrier.js +39 -0
- package/src/components/LogicDestroyMe.js +58 -0
- package/src/components/LogicDirectionalMovement.js +325 -0
- package/src/components/LogicDragDrop.js +371 -0
- package/src/components/LogicImpactLaunch.js +144 -0
- package/src/components/LogicPacingPlatform.js +64 -0
- package/src/components/LogicPortable.js +112 -0
- package/src/components/LogicPortal.js +115 -0
- package/src/components/LogicPushable.js +98 -0
- package/src/components/LogicRebounder.js +136 -0
- package/src/components/LogicRegionSpawner.js +139 -0
- package/src/components/LogicRotationalMovement.js +205 -0
- package/src/components/LogicSpawner.js +159 -0
- package/src/components/LogicStateMachine.js +382 -0
- package/src/components/LogicSwitch.js +77 -0
- package/src/components/LogicTeleportee.js +68 -0
- package/src/components/LogicTeleporter.js +93 -0
- package/src/components/LogicTimer.js +178 -0
- package/src/components/LogicWindUpRacer.js +179 -0
- package/src/components/Motion.js +371 -0
- package/src/components/Mover.js +566 -0
- package/src/components/Node.js +289 -0
- package/src/components/NodeMap.js +295 -0
- package/src/components/NodeResident.js +636 -0
- package/src/components/Orientation.js +697 -0
- package/src/components/RandomEvents.js +73 -0
- package/src/components/RelativePosition.js +204 -0
- package/src/components/RelayFamily.js +106 -0
- package/src/components/RelayGame.js +53 -0
- package/src/components/RelayLinker.js +94 -0
- package/src/components/RelayParent.js +57 -0
- package/src/components/RelaySelf.js +55 -0
- package/src/components/Render.js +178 -0
- package/src/components/RenderAnimator.js +275 -0
- package/src/components/RenderContainer.js +646 -0
- package/src/components/RenderDebug.js +319 -0
- package/src/components/RenderDestroyMe.js +59 -0
- package/src/components/RenderLottie.js +149 -0
- package/src/components/RenderProgress.js +120 -0
- package/src/components/RenderSpine.js +833 -0
- package/src/components/RenderSprite.js +527 -0
- package/src/components/RenderText.js +147 -0
- package/src/components/RenderTiles.js +1391 -0
- package/src/components/SceneChanger.js +128 -0
- package/src/components/TiledLoader.js +1451 -0
- package/src/components/Timeline.js +314 -0
- package/src/components/Tutorial.js +267 -0
- package/src/components/Tween.js +296 -0
- package/src/components/VoiceOver.js +373 -0
- package/src/components/XHR.js +129 -0
- package/src/components/index.js +79 -0
- package/src/factory.js +305 -0
- package/src/index.js +159 -0
- package/src/mixins/PIXI.Graphics.js +41 -0
- package/src/platypus.css +68 -0
- package/src/sayHello.js +50 -0
- package/src/shapes/Capsule.js +74 -0
- package/src/shapes/Circle.js +43 -0
- package/src/shapes/Ellipse.js +117 -0
- package/src/shapes/Point.js +191 -0
- package/src/shapes/Polygon.js +112 -0
- package/src/shapes/Polyline.js +97 -0
- package/src/shapes/Rectangle.js +78 -0
- package/src/shapes/RoundedRectangle.js +33 -0
- package/src/shapes/Segment.js +346 -0
- package/src/shapes/adjustedXY.js +19 -0
- package/src/shapes/castFromBox2D.js +92 -0
- package/src/shapes/castFromObject.js +53 -0
- package/src/shapes/castFromPixiGraphics.js +6 -0
- package/src/shapes/castFromPixiShape.js +89 -0
- package/src/shapes/castToBox2D.js +190 -0
- package/src/shapes/castToPixiGraphics.js +100 -0
- package/src/shapes/castToPixiShape.js +61 -0
- package/src/shapes/checkPointsMap.js +313 -0
- package/src/shapes/index.js +35 -0
- package/src/utils/array.js +73 -0
- package/src/utils/string.js +39 -0
package/src/Gamepad.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import Data from './Data.js';
|
|
2
|
+
import Vector from './Vector.js';
|
|
3
|
+
import {arrayCache} from './utils/array.js';
|
|
4
|
+
import recycle from 'recycle';
|
|
5
|
+
|
|
6
|
+
const
|
|
7
|
+
/**
|
|
8
|
+
* This class defines an axis-aligned bounding box (AABB) which is used during the collision process to determine if two objects are colliding. This is used in a few places including [CollisionBasic](platypus.components.CollisionBasic.html) and [[Collision-Shape]].
|
|
9
|
+
*
|
|
10
|
+
* @memberof platypus
|
|
11
|
+
* @class Gamepad
|
|
12
|
+
* @param gamepad {number} The browser's gamepad object.
|
|
13
|
+
* @param id {number} Id of gamepad.
|
|
14
|
+
* @param deadzone {number} distance from axis `0` position to ignore.
|
|
15
|
+
* @param height {number} The height of the AABB.
|
|
16
|
+
* @return {platypus.Gamepad} Returns the new aabb object.
|
|
17
|
+
*/
|
|
18
|
+
Gamepad = function (gamepad, onDown, onUp, onChange, id = '', deadzone = 0.1) {
|
|
19
|
+
this.source = gamepad;
|
|
20
|
+
this.deadzone = deadzone;
|
|
21
|
+
this.axes = this.axes || arrayCache.setUp();
|
|
22
|
+
for (let i = 0; i < (gamepad.axes.length >> 1); i++) {
|
|
23
|
+
this.axes.push(clampVector(Vector.setUp(gamepad.axes[i * 2], gamepad.axes[i * 2 + 1]), deadzone));
|
|
24
|
+
}
|
|
25
|
+
this.buttons = this.buttons || arrayCache.setUp();
|
|
26
|
+
for (let i = 0; i < gamepad.buttons.length; i++) {
|
|
27
|
+
this.buttons.push(gamepad.buttons[i].value);
|
|
28
|
+
}
|
|
29
|
+
this.id = id || `${gamepad.id} - ${gamepad.index}`; // Adding index to make it unique.
|
|
30
|
+
|
|
31
|
+
this.onDown = onDown;
|
|
32
|
+
this.onUp = onUp;
|
|
33
|
+
this.onChange = onChange;
|
|
34
|
+
},
|
|
35
|
+
playEffectOptions = {
|
|
36
|
+
duration: 500,
|
|
37
|
+
startDelay: 0,
|
|
38
|
+
strongMagnitude: 1.0,
|
|
39
|
+
weakMagnitude: 1.0
|
|
40
|
+
},
|
|
41
|
+
controllers = {
|
|
42
|
+
a0: 'LeftStick',
|
|
43
|
+
a1: 'RightStick',
|
|
44
|
+
b0: 'AButton',
|
|
45
|
+
b1: 'BButton',
|
|
46
|
+
b2: 'XButton',
|
|
47
|
+
b3: 'YButton',
|
|
48
|
+
b4: 'LeftBumper',
|
|
49
|
+
b5: 'RightBumper',
|
|
50
|
+
b6: 'LeftTrigger',
|
|
51
|
+
b7: 'RightTrigger',
|
|
52
|
+
b8: 'BackButton',
|
|
53
|
+
b9: 'StartButton',
|
|
54
|
+
b10: 'LeftStickButton',
|
|
55
|
+
b11: 'RightStickButton',
|
|
56
|
+
b12: 'UpDPad',
|
|
57
|
+
b13: 'DownDPad',
|
|
58
|
+
b14: 'LeftDPad',
|
|
59
|
+
b15: 'RightDPad'
|
|
60
|
+
},
|
|
61
|
+
clampVector = function (v, deadzone) {
|
|
62
|
+
const m = v.magnitude();
|
|
63
|
+
|
|
64
|
+
if (m > 1) {
|
|
65
|
+
v.x *= 1 / m;
|
|
66
|
+
v.y *= 1 / m;
|
|
67
|
+
} else if (m < deadzone) {
|
|
68
|
+
v.x = 0;
|
|
69
|
+
v.y = 0;
|
|
70
|
+
} else {
|
|
71
|
+
const span = 1 - deadzone;
|
|
72
|
+
v.x = (v.x - deadzone) / span;
|
|
73
|
+
v.y = (v.y - deadzone) / span;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return v;
|
|
77
|
+
},
|
|
78
|
+
proto = Gamepad.prototype;
|
|
79
|
+
|
|
80
|
+
proto.dualRumble = function (duration = 500, delay = 0, strong = 1.0, weak = 1.0) {
|
|
81
|
+
playEffectOptions.duration = duration;
|
|
82
|
+
playEffectOptions.startDelay = delay;
|
|
83
|
+
playEffectOptions.strongMagnitude = strong;
|
|
84
|
+
playEffectOptions.weakMagnitude = weak;
|
|
85
|
+
this.source.vibrationActuator.playEffect('dual-rumble', playEffectOptions);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
proto.update = function (gamepad) {
|
|
89
|
+
const
|
|
90
|
+
axes = this.axes,
|
|
91
|
+
buttons = this.buttons,
|
|
92
|
+
onDown = this.onDown,
|
|
93
|
+
onUp = this.onUp,
|
|
94
|
+
onChange = this.onChange;
|
|
95
|
+
|
|
96
|
+
for (let i = 0; i < axes.length; i++) {
|
|
97
|
+
const
|
|
98
|
+
oldVector = axes[i],
|
|
99
|
+
newVector = clampVector(Vector.setUp(gamepad.axes[i * 2], gamepad.axes[i * 2 + 1]), this.deadzone);
|
|
100
|
+
|
|
101
|
+
if (!newVector.equals(oldVector, 2)) {
|
|
102
|
+
const event = Data.setUp(
|
|
103
|
+
'code', controllers[`a${i}`],
|
|
104
|
+
'direction', oldVector,
|
|
105
|
+
'gamepad', this,
|
|
106
|
+
'id', this.id
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
oldVector.set(newVector);
|
|
110
|
+
onChange(event);
|
|
111
|
+
event.recycle();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
newVector.recycle();
|
|
115
|
+
}
|
|
116
|
+
for (let i = 0; i < gamepad.buttons.length; i++) {
|
|
117
|
+
const
|
|
118
|
+
newButton = gamepad.buttons[i],
|
|
119
|
+
newValue = newButton.value,
|
|
120
|
+
oldButton = buttons[i];
|
|
121
|
+
|
|
122
|
+
if (newValue !== oldButton) {
|
|
123
|
+
const event = Data.setUp(
|
|
124
|
+
'code', controllers[`b${i}`],
|
|
125
|
+
'button', newButton,
|
|
126
|
+
'gamepad', this,
|
|
127
|
+
'id', this.id
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
buttons[i] = newValue;
|
|
131
|
+
|
|
132
|
+
if (oldButton === 0) {
|
|
133
|
+
onDown(event);
|
|
134
|
+
onChange(event);
|
|
135
|
+
} else if (newValue === 0) {
|
|
136
|
+
onChange(event);
|
|
137
|
+
onUp(event);
|
|
138
|
+
} else {
|
|
139
|
+
onChange(event);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
event.recycle();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Returns an Gamepad from cache or creates a new one if none are available.
|
|
149
|
+
*
|
|
150
|
+
* @method platypus.Gamepad.setUp
|
|
151
|
+
* @return {platypus.Gamepad} The instantiated Gamepad.
|
|
152
|
+
*/
|
|
153
|
+
/**
|
|
154
|
+
* Returns a Gamepad back to the cache.
|
|
155
|
+
*
|
|
156
|
+
* @method platypus.Gamepad.recycle
|
|
157
|
+
* @param {platypus.Gamepad} gamepad The Gamepad to be recycled.
|
|
158
|
+
*/
|
|
159
|
+
/**
|
|
160
|
+
* Relinquishes properties of the Gamepad and recycles it.
|
|
161
|
+
*
|
|
162
|
+
* @method platypus.Gamepad#recycle
|
|
163
|
+
*/
|
|
164
|
+
recycle.add(Gamepad, 'Gamepad', Gamepad, function () {
|
|
165
|
+
for (let i = 0; i < this.axes.length; i++) {
|
|
166
|
+
this.axes[i].recycle();
|
|
167
|
+
}
|
|
168
|
+
this.axes.length = 0;
|
|
169
|
+
this.buttons.length = 0;
|
|
170
|
+
this.onDown = null;
|
|
171
|
+
this.onUp = null;
|
|
172
|
+
this.onChange = null;
|
|
173
|
+
}, true);
|
|
174
|
+
|
|
175
|
+
export default Gamepad;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import {CaptionFactory, CaptionPlayer, HtmlRenderer} from 'springroll';
|
|
2
|
+
|
|
3
|
+
const
|
|
4
|
+
nullCaption = [{
|
|
5
|
+
content: "Prevent empty captions error.",
|
|
6
|
+
start: 0,
|
|
7
|
+
end: 1
|
|
8
|
+
}],
|
|
9
|
+
findAndFormatCaptionsFromTags = ({tags}, length) => {
|
|
10
|
+
const
|
|
11
|
+
{SYLT} = tags;
|
|
12
|
+
|
|
13
|
+
if (SYLT) {
|
|
14
|
+
const
|
|
15
|
+
list = Array.isArray(SYLT) ? SYLT : [SYLT],
|
|
16
|
+
captionsSYLT = list.filter(({data}) => data.descriptor === 'captions')[0] ?? list.filter(({data}) => data.contentType === 'transcription')[0] ?? list.filter(({data}) => data.contentType === 'lyrics')[0] ?? null;
|
|
17
|
+
|
|
18
|
+
if (captionsSYLT) {
|
|
19
|
+
return CaptionFactory.createCaption(captionsSYLT.data.synchronisedText.map(({text: content, timeStamp: start}, index, arr) => {
|
|
20
|
+
const
|
|
21
|
+
next = arr[index + 1];
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
content,
|
|
25
|
+
start: Math.max(start, 0.001), // Prevents CaptionPlayer from playing caption before the audio is loaded/playing.
|
|
26
|
+
end: next ? next.timeStamp : length
|
|
27
|
+
};
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return null;
|
|
33
|
+
},
|
|
34
|
+
ID3CaptionPlayer = class extends CaptionPlayer {
|
|
35
|
+
constructor (captions = {nullCaption}, captionsElement, tagReader = null) {
|
|
36
|
+
super(captions, new HtmlRenderer(captionsElement));
|
|
37
|
+
|
|
38
|
+
if (tagReader) {
|
|
39
|
+
this.getCaption = (audio) => new Promise((resolve, reject) => {
|
|
40
|
+
tagReader.read(audio.media?.file ?? audio.url, {
|
|
41
|
+
onSuccess: (tags) => resolve(findAndFormatCaptionsFromTags(tags, (audio.duration * 1000) >> 0)),
|
|
42
|
+
onError: reject
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async start (audio, audioId, ...args) {
|
|
49
|
+
if (this.getCaption && typeof this.captions[audioId] === 'undefined') {
|
|
50
|
+
try {
|
|
51
|
+
this.captions[audioId] = await this.getCaption(audio);
|
|
52
|
+
} catch (e) {
|
|
53
|
+
this.captions[audioId] = null;
|
|
54
|
+
platypus.debug.warn(e.type, e.info);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
super.start(this.captions[audioId] ? audioId : audio.url, ...args);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default ID3CaptionPlayer;
|
package/src/Messenger.js
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/* global platypus, window */
|
|
2
|
+
import EventHandlerList from './EventHandlerList.js';
|
|
3
|
+
import {arrayCache, greenSlice} from './utils/array.js';
|
|
4
|
+
|
|
5
|
+
const
|
|
6
|
+
getPerfTools = () => typeof performance !== 'undefined' && performance.mark && performance.measure ? performance : null,
|
|
7
|
+
runBoth = function (f1, f2) {
|
|
8
|
+
return function () {
|
|
9
|
+
f1.apply(this, arguments);
|
|
10
|
+
f2.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Messenger provides prioritized event-based communication between
|
|
16
|
+
* components, entities, and systems.
|
|
17
|
+
*
|
|
18
|
+
* Features include:
|
|
19
|
+
* - prioritized listeners
|
|
20
|
+
* - one-time listeners
|
|
21
|
+
* - deterministic execution ordering
|
|
22
|
+
* - safe listener mutation during dispatch
|
|
23
|
+
* - pooled listener structures
|
|
24
|
+
* - array/object event dispatch formats
|
|
25
|
+
* - optional debug instrumentation
|
|
26
|
+
*
|
|
27
|
+
* Messenger is commonly mixed into entities and components to
|
|
28
|
+
* provide lightweight pub/sub behavior without repeated allocations.
|
|
29
|
+
*
|
|
30
|
+
* @memberof platypus
|
|
31
|
+
* @class Messenger
|
|
32
|
+
*/
|
|
33
|
+
class Messenger {
|
|
34
|
+
/**
|
|
35
|
+
* Creates a Messenger instance.
|
|
36
|
+
*
|
|
37
|
+
* @param {Object} [options]
|
|
38
|
+
* Configuration options.
|
|
39
|
+
*
|
|
40
|
+
* @param {Boolean} [options.debug=false]
|
|
41
|
+
* Enables nested-event debugging and performance instrumentation.
|
|
42
|
+
*/
|
|
43
|
+
constructor ({debug} = {}) {
|
|
44
|
+
this._listeners = {};
|
|
45
|
+
this._destroyed = false;
|
|
46
|
+
this.loopCheck = arrayCache.setUp();
|
|
47
|
+
|
|
48
|
+
if (debug) {
|
|
49
|
+
const
|
|
50
|
+
triggerEvent = this.triggerEvent;
|
|
51
|
+
|
|
52
|
+
this.triggerEvent = function (event, value) {
|
|
53
|
+
const
|
|
54
|
+
debugLimit = 5,
|
|
55
|
+
debugLogging = value && value.debug;
|
|
56
|
+
let debugCount = 0;
|
|
57
|
+
|
|
58
|
+
// Debug logging.
|
|
59
|
+
if (debugLogging || this.debug) {
|
|
60
|
+
const perfTools = getPerfTools();
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < this.loopCheck.length; i++) {
|
|
63
|
+
if (this.loopCheck[i] === event) {
|
|
64
|
+
debugCount += 1;
|
|
65
|
+
if (debugCount > debugLimit) {
|
|
66
|
+
throw "Endless loop detected for '" + event + "'.";
|
|
67
|
+
} else {
|
|
68
|
+
platypus.debug.warn("Event '" + event + "' is nested inside another '" + event + "' event.");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this.loopCheck.push(event);
|
|
74
|
+
|
|
75
|
+
if (perfTools) {
|
|
76
|
+
perfTools.mark("a");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const
|
|
80
|
+
count = triggerEvent.apply(this, arguments);
|
|
81
|
+
|
|
82
|
+
if (perfTools) {
|
|
83
|
+
perfTools.mark("b");
|
|
84
|
+
perfTools.measure(this.type + ":" + event, 'a', 'b');
|
|
85
|
+
}
|
|
86
|
+
this.loopCheck.length = this.loopCheck.length - 1;
|
|
87
|
+
if (debugLogging) {
|
|
88
|
+
if (count) {
|
|
89
|
+
platypus.debug.log('Entity "' + this.type + '": Event "' + event + '" has ' + count + ' subscriber' + ((count > 1) ? 's' : '') + '.', value);
|
|
90
|
+
} else {
|
|
91
|
+
platypus.debug.warn('Entity "' + this.type + '": Event "' + event + '" has no subscribers.', value);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return count;
|
|
95
|
+
} else {
|
|
96
|
+
return triggerEvent.apply(this, arguments);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Registers an event listener.
|
|
104
|
+
*
|
|
105
|
+
* Listeners are executed in ascending priority order.
|
|
106
|
+
* Lower priority values execute first.
|
|
107
|
+
*
|
|
108
|
+
* When priorities match, listeners execute in
|
|
109
|
+
* registration order.
|
|
110
|
+
*
|
|
111
|
+
* If no context is supplied, the Messenger instance
|
|
112
|
+
* becomes the callback context.
|
|
113
|
+
*
|
|
114
|
+
* @method on
|
|
115
|
+
*
|
|
116
|
+
* @param {String} name
|
|
117
|
+
* Event name.
|
|
118
|
+
*
|
|
119
|
+
* @param {Function} callback
|
|
120
|
+
* Function invoked when the event fires.
|
|
121
|
+
*
|
|
122
|
+
* @param {Object} [context=this]
|
|
123
|
+
* Callback execution context.
|
|
124
|
+
*
|
|
125
|
+
* @param {Boolean} [once=false]
|
|
126
|
+
* Whether the listener should automatically remove
|
|
127
|
+
* itself after its first execution.
|
|
128
|
+
*
|
|
129
|
+
* @param {Number} [priority=MAX_SAFE_INTEGER]
|
|
130
|
+
* Listener execution priority.
|
|
131
|
+
*
|
|
132
|
+
* Lower numbers execute first.
|
|
133
|
+
*/
|
|
134
|
+
on (name, callback, context = null, once = false, priority = -1) {
|
|
135
|
+
if (!this._destroyed) {
|
|
136
|
+
const
|
|
137
|
+
listenerList = this._listeners[name] = this._listeners[name] ?? EventHandlerList.setUp();
|
|
138
|
+
|
|
139
|
+
return listenerList.add(callback, context ?? this, once, priority === -1 ? Number.MAX_SAFE_INTEGER : priority);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Removes listeners.
|
|
147
|
+
*
|
|
148
|
+
* Calling without arguments removes all listeners.
|
|
149
|
+
*
|
|
150
|
+
* Calling with only an event name removes all listeners
|
|
151
|
+
* for that event.
|
|
152
|
+
*
|
|
153
|
+
* Calling with both name and callback removes matching
|
|
154
|
+
* listeners for that callback.
|
|
155
|
+
*
|
|
156
|
+
* @method off
|
|
157
|
+
*
|
|
158
|
+
* @param {String} [name]
|
|
159
|
+
* Event name.
|
|
160
|
+
*
|
|
161
|
+
* @param {Function} [callback]
|
|
162
|
+
* Listener callback.
|
|
163
|
+
*/
|
|
164
|
+
off (name, callback, context) {
|
|
165
|
+
if (!this._destroyed) {
|
|
166
|
+
// remove all
|
|
167
|
+
if (typeof name === 'undefined') {
|
|
168
|
+
this.getMessageIds().forEach((id) => this._listeners[id].recycle());
|
|
169
|
+
this._listeners = {};
|
|
170
|
+
} else {
|
|
171
|
+
const
|
|
172
|
+
listenerList = this._listeners[name];
|
|
173
|
+
|
|
174
|
+
if (listenerList) {
|
|
175
|
+
// remove all listeners for that event
|
|
176
|
+
if (typeof callback === 'undefined') {
|
|
177
|
+
listenerList.recycle();
|
|
178
|
+
delete this._listeners[name];
|
|
179
|
+
} else {
|
|
180
|
+
//remove single listener
|
|
181
|
+
listenerList.remove(callback, context);
|
|
182
|
+
if (!listenerList.handlers.length) {
|
|
183
|
+
listenerList.recycle();
|
|
184
|
+
delete this._listeners[name];
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Returns a string describing the Messenger as "[Messenger object]".
|
|
194
|
+
*
|
|
195
|
+
* @return String
|
|
196
|
+
*/
|
|
197
|
+
toString () {
|
|
198
|
+
return "[Messenger Object]";
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Dispatches one or more events.
|
|
203
|
+
*
|
|
204
|
+
* Supported formats:
|
|
205
|
+
*
|
|
206
|
+
* String:
|
|
207
|
+
* trigger('jump', value)
|
|
208
|
+
*
|
|
209
|
+
* Array:
|
|
210
|
+
* trigger(['jump', 'land'], value)
|
|
211
|
+
*
|
|
212
|
+
* Object:
|
|
213
|
+
* trigger({
|
|
214
|
+
* event: 'jump',
|
|
215
|
+
* message: value,
|
|
216
|
+
* debug: true
|
|
217
|
+
* })
|
|
218
|
+
*
|
|
219
|
+
* @method trigger
|
|
220
|
+
*
|
|
221
|
+
* @param {String|Array|Object} events
|
|
222
|
+
* Event descriptor.
|
|
223
|
+
*
|
|
224
|
+
* @param {*} [message]
|
|
225
|
+
* Event payload.
|
|
226
|
+
*
|
|
227
|
+
* @param {Boolean} [debug]
|
|
228
|
+
* Enables debug logging for this dispatch.
|
|
229
|
+
*
|
|
230
|
+
* @return {Number}
|
|
231
|
+
* Total number of listeners triggered.
|
|
232
|
+
*/
|
|
233
|
+
trigger (events, message, debug) {
|
|
234
|
+
if (typeof events === 'string') {
|
|
235
|
+
return this.triggerEvent.apply(this, arguments);
|
|
236
|
+
} else if (Array.isArray(events)) {
|
|
237
|
+
const
|
|
238
|
+
args = greenSlice(arguments);
|
|
239
|
+
let count = 0;
|
|
240
|
+
|
|
241
|
+
for (let i = 0; i < events.length; i++) {
|
|
242
|
+
args[0] = events[i];
|
|
243
|
+
count += this.trigger.apply(this, args);
|
|
244
|
+
}
|
|
245
|
+
arrayCache.recycle(args);
|
|
246
|
+
|
|
247
|
+
return count;
|
|
248
|
+
} else if (events.event) {
|
|
249
|
+
if (typeof events.debug !== 'undefined') {
|
|
250
|
+
return this.triggerEvent(
|
|
251
|
+
events.event,
|
|
252
|
+
events.message ?? message,
|
|
253
|
+
events.debug
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return this.triggerEvent(
|
|
258
|
+
events.event,
|
|
259
|
+
events.message ?? message
|
|
260
|
+
);
|
|
261
|
+
} else {
|
|
262
|
+
platypus.debug.warn('Event incorrectly formatted: must be string, array, or object containing an "event" property.', events);
|
|
263
|
+
return 0;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Dispatches a single event directly.
|
|
269
|
+
*
|
|
270
|
+
* This bypasses trigger-format normalization and is
|
|
271
|
+
* the fastest dispatch path.
|
|
272
|
+
*
|
|
273
|
+
* @method triggerEvent
|
|
274
|
+
*
|
|
275
|
+
* @param {String} type
|
|
276
|
+
* Event name.
|
|
277
|
+
*
|
|
278
|
+
* @param {...*} args
|
|
279
|
+
* Arguments forwarded to listeners.
|
|
280
|
+
*
|
|
281
|
+
* @return {Number}
|
|
282
|
+
* Number of listeners triggered.
|
|
283
|
+
*/
|
|
284
|
+
triggerEvent (type, ...args) {
|
|
285
|
+
const
|
|
286
|
+
{_listeners} = this;
|
|
287
|
+
|
|
288
|
+
if (!this._destroyed && _listeners.hasOwnProperty(type) && (_listeners[type])) {
|
|
289
|
+
return _listeners[type].trigger(args);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return 0;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* This method returns all the messages that this entity is concerned about.
|
|
297
|
+
*
|
|
298
|
+
* @return {Array} An array of strings listing all the messages for which this Messenger has handlers.
|
|
299
|
+
*/
|
|
300
|
+
getMessageIds () {
|
|
301
|
+
return Object.keys(this._listeners);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* This method relinguishes Messenger properties
|
|
306
|
+
*
|
|
307
|
+
*/
|
|
308
|
+
destroy () {
|
|
309
|
+
arrayCache.recycle(this.loopCheck);
|
|
310
|
+
this.loopCheck = null;
|
|
311
|
+
this._destroyed = true;
|
|
312
|
+
this.getMessageIds().forEach((id) => this._listeners[id].recycle());
|
|
313
|
+
this._listeners = null;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* This read-only property shows whether this Messenger is destroyed.
|
|
318
|
+
*
|
|
319
|
+
* @property destroyed
|
|
320
|
+
* @type Boolean
|
|
321
|
+
* @default false
|
|
322
|
+
*/
|
|
323
|
+
get destroyed () {
|
|
324
|
+
return this._destroyed;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Adds Messenger functionality to a Class.
|
|
329
|
+
*
|
|
330
|
+
* @param {Class|Function} ClassObject The class to add Messenger behavior to.
|
|
331
|
+
*/
|
|
332
|
+
static mixin (ClassObject) {
|
|
333
|
+
const
|
|
334
|
+
fromProto = Messenger.prototype,
|
|
335
|
+
toProto = ClassObject.prototype,
|
|
336
|
+
methods = Object.getOwnPropertyNames(fromProto);
|
|
337
|
+
let i = methods.length;
|
|
338
|
+
|
|
339
|
+
while (i--) {
|
|
340
|
+
const
|
|
341
|
+
key = methods[i];
|
|
342
|
+
|
|
343
|
+
if (key !== 'constructor') {
|
|
344
|
+
if (toProto[key]) {
|
|
345
|
+
toProto[key] = runBoth(toProto[key], fromProto[key]);
|
|
346
|
+
} else {
|
|
347
|
+
toProto[key] = fromProto[key];
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Call this method in an Object's instantiation if `Messenger.mixin` has been called on its Class.
|
|
355
|
+
*
|
|
356
|
+
* @param {Object} object The object for which Messenger should be instantiated.
|
|
357
|
+
*/
|
|
358
|
+
static initialize (object) {
|
|
359
|
+
object._listeners = {};
|
|
360
|
+
object._destroyed = false;
|
|
361
|
+
object.loopCheck = arrayCache.setUp();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export default Messenger;
|