@makefully/platypus 4.1.5 → 4.1.8
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 +31 -0
- package/README.md +3 -3
- package/lib/platypus.js +1 -1
- package/package.json +7 -6
- 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 +840 -0
- package/src/components/RenderSprite.js +527 -0
- package/src/components/RenderText.js +147 -0
- package/src/components/RenderTiles.js +1440 -0
- package/src/components/SceneChanger.js +128 -0
- package/src/components/TiledLoader.js +1459 -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/lib/243.platypus.mjs +0 -1
- package/lib/platypus.mjs +0 -1
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/* global platypus */
|
|
2
|
+
import {arrayCache, greenSplice} from '../utils/array.js';
|
|
3
|
+
import Data from '../Data.js';
|
|
4
|
+
import createComponentClass from '../factory.js';
|
|
5
|
+
import TimeEventList from '../TimeEventList.js';
|
|
6
|
+
|
|
7
|
+
const
|
|
8
|
+
pause = function () {
|
|
9
|
+
this.active--;
|
|
10
|
+
},
|
|
11
|
+
play = function () {
|
|
12
|
+
this.active++;
|
|
13
|
+
},
|
|
14
|
+
updateLogic = function (tick) {
|
|
15
|
+
const
|
|
16
|
+
{executionFlow, owner, timelineInstances} = this,
|
|
17
|
+
delta = tick.delta;
|
|
18
|
+
let i = timelineInstances.length,
|
|
19
|
+
removalOccurred = false;
|
|
20
|
+
|
|
21
|
+
while (i--) {
|
|
22
|
+
const
|
|
23
|
+
instance = timelineInstances[i];
|
|
24
|
+
|
|
25
|
+
if (instance.remove) {
|
|
26
|
+
greenSplice(timelineInstances, i);
|
|
27
|
+
instance.timeline.recycle();
|
|
28
|
+
instance.recycle();
|
|
29
|
+
removalOccurred = true;
|
|
30
|
+
} else if (instance.active) {
|
|
31
|
+
if (instance.timeline.list.length === 0) {
|
|
32
|
+
greenSplice(timelineInstances, i);
|
|
33
|
+
instance.timeline.recycle();
|
|
34
|
+
instance.recycle();
|
|
35
|
+
removalOccurred = true;
|
|
36
|
+
} else {
|
|
37
|
+
this.progressTimeline(instance, delta);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (timelineInstances.length) {
|
|
43
|
+
if (removalOccurred && executionFlow === 'serial') {
|
|
44
|
+
const
|
|
45
|
+
timeline = timelineInstances[0];
|
|
46
|
+
|
|
47
|
+
if (!timeline.active) {
|
|
48
|
+
timeline.play();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
owner.triggerEvent('timeline-progress', timelineInstances);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default createComponentClass(/** @lends platypus.components.Timeline.prototype */{
|
|
56
|
+
|
|
57
|
+
id: 'Timeline',
|
|
58
|
+
|
|
59
|
+
properties: {
|
|
60
|
+
/**
|
|
61
|
+
* Sets the execution flow if multiple timelines are triggered.
|
|
62
|
+
* * "parallel" - Each timeline begins immediately when triggered and does not directly affect other timelines.
|
|
63
|
+
* * "serial" - A timeline doesn't start if another timeline is currently active: it will append itself to a queue of timelines and run eventually.
|
|
64
|
+
* * "exclusive" - Timeline begins immediately and will stop any other active timeline.
|
|
65
|
+
* * "tentative" - Timeline begins if no other timelines are active, otherwise it is ignored.
|
|
66
|
+
*/
|
|
67
|
+
executionFlow: 'parallel',
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Defines the set of timelines. Triggering the key for one of the events will run the timeline. A timeline can contain three different types integers >= 0, strings, and objects. Integers are interpreted as waits and define
|
|
71
|
+
* pauses between events. Strings are intepreted as event calls. Objects can contain several parameters: entity, event, message. The entity is the id of the entity that
|
|
72
|
+
* the event will be fired on. The event can be a string or array. If a string, it will call that event on the entity or owner. If an array, the value will be passed
|
|
73
|
+
* to the event handling system.
|
|
74
|
+
*
|
|
75
|
+
* "timelines": {
|
|
76
|
+
* "sample-timeline-1": [
|
|
77
|
+
* 500,
|
|
78
|
+
* "sample-event",
|
|
79
|
+
* {"event": "sample-event", "message": "sample-message"},
|
|
80
|
+
* {"entity": "entity-id-to-trigger-event-on", "event": "sample-event"},
|
|
81
|
+
* {"event": ["sample-event", "sample-event-2", {"event": "sample-event-3", "message": "sample-message"}]},
|
|
82
|
+
* ],
|
|
83
|
+
* "sample-timeline-2": [
|
|
84
|
+
* 200,
|
|
85
|
+
* "sample-event"
|
|
86
|
+
* ]
|
|
87
|
+
* }
|
|
88
|
+
*
|
|
89
|
+
* @property timelines
|
|
90
|
+
* @type Object
|
|
91
|
+
* @default {}
|
|
92
|
+
*/
|
|
93
|
+
timelines: {}
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Timeline enables the scheduling of events based on a linear timeline
|
|
98
|
+
*
|
|
99
|
+
* @memberof platypus.components
|
|
100
|
+
* @uses platypus.Component
|
|
101
|
+
* @constructs
|
|
102
|
+
* @listens platypus.Entity#handle-logic
|
|
103
|
+
* @listens platypus.Entity#stop-active-timelines
|
|
104
|
+
*/
|
|
105
|
+
initialize: function () {
|
|
106
|
+
const
|
|
107
|
+
keys = Object.keys(this.timelines),
|
|
108
|
+
{length} = keys;
|
|
109
|
+
|
|
110
|
+
this.timelineInstances = arrayCache.setUp();
|
|
111
|
+
|
|
112
|
+
for (let i = 0; i < length; i++) {
|
|
113
|
+
const
|
|
114
|
+
timelineId = keys[i];
|
|
115
|
+
|
|
116
|
+
this.addTimeline(timelineId, this.timelines[timelineId]);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
events: {
|
|
121
|
+
"handle-logic": updateLogic,
|
|
122
|
+
|
|
123
|
+
"pause-timelines": function () {
|
|
124
|
+
this.timelineInstances.forEach((timeline) => {
|
|
125
|
+
if (timeline.active) {
|
|
126
|
+
timeline.pause();
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
"play-timelines": function () {
|
|
132
|
+
const
|
|
133
|
+
{executionFlow, timelineInstances} = this;
|
|
134
|
+
|
|
135
|
+
if (executionFlow === 'serial') {
|
|
136
|
+
if (timelineInstances.length) {
|
|
137
|
+
const
|
|
138
|
+
timeline = timelineInstances[0];
|
|
139
|
+
|
|
140
|
+
if (!timeline.active) {
|
|
141
|
+
timeline.play();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
timelineInstances.forEach((timeline) => {
|
|
146
|
+
if (!timeline.active) {
|
|
147
|
+
timeline.play();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Stops active timelines.
|
|
155
|
+
*
|
|
156
|
+
* @event platypus.Entity#stop-active-timelines
|
|
157
|
+
*/
|
|
158
|
+
"stop-active-timelines": function () {
|
|
159
|
+
const
|
|
160
|
+
instances = this.timelineInstances;
|
|
161
|
+
let i = instances.length;
|
|
162
|
+
|
|
163
|
+
while (i--) {
|
|
164
|
+
if (instances[i].active) {
|
|
165
|
+
instances[i].remove = true;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Stops all timelines.
|
|
172
|
+
*
|
|
173
|
+
* @event platypus.Entity#stop-all-timelines
|
|
174
|
+
*/
|
|
175
|
+
"stop-all-timelines": function () {
|
|
176
|
+
const
|
|
177
|
+
instances = this.timelineInstances;
|
|
178
|
+
let i = instances.length;
|
|
179
|
+
|
|
180
|
+
while (i--) {
|
|
181
|
+
instances[i].remove = true;
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Add a timeline dynamically.
|
|
187
|
+
*
|
|
188
|
+
* @event platypus.Entity#add-timeline
|
|
189
|
+
* @param eventId {String} The event to listen for to trigger the timeline.
|
|
190
|
+
* @param timeline {Array} The array of timeline data.
|
|
191
|
+
*/
|
|
192
|
+
"add-timeline": function (eventId, timeline) {
|
|
193
|
+
this.addTimeline(eventId, timeline);
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Play a timeline dynamically.
|
|
198
|
+
*
|
|
199
|
+
* @event platypus.Entity#start-timeline
|
|
200
|
+
* @param timeline {Array} The array of timeline data.
|
|
201
|
+
*/
|
|
202
|
+
"start-timeline": function (timeline) {
|
|
203
|
+
this.startTimeline(timeline);
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
methods: {
|
|
208
|
+
addTimeline: function (eventId, timeline) {
|
|
209
|
+
this.addEventListener(eventId, () => this.startTimeline(timeline));
|
|
210
|
+
},
|
|
211
|
+
createTimeStampedTimeline: function (timeline, active = 1) {
|
|
212
|
+
const
|
|
213
|
+
timeStampedTimeline = TimeEventList.setUp(timeline);
|
|
214
|
+
|
|
215
|
+
return Data.setUp(
|
|
216
|
+
"timeline", timeStampedTimeline,
|
|
217
|
+
"time", 0,
|
|
218
|
+
"total", timeStampedTimeline.getDuration(),
|
|
219
|
+
"active", 1,
|
|
220
|
+
"pause", pause,
|
|
221
|
+
"play", play,
|
|
222
|
+
"remove", false
|
|
223
|
+
);
|
|
224
|
+
},
|
|
225
|
+
startTimeline (timeline) {
|
|
226
|
+
const
|
|
227
|
+
{executionFlow, timelineInstances} = this;
|
|
228
|
+
|
|
229
|
+
switch (executionFlow) {
|
|
230
|
+
case 'serial':
|
|
231
|
+
timelineInstances.push(this.createTimeStampedTimeline(timeline), timelineInstances.some(({active}) => active) ? 0 : 1);
|
|
232
|
+
return true;
|
|
233
|
+
case 'exclusive':
|
|
234
|
+
timelineInstances.forEach((instance) => instance.remove = true);
|
|
235
|
+
timelineInstances.push(this.createTimeStampedTimeline(timeline));
|
|
236
|
+
return true;
|
|
237
|
+
case 'tentative':
|
|
238
|
+
if (!timelineInstances.some(({active}) => active)) {
|
|
239
|
+
timelineInstances.push(this.createTimeStampedTimeline(timeline));
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
return false;
|
|
243
|
+
default:
|
|
244
|
+
timelineInstances.push(this.createTimeStampedTimeline(timeline));
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
progressTimeline (instance, delta) {
|
|
249
|
+
const
|
|
250
|
+
timeline = instance.timeline;
|
|
251
|
+
|
|
252
|
+
instance.time += delta;
|
|
253
|
+
|
|
254
|
+
//Go through the timeline playing events if the time has progressed far enough to trigger them.
|
|
255
|
+
timeline.getEvents(instance.time).forEach((entry) => {
|
|
256
|
+
const
|
|
257
|
+
{event, entity} = entry;
|
|
258
|
+
|
|
259
|
+
if (typeof event === 'function') {
|
|
260
|
+
event(this.owner, instance);
|
|
261
|
+
} else {
|
|
262
|
+
let triggerOn = this.owner;
|
|
263
|
+
|
|
264
|
+
if (entity) {
|
|
265
|
+
if (typeof entity === 'string') {
|
|
266
|
+
if (this.owner.getEntityById) {
|
|
267
|
+
triggerOn = this.owner.getEntityById(entity);
|
|
268
|
+
} else {
|
|
269
|
+
triggerOn = this.owner.parent.getEntityById(entity);
|
|
270
|
+
}
|
|
271
|
+
} else {
|
|
272
|
+
triggerOn = entity; // Maybe it's an Entity.
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (!triggerOn) {
|
|
276
|
+
platypus.debug.warn('No entity of that id');
|
|
277
|
+
triggerOn = this.owner;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
triggerOn.trigger(entry);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
entry.recycle();
|
|
285
|
+
});
|
|
286
|
+
},
|
|
287
|
+
destroy: function () {
|
|
288
|
+
const
|
|
289
|
+
instances = this.timelineInstances;
|
|
290
|
+
let i = instances.length;
|
|
291
|
+
|
|
292
|
+
while (i--) {
|
|
293
|
+
const
|
|
294
|
+
instance = instances[i];
|
|
295
|
+
|
|
296
|
+
instance.timeline.recycle();
|
|
297
|
+
instance.recycle();
|
|
298
|
+
}
|
|
299
|
+
arrayCache.recycle(instances);
|
|
300
|
+
this.timelineInstances = null;
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
publicMethods: {
|
|
305
|
+
// asynchronous wait that incorporates ticker pauses.
|
|
306
|
+
wait (time) {
|
|
307
|
+
return new Promise ((resolve, reject) => {
|
|
308
|
+
if (!this.startTimeline([time, resolve])) {
|
|
309
|
+
reject();
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
});
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/* global platypus */
|
|
2
|
+
import createComponentClass from '../factory.js';
|
|
3
|
+
import {greenSlice} from '../utils/array.js';
|
|
4
|
+
|
|
5
|
+
const
|
|
6
|
+
entityAdded = function (entity) {
|
|
7
|
+
if (entity.type in this.watchedEntities) {
|
|
8
|
+
this.watchedEntities[entity.type].push(entity);
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
entityRemoved = function (entity) {
|
|
12
|
+
const
|
|
13
|
+
watchedEntities = this.watchedEntities[entity.type];
|
|
14
|
+
|
|
15
|
+
for (let x = watchedEntities.length - 1; x >= 0; x--) {
|
|
16
|
+
if (watchedEntities[x] === entity) {
|
|
17
|
+
watchedEntities.splice(x, 1);
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
updateLogic = function (tick) {
|
|
23
|
+
const
|
|
24
|
+
delta = tick.delta;
|
|
25
|
+
let toPlay = null,
|
|
26
|
+
toPlayIndex = -1;
|
|
27
|
+
|
|
28
|
+
for (let x = 0; x < this.tutorials.length; x++) {
|
|
29
|
+
const
|
|
30
|
+
tut = this.tutorials[x];
|
|
31
|
+
let keepChecking = false;
|
|
32
|
+
|
|
33
|
+
if (!this.playing && this.theQueue.length === 0) {
|
|
34
|
+
keepChecking = true;
|
|
35
|
+
} else if ((!this.playing && this.theQueue.length > 0) && (tut.priority > this.theQueue[0].priority)) {
|
|
36
|
+
keepChecking = true;
|
|
37
|
+
} else if (this.playing && (this.playing.priority < tut.priority)) {
|
|
38
|
+
keepChecking = true;
|
|
39
|
+
} else if (tut.queue) {
|
|
40
|
+
keepChecking = true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!keepChecking) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (this.checkRequirements(tut.requirements)) {
|
|
48
|
+
if (tut.replayDelay && tut.replayDelayTimer > 0) {
|
|
49
|
+
tut.replayDelayTimer -= delta;
|
|
50
|
+
if (tut.replayDelayTimer > 0) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!toPlay || toPlay.priority < tut.priority) {
|
|
56
|
+
//TML - If we only have one item we try to play, then we may prevent certain audio from playing if it's only valid for a single tick.
|
|
57
|
+
toPlay = tut;
|
|
58
|
+
toPlayIndex = x;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (toPlay) {
|
|
64
|
+
const
|
|
65
|
+
tutorial = this.tutorials.splice(toPlayIndex, 1)[0];
|
|
66
|
+
|
|
67
|
+
if (this.playing) {
|
|
68
|
+
if (tutorial.priority > this.playing.priority) {
|
|
69
|
+
/**
|
|
70
|
+
* On receiving this message, audio will stop playing.
|
|
71
|
+
*
|
|
72
|
+
* @event platypus.Entity#stop-audio
|
|
73
|
+
* @param audioId {String} If an audioId is provided, that particular sound instance is stopped. Otherwise all audio is stopped.
|
|
74
|
+
*/
|
|
75
|
+
this.owner.triggerEvent('stop-audio');
|
|
76
|
+
this.play(tutorial);
|
|
77
|
+
} else {
|
|
78
|
+
this.queue(tutorial);
|
|
79
|
+
}
|
|
80
|
+
} else if (this.theQueue.length > 0) {
|
|
81
|
+
if (tutorial.priority > this.theQueue[0].priority) {
|
|
82
|
+
this.play(tutorial);
|
|
83
|
+
} else {
|
|
84
|
+
this.play(this.theQueue.splice(0, 1)[0]);
|
|
85
|
+
this.queue(tutorial);
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
this.play(tutorial);
|
|
89
|
+
}
|
|
90
|
+
} else if (!this.playing && this.theQueue.length > 0) {
|
|
91
|
+
this.play(this.theQueue.splice(0, 1)[0]);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export default createComponentClass(/** @lends platypus.components.Tutorial.prototype */{
|
|
96
|
+
|
|
97
|
+
id: 'Tutorial',
|
|
98
|
+
|
|
99
|
+
properties: {
|
|
100
|
+
|
|
101
|
+
/* An array of tutorial definition objects. These objects define what events will be called by the tutorial, the priority of the tutorial, how often and how many times it will fire, the required conditions for it to fire, and more.
|
|
102
|
+
*
|
|
103
|
+
* "tutorialDefs": [
|
|
104
|
+
* {
|
|
105
|
+
* "events": ["example-vo-event"], //An Array of Strings. Defines the events to fire when all the conditions for this tutorial are met. If there are multiple events, one is chosen at random. All events in the array will play before any repeat.
|
|
106
|
+
* "priority": 5, //The priorioty of the tutorial. Higher numbered tutorials interrupt lower numbered. Default: 0.
|
|
107
|
+
* "queue": true, //Will the tutorial queue up if played while another tutorial is playing? Default: false.
|
|
108
|
+
* "timesToReplay": 3, //The number of times a tutorial will replay. Set to 0 to make a tutorial play only once. Default: Infinity.
|
|
109
|
+
* "replayDelay": 10000, //While the conditions are met, the tutorial will replay at this interval in milliseconds. If set to null, it will not repeat. Default: null.
|
|
110
|
+
* "level": "example-level", //Tutorial will only play when this level is the currently loaded level.
|
|
111
|
+
* "requirements": { //The requirements is a collection of entities types that are watched by the tutorial to determine if the conditions to play this tutorial are true.
|
|
112
|
+
* "example-entity-type": ["example-entity-state"] //The requirements is a set of key-value pairs. The keys are entity types that the tutorial will watch. The values are arrays of states of that entity type which must be true for the tutorial to play.
|
|
113
|
+
* }
|
|
114
|
+
* }
|
|
115
|
+
* ]
|
|
116
|
+
*
|
|
117
|
+
* @property tutorialDefs
|
|
118
|
+
* @type Array [Object]
|
|
119
|
+
* @default []
|
|
120
|
+
*/
|
|
121
|
+
"tutorialDefs": []
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Tutorial provides a framework for playing tutorials. It allows the user to define things such as under what conditions tutorials will play, how often they play, and which tutorials have priority.
|
|
126
|
+
*
|
|
127
|
+
* @memberof platypus.components
|
|
128
|
+
* @uses platypus.Component
|
|
129
|
+
* @constructs
|
|
130
|
+
* @listens platypus.Entity#child-entity-added
|
|
131
|
+
* @listens platypus.Entity#child-entity-removed
|
|
132
|
+
* @listens platypus.Entity#handle-logic
|
|
133
|
+
* @listens platypus.Entity#peer-entity-added
|
|
134
|
+
* @listens platypus.Entity#peer-entity-removed
|
|
135
|
+
* @listens platypus.Entity#sequence-complete
|
|
136
|
+
* @fires platypus.Entity#stop-audio
|
|
137
|
+
*/
|
|
138
|
+
initialize: function () {
|
|
139
|
+
this.playing = null;
|
|
140
|
+
this.theQueue = [];
|
|
141
|
+
this.watchedEntities = {};
|
|
142
|
+
this.tutorials = [];
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
for (let x = 0; x < this.tutorialDefs.length; x++) {
|
|
146
|
+
const
|
|
147
|
+
tutDef = this.tutorialDefs[x];
|
|
148
|
+
|
|
149
|
+
if (!tutDef.events) {
|
|
150
|
+
platypus.debug.warn("Tutorial definition lacks events.");
|
|
151
|
+
} else {
|
|
152
|
+
const
|
|
153
|
+
tutorial = {
|
|
154
|
+
events: greenSlice(tutDef.events),
|
|
155
|
+
originalEvents: greenSlice(tutDef.events),
|
|
156
|
+
priority: tutDef.priority || 0,
|
|
157
|
+
queue: tutDef.queue || false,
|
|
158
|
+
timesToReplay: (typeof tutDef.timesToReplay === 'number') ? tutDef.timesToReplay : Infinity,
|
|
159
|
+
replayDelay: tutDef.replayDelay || null,
|
|
160
|
+
replayDelayTimer: tutDef.replayDelay || null,
|
|
161
|
+
level: tutDef.level,
|
|
162
|
+
requirements: {}
|
|
163
|
+
},
|
|
164
|
+
keys = Object.keys(tutDef.requirements),
|
|
165
|
+
{length} = keys;
|
|
166
|
+
|
|
167
|
+
for (let i = 0; i < length; i++) {
|
|
168
|
+
const
|
|
169
|
+
entityType = keys[i];
|
|
170
|
+
|
|
171
|
+
tutorial.requirements[entityType] = greenSlice(tutDef.requirements[entityType]);
|
|
172
|
+
if (!this.watchedEntities[entityType]) {
|
|
173
|
+
this.watchedEntities[entityType] = [];
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
this.tutorials.push(tutorial);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
events: {// These are messages that this component listens for
|
|
182
|
+
"child-entity-added": entityAdded,
|
|
183
|
+
|
|
184
|
+
"peer-entity-added": entityAdded,
|
|
185
|
+
|
|
186
|
+
"child-entity-removed": entityRemoved,
|
|
187
|
+
|
|
188
|
+
"peer-entity-removed": entityRemoved,
|
|
189
|
+
|
|
190
|
+
"handle-logic": updateLogic,
|
|
191
|
+
|
|
192
|
+
"sequence-complete": function () {
|
|
193
|
+
if (this.playing.timesToReplay >= 0) {
|
|
194
|
+
this.tutorials.push(this.playing);
|
|
195
|
+
}
|
|
196
|
+
this.playing = null;
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
methods: {// These are internal methods that are invoked by this component.
|
|
201
|
+
play: function (tutorial) {
|
|
202
|
+
this.playing = tutorial;
|
|
203
|
+
if (this.playing.events.length === 0) {
|
|
204
|
+
this.playing.events = greenSlice(this.playing.originalEvents);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this.owner.triggerEvent(this.playing.events.splice(Math.floor(Math.random() * this.playing.events.length), 1)[0]);
|
|
208
|
+
|
|
209
|
+
tutorial.timesToReplay -= 1;
|
|
210
|
+
tutorial.replayDelayTimer = tutorial.replayDelay;
|
|
211
|
+
},
|
|
212
|
+
queue: function (tutorial) {
|
|
213
|
+
let added = false;
|
|
214
|
+
|
|
215
|
+
for (let x = 0; x < this.theQueue.length; x++) {
|
|
216
|
+
if (this.theQueue[x].priority < tutorial.priority) {
|
|
217
|
+
this.theQueue.splice(x, 0, tutorial);
|
|
218
|
+
added = true;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (!added) {
|
|
224
|
+
this.theQueue.push(tutorial);
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
checkRequirements: function (requirements) {
|
|
228
|
+
const
|
|
229
|
+
keys = Object.keys(requirements),
|
|
230
|
+
{length} = keys;
|
|
231
|
+
|
|
232
|
+
//Going through the types of entities
|
|
233
|
+
for (let i = 0; i < length; i++) {
|
|
234
|
+
const
|
|
235
|
+
entityType = keys[i],
|
|
236
|
+
states = requirements[entityType];
|
|
237
|
+
let metRequirement = true;
|
|
238
|
+
|
|
239
|
+
for (let y = this.watchedEntities[entityType].length - 1; y >= 0; y--) { //Going through the instances of those entities
|
|
240
|
+
const
|
|
241
|
+
anEntity = this.watchedEntities[entityType][y];
|
|
242
|
+
|
|
243
|
+
metRequirement = true;
|
|
244
|
+
for (let x = 0; x < states.length; x++) { //Going through the required states of an entity instance
|
|
245
|
+
if (!anEntity.state.get(states[x])) {
|
|
246
|
+
metRequirement = false;
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (metRequirement) {
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (!metRequirement) {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return true;
|
|
259
|
+
},
|
|
260
|
+
destroy: function () {
|
|
261
|
+
this.watchedEntities = null;
|
|
262
|
+
this.theQueue = null;
|
|
263
|
+
this.playing = null;
|
|
264
|
+
this.tutorials = null;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
});
|