@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
package/src/RandomSet.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import recycle from 'recycle';
|
|
2
|
+
|
|
3
|
+
export default (function () {
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This class defines a set that is populated and then pulled from at random. When pulled from, the set will return copies of the contents
|
|
7
|
+
* such that all the contents in the set are used once before there are repeats. Repeats may still occur when the set has been used
|
|
8
|
+
* up or when the number of items requested is greater than the size of the set.
|
|
9
|
+
*
|
|
10
|
+
* @memberof platypus
|
|
11
|
+
* @class RandomSet
|
|
12
|
+
* @param contents {array} The contents that will populate the set.
|
|
13
|
+
* @return {platypus.RandomSet} Returns the new RandomSet object.
|
|
14
|
+
*/
|
|
15
|
+
const RandomSet = function (contents) {
|
|
16
|
+
let x = 0;
|
|
17
|
+
|
|
18
|
+
if (contents) {
|
|
19
|
+
this.contents = [];
|
|
20
|
+
for (x = 0; x < contents.length; x++) {
|
|
21
|
+
this.contents.push(contents[x]);
|
|
22
|
+
}
|
|
23
|
+
} else {
|
|
24
|
+
this.contents = [];
|
|
25
|
+
}
|
|
26
|
+
this.availableIndexes = [];
|
|
27
|
+
|
|
28
|
+
this.refill();
|
|
29
|
+
},
|
|
30
|
+
proto = RandomSet.prototype;
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
proto.refill = function () {
|
|
34
|
+
let x = 0;
|
|
35
|
+
|
|
36
|
+
for (x = 0; x < this.contents.length; x++) {
|
|
37
|
+
this.availableIndexes.push(x);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Add single element to the content set. Includes the new content in the current set, which means it be returned quickly depending on the remaining set size.
|
|
43
|
+
*
|
|
44
|
+
* @method platypus.RandomSet#add
|
|
45
|
+
* @param toAdd {primitive|Object} Content to add to the set.
|
|
46
|
+
*/
|
|
47
|
+
proto.add = function (toAdd) {
|
|
48
|
+
this.contents.push(toAdd);
|
|
49
|
+
this.availableIndexes.push(this.contents.length - 1);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Remove from the content set. Use removeAll if you want to remove all instances, otherwise only removes the first instance found.
|
|
54
|
+
*
|
|
55
|
+
* @method platypus.RandomSet#remove
|
|
56
|
+
* @param toRemove {primitive|Object} Content to remove from the set.
|
|
57
|
+
* @param removeAll {boolean} Remove all instances of the primitive/object.
|
|
58
|
+
*/
|
|
59
|
+
proto.remove = function (toRemove, removeAll) {
|
|
60
|
+
let index = -1,
|
|
61
|
+
indexesIndex = -1;
|
|
62
|
+
|
|
63
|
+
do {
|
|
64
|
+
index = this.contents.indexOf(toRemove);
|
|
65
|
+
if (index !== -1) {
|
|
66
|
+
this.contents.splice(index, 1);
|
|
67
|
+
|
|
68
|
+
indexesIndex = this.availableIndexes.indexOf(index);
|
|
69
|
+
this.availableIndexes.splice(indexesIndex, 1);
|
|
70
|
+
|
|
71
|
+
// Now we need to re-index entries above index...
|
|
72
|
+
for (let i = 0; i < this.availableIndexes; i++) {
|
|
73
|
+
if (this.availableIndexes[i] > index) {
|
|
74
|
+
this.availableIndexes[i] -= 1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
} while (index !== -1 && removeAll);
|
|
79
|
+
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get a random member of the set.
|
|
84
|
+
*
|
|
85
|
+
* @method platypus.RandomSet#get
|
|
86
|
+
* @return {primitive|Object} A random member of the set
|
|
87
|
+
*/
|
|
88
|
+
proto.get = function () {
|
|
89
|
+
let index = 0;
|
|
90
|
+
|
|
91
|
+
if (this.availableIndexes.length === 0) {
|
|
92
|
+
this.refill();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
index = this.availableIndexes.splice(Math.floor(Math.random() * this.availableIndexes.length), 1)[0];
|
|
96
|
+
|
|
97
|
+
return this.contents[index];
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get an array of random set members. There may be multiple of the same member in the set if the quantity requested is greater
|
|
102
|
+
* than the set size, or the set is exhausted and replenished while retrieving members.
|
|
103
|
+
*
|
|
104
|
+
* @method platypus.RandomSet#getMultiple
|
|
105
|
+
* @param numberToGet {integer} Number of set members to retrieve
|
|
106
|
+
* @return {primitive|Object} A random member of the set
|
|
107
|
+
*/
|
|
108
|
+
proto.getMultiple = function (numberToGet) {
|
|
109
|
+
const toReturn = [];
|
|
110
|
+
let x = 0;
|
|
111
|
+
|
|
112
|
+
for (x = 0; x < numberToGet; x++) {
|
|
113
|
+
toReturn.push(this.get());
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return toReturn;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Returns an RandomSet from cache or creates a new one if none are available.
|
|
122
|
+
*
|
|
123
|
+
* @method platypus.RandomSet.setUp
|
|
124
|
+
* @return {platypus.RandomSet} The instantiated RandomSet.
|
|
125
|
+
*/
|
|
126
|
+
/**
|
|
127
|
+
* Returns a RandomSet back to the cache.
|
|
128
|
+
*
|
|
129
|
+
* @method platypus.RandomSet.recycle
|
|
130
|
+
* @param {platypus.RandomSet} randomSet The RandomSet to be recycled.
|
|
131
|
+
*/
|
|
132
|
+
/**
|
|
133
|
+
* Relinquishes properties of the RandomSet and recycles it.
|
|
134
|
+
*
|
|
135
|
+
* @method platypus.RandomSet#recycle
|
|
136
|
+
*/
|
|
137
|
+
recycle.add(RandomSet, 'RandomSet', RandomSet, null, true);
|
|
138
|
+
|
|
139
|
+
return RandomSet;
|
|
140
|
+
}());
|
package/src/SFXPlayer.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/* global platypus */
|
|
2
|
+
import {arrayCache, greenSplice} from './utils/array.js';
|
|
3
|
+
import TweenJS from '@tweenjs/tween.js';
|
|
4
|
+
|
|
5
|
+
const
|
|
6
|
+
{Tween} = TweenJS;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* This class plays sfx audio and manages Springroll volume changes.
|
|
10
|
+
*
|
|
11
|
+
* @memberof platypus
|
|
12
|
+
* @class SFXPlayer
|
|
13
|
+
*/
|
|
14
|
+
export default class SFXPlayer {
|
|
15
|
+
constructor () {
|
|
16
|
+
this.masterVolume = 1;
|
|
17
|
+
this.volume = 1;
|
|
18
|
+
this.playingAudio = arrayCache.setUp();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Plays a sound.
|
|
23
|
+
*
|
|
24
|
+
* @method platypus.SFXPlayer#play
|
|
25
|
+
* @param {String} sound Sound Id to play.
|
|
26
|
+
* @param {Object} data PixiSound data to inform sound playback.
|
|
27
|
+
* @return {pixiSound.MediaInstance} The media instance of the playing sound.
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
play (sound, data) {
|
|
31
|
+
const
|
|
32
|
+
sfx = typeof sound === 'string' ? platypus.assetCache.get(platypus.assetCache.getFileId(sound)) : sound,
|
|
33
|
+
audio = sfx.play(data);
|
|
34
|
+
|
|
35
|
+
audio.initialVolume = (typeof data.initialVolume === 'number' ? data.initialVolume : audio.volume);
|
|
36
|
+
audio.set('volume', audio.volume * this.volume * this.masterVolume);
|
|
37
|
+
this.playingAudio.push(audio);
|
|
38
|
+
audio.on('end', () => {
|
|
39
|
+
const index = this.playingAudio.indexOf(audio);
|
|
40
|
+
|
|
41
|
+
greenSplice(this.playingAudio, index);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return audio;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Plays a sound.
|
|
49
|
+
*
|
|
50
|
+
* @method platypus.SFXPlayer#stop
|
|
51
|
+
* @param {pixiSound.MediaInstance} audio Audio to stop.
|
|
52
|
+
* @public
|
|
53
|
+
*/
|
|
54
|
+
stop (audio) {
|
|
55
|
+
const index = this.playingAudio.indexOf(audio);
|
|
56
|
+
|
|
57
|
+
audio.stop();
|
|
58
|
+
if (index >= 0) {
|
|
59
|
+
greenSplice(this.playingAudio, index);
|
|
60
|
+
} else {
|
|
61
|
+
platypus.debug.warn('SFXPlayer: Did not find "' + audio.soundId + '"');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
fade (audio, volume, time, onComplete = () => {}) {
|
|
66
|
+
const
|
|
67
|
+
tween = new Tween(audio);
|
|
68
|
+
|
|
69
|
+
tween.to({
|
|
70
|
+
initialVolume: volume
|
|
71
|
+
}, time);
|
|
72
|
+
tween.onUpdate(() => {
|
|
73
|
+
audio.set('volume', audio.initialVolume * this.volume * this.masterVolume);
|
|
74
|
+
});
|
|
75
|
+
tween.onComplete(onComplete);
|
|
76
|
+
tween.start();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Sets volume on all playing sound effects.
|
|
81
|
+
*
|
|
82
|
+
* @method platypus.SFXPlayer#setVolume
|
|
83
|
+
* @param {Number} volume A value between 0-1 to set volume on all playing sound effects.
|
|
84
|
+
* @public
|
|
85
|
+
*/
|
|
86
|
+
setVolume (volume) {
|
|
87
|
+
const
|
|
88
|
+
playingAudio = this.playingAudio;
|
|
89
|
+
|
|
90
|
+
this.volume = volume;
|
|
91
|
+
for (let i = 0; i < playingAudio.length; i++) {
|
|
92
|
+
const
|
|
93
|
+
audio = playingAudio[i];
|
|
94
|
+
|
|
95
|
+
audio.set('volume', audio.initialVolume * this.volume * this.masterVolume);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Sets master volume on all playing sound effects.
|
|
101
|
+
*
|
|
102
|
+
* @method platypus.SFXPlayer#setMasterVolume
|
|
103
|
+
* @param {Number} volume A value between 0-1 to set volume on all playing sound effects.
|
|
104
|
+
* @public
|
|
105
|
+
*/
|
|
106
|
+
setMasterVolume (volume) {
|
|
107
|
+
this.masterVolume = volume;
|
|
108
|
+
this.setVolume(this.volume);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Cleans up this SFXPlayer.
|
|
113
|
+
* @method platypus.SFXPlayer#destroy
|
|
114
|
+
* @public
|
|
115
|
+
*/
|
|
116
|
+
destroy () {
|
|
117
|
+
arrayCache.recycle(this.playingAudio);
|
|
118
|
+
this.playingAudio = null;
|
|
119
|
+
}
|
|
120
|
+
};
|
package/src/StateMap.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import DataMap from './DataMap.js';
|
|
2
|
+
import {arrayCache} from './utils/array.js';
|
|
3
|
+
import {greenSplit} from './utils/string.js';
|
|
4
|
+
import recycle from 'recycle';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This class defines a state object to use for entity states with helper methods. It includes recycle methods to encourage reuse.
|
|
8
|
+
*
|
|
9
|
+
* @memberof platypus
|
|
10
|
+
* @class StateMap
|
|
11
|
+
* @extends platypus.DataMap
|
|
12
|
+
* @return stateMap {platypus.StateMap} Returns the new StateMap object.
|
|
13
|
+
*/
|
|
14
|
+
const
|
|
15
|
+
clean = function (arr) {
|
|
16
|
+
const
|
|
17
|
+
cleaned = arrayCache.setUp();
|
|
18
|
+
|
|
19
|
+
if (typeof arr[0] === 'string') {
|
|
20
|
+
for (let i = 0; i < arr.length; i++) {
|
|
21
|
+
cleaned.push((i % 2) ? !!arr[i] : arr[i]);
|
|
22
|
+
}
|
|
23
|
+
} else if (typeof arr[0] === 'object') {
|
|
24
|
+
const
|
|
25
|
+
obj = arr[0];
|
|
26
|
+
|
|
27
|
+
if (obj.keys && obj.get) {
|
|
28
|
+
const
|
|
29
|
+
{keys} = obj;
|
|
30
|
+
let i = keys.length;
|
|
31
|
+
|
|
32
|
+
while (i--) {
|
|
33
|
+
cleaned.push(keys[i], !!obj.get(keys[i]));
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
const
|
|
37
|
+
keys = Object.keys(obj);
|
|
38
|
+
let i = keys.length;
|
|
39
|
+
|
|
40
|
+
while (i--) {
|
|
41
|
+
cleaned.push(keys[i], !!obj[keys[i]]);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return cleaned;
|
|
47
|
+
},
|
|
48
|
+
StateMap = function (first) {
|
|
49
|
+
const
|
|
50
|
+
l = arguments.length;
|
|
51
|
+
|
|
52
|
+
if (l) {
|
|
53
|
+
if ((l === 1) && (typeof first === 'string')) {
|
|
54
|
+
DataMap.call(this);
|
|
55
|
+
this.updateFromString(first);
|
|
56
|
+
} else {
|
|
57
|
+
const
|
|
58
|
+
cleanedArgs = clean(arguments);
|
|
59
|
+
|
|
60
|
+
DataMap.apply(this, cleanedArgs);
|
|
61
|
+
arrayCache.recycle(cleanedArgs);
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
DataMap.call(this);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
parent = DataMap.prototype,
|
|
68
|
+
proto = StateMap.prototype = Object.create(parent);
|
|
69
|
+
|
|
70
|
+
Object.defineProperty(proto, 'constructor', {
|
|
71
|
+
configurable: true,
|
|
72
|
+
writable: true,
|
|
73
|
+
value: StateMap
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Returns a JSON object of state keys and boolean values.
|
|
78
|
+
*
|
|
79
|
+
* @method platypus.StateMap#toJSON
|
|
80
|
+
* @return {Object} State keys mapped to `true` or `false`.
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Returns a comma-delimited list of state keys compatible with `updateFromString`. False values are prefixed with `"!"`.
|
|
85
|
+
*
|
|
86
|
+
* @method platypus.StateMap#toString
|
|
87
|
+
* @return {String} The serialized state string.
|
|
88
|
+
*/
|
|
89
|
+
Object.defineProperty(proto, 'toString', {
|
|
90
|
+
value: function () {
|
|
91
|
+
const
|
|
92
|
+
{keys} = this;
|
|
93
|
+
let i = keys.length,
|
|
94
|
+
parts = arrayCache.setUp();
|
|
95
|
+
|
|
96
|
+
while (i--) {
|
|
97
|
+
const
|
|
98
|
+
key = keys[i];
|
|
99
|
+
|
|
100
|
+
parts.push(this.get(key) ? key : `!${key}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const
|
|
104
|
+
string = parts.join(',');
|
|
105
|
+
|
|
106
|
+
arrayCache.recycle(parts);
|
|
107
|
+
|
|
108
|
+
return string;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Sets the state using the provided string value which is a comma-delimited list such that `"blue,red,!green"` sets the following state values:
|
|
114
|
+
*
|
|
115
|
+
* {
|
|
116
|
+
* red: true,
|
|
117
|
+
* blue: true,
|
|
118
|
+
* green: false
|
|
119
|
+
* }
|
|
120
|
+
*
|
|
121
|
+
* @method platypus.StateMap#updateFromString
|
|
122
|
+
* @param states {String} A comma-delimited list of true/false state values.
|
|
123
|
+
* @chainable
|
|
124
|
+
*/
|
|
125
|
+
Object.defineProperty(proto, 'updateFromString', {
|
|
126
|
+
value: function (states) {
|
|
127
|
+
const
|
|
128
|
+
arr = greenSplit(states, ',');
|
|
129
|
+
let i = arr.length;
|
|
130
|
+
|
|
131
|
+
while (i--) {
|
|
132
|
+
const
|
|
133
|
+
str = arr[i];
|
|
134
|
+
|
|
135
|
+
if (str) {
|
|
136
|
+
if (str.substr(0, 1) === '!') {
|
|
137
|
+
this.set(str.substr(1), false);
|
|
138
|
+
} else {
|
|
139
|
+
this.set(str, true);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
arrayCache.recycle(arr);
|
|
145
|
+
|
|
146
|
+
return this;
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Checks whether the provided state matches this state and updates this state to match.
|
|
152
|
+
*
|
|
153
|
+
* @method platypus.StateMap#update
|
|
154
|
+
* @param state {platypus.StateMap} The state that this state should match.
|
|
155
|
+
* @return {Boolean} Whether this state already matches the provided state.
|
|
156
|
+
*/
|
|
157
|
+
Object.defineProperty(proto, 'update', {
|
|
158
|
+
value: function (newState) {
|
|
159
|
+
const
|
|
160
|
+
{keys} = newState;
|
|
161
|
+
let i = keys.length,
|
|
162
|
+
changed = false;
|
|
163
|
+
|
|
164
|
+
while (i--) {
|
|
165
|
+
const
|
|
166
|
+
state = keys[i],
|
|
167
|
+
value = newState.get(state);
|
|
168
|
+
|
|
169
|
+
if (this.get(state) !== value) {
|
|
170
|
+
this.set(state, value);
|
|
171
|
+
changed = true;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return changed;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Checks whether the provided state matches all equivalent keys on this state.
|
|
181
|
+
*
|
|
182
|
+
* @method platypus.StateMap#includes
|
|
183
|
+
* @param state {platypus.StateMap} The state that this state should match.
|
|
184
|
+
* @return {Boolean} Whether this state matches the provided state.
|
|
185
|
+
*/
|
|
186
|
+
Object.defineProperty(proto, 'includes', {
|
|
187
|
+
value: function (otherState) {
|
|
188
|
+
const
|
|
189
|
+
{keys} = otherState;
|
|
190
|
+
let i = keys.length;
|
|
191
|
+
|
|
192
|
+
while (i--) {
|
|
193
|
+
const
|
|
194
|
+
state = keys[i];
|
|
195
|
+
|
|
196
|
+
if (this.get(state) !== otherState.get(state)) {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Checks whether the provided state matches any equivalent keys on this state.
|
|
207
|
+
*
|
|
208
|
+
* @method platypus.StateMap#intersects
|
|
209
|
+
* @param state {platypus.StateMap} The state that this state should intersect.
|
|
210
|
+
* @return {Boolean} Whether this state intersects the provided state.
|
|
211
|
+
*/
|
|
212
|
+
Object.defineProperty(proto, 'intersects', {
|
|
213
|
+
value: function (otherState) {
|
|
214
|
+
const
|
|
215
|
+
{keys} = otherState;
|
|
216
|
+
let i = keys.length;
|
|
217
|
+
|
|
218
|
+
while (i--) {
|
|
219
|
+
const
|
|
220
|
+
state = keys[i];
|
|
221
|
+
|
|
222
|
+
if (this.get(state) === otherState.get(state)) {
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Returns StateMap from cache or creates a new one if none are available.
|
|
233
|
+
*
|
|
234
|
+
* @method platypus.StateMap.setUp
|
|
235
|
+
* @return {platypus.StateMap} The instantiated StateMap.
|
|
236
|
+
*/
|
|
237
|
+
/**
|
|
238
|
+
* Returns StateMap back to the cache. Prefer the StateMap's recycle method since it recycles property objects as well.
|
|
239
|
+
*
|
|
240
|
+
* @method platypus.StateMap.recycle
|
|
241
|
+
* @param {platypus.StateMap} stateMap The StateMap to be recycled.
|
|
242
|
+
*/
|
|
243
|
+
/**
|
|
244
|
+
* Relinquishes StateMap properties and recycles it.
|
|
245
|
+
*
|
|
246
|
+
* @method platypus.StateMap#recycle
|
|
247
|
+
*/
|
|
248
|
+
recycle.add(StateMap, 'StateMap', StateMap, function () {
|
|
249
|
+
this.clear();
|
|
250
|
+
}, true);
|
|
251
|
+
|
|
252
|
+
export default StateMap;
|
package/src/Storage.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/* global platypus, window */
|
|
2
|
+
import DataMap from './DataMap.js';
|
|
3
|
+
import {UserData} from 'springroll';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This class is used to create the Platypus storage system accessible at `platypus.storage`. It uses Springroll UserData if available, with a fallback to local storage if not.
|
|
7
|
+
*
|
|
8
|
+
* @memberof platypus
|
|
9
|
+
* @class Storage
|
|
10
|
+
* @param {*} springroll
|
|
11
|
+
* @param {*} options
|
|
12
|
+
* @return {Data} Returns the new Storage object.
|
|
13
|
+
*/
|
|
14
|
+
class Storage {
|
|
15
|
+
constructor (springroll, {name: gameId, storageKeys: keys = null}) {
|
|
16
|
+
const
|
|
17
|
+
storageKey = `${gameId}-data`,
|
|
18
|
+
unconnectedData = window.localStorage.getItem(storageKey),
|
|
19
|
+
handleData = (resp) => {
|
|
20
|
+
const
|
|
21
|
+
data = resp?.data ?? resp;
|
|
22
|
+
|
|
23
|
+
if (data) {
|
|
24
|
+
const
|
|
25
|
+
keys = Object.keys(data),
|
|
26
|
+
{length} = keys;
|
|
27
|
+
|
|
28
|
+
for (let i = 0; i < length; i++) {
|
|
29
|
+
const
|
|
30
|
+
key = keys[i];
|
|
31
|
+
|
|
32
|
+
if (this.map.has(key)) {
|
|
33
|
+
this.map.set(key, data[key]);
|
|
34
|
+
} else {
|
|
35
|
+
this.addKey(key, data[key]);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
this.map = DataMap.setUp();
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The storage key being used to store data.
|
|
45
|
+
*
|
|
46
|
+
* @property storageKey
|
|
47
|
+
* @type String
|
|
48
|
+
* @default options.name+'-data'
|
|
49
|
+
*/
|
|
50
|
+
this.storageKey = storageKey;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Whether Springroll is connected to a hosting page.
|
|
54
|
+
*
|
|
55
|
+
* @property connected
|
|
56
|
+
* @type Boolean
|
|
57
|
+
* @default false
|
|
58
|
+
*/
|
|
59
|
+
this.connected = false;
|
|
60
|
+
|
|
61
|
+
if (keys) {
|
|
62
|
+
for (let i = 0; i < keys.length; i++) {
|
|
63
|
+
this.addKey(keys[i], null);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try { // May throw if data is not parseable. If so, we'll just ignore it.
|
|
68
|
+
handleData(JSON.parse(unconnectedData));
|
|
69
|
+
} catch (e) {}
|
|
70
|
+
|
|
71
|
+
// Using Bellhop's "connected" event because springroll.state.ready doesn't ensure that Bellhop is also ready.
|
|
72
|
+
springroll.container.on('connected', async () => {
|
|
73
|
+
this.connected = true;
|
|
74
|
+
try {
|
|
75
|
+
handleData(await UserData.read(this.storageKey));
|
|
76
|
+
} catch (e) {
|
|
77
|
+
platypus.debug.warn('Storage: connected but received an error', e);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Adds a storage key to the game's storage.
|
|
84
|
+
*
|
|
85
|
+
* @param {String} key The key to add.
|
|
86
|
+
* @param {*} value The data to store at this defined key.
|
|
87
|
+
*/
|
|
88
|
+
addKey (key, value) {
|
|
89
|
+
this.map.set(key, value);
|
|
90
|
+
Object.defineProperty(this, key, {
|
|
91
|
+
get: function () {
|
|
92
|
+
return this.map.get(key);
|
|
93
|
+
},
|
|
94
|
+
set: function (value) {
|
|
95
|
+
this.map.set(key, value);
|
|
96
|
+
|
|
97
|
+
this.save();
|
|
98
|
+
},
|
|
99
|
+
configurable: true,
|
|
100
|
+
enumerable: true
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Gets a value from storage for the provided storage key.
|
|
106
|
+
*
|
|
107
|
+
* @param {String} key The key for the data to return
|
|
108
|
+
* @return {*}
|
|
109
|
+
*/
|
|
110
|
+
get (key) {
|
|
111
|
+
if (!this.map.has(key)) {
|
|
112
|
+
this.addKey(key, null);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return this[key];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Takes the current game storage and saves it to local storage or Springroll UserData
|
|
120
|
+
*
|
|
121
|
+
*/
|
|
122
|
+
async save () {
|
|
123
|
+
const save = this.map.toJSON();
|
|
124
|
+
|
|
125
|
+
if (this.connected) {
|
|
126
|
+
try {
|
|
127
|
+
await UserData.write(this.storageKey, save);
|
|
128
|
+
} catch (e) {
|
|
129
|
+
platypus.debug.warn('Storage: tried to save but received an error', e);
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
window.localStorage.setItem(this.storageKey, JSON.stringify(save));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Updates a storage key's data. Creates the key if it does not exist.
|
|
138
|
+
*
|
|
139
|
+
* @param {String} key The key to update.
|
|
140
|
+
* @param {*} value The data to store at this key.
|
|
141
|
+
*/
|
|
142
|
+
set (key, value) {
|
|
143
|
+
if (!this.map.has(key)) {
|
|
144
|
+
this.addKey(key, value);
|
|
145
|
+
this.save();
|
|
146
|
+
} else {
|
|
147
|
+
this[key] = value;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export default Storage;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export default class {
|
|
2
|
+
constructor (targetFPS = 60) {
|
|
3
|
+
const
|
|
4
|
+
listeners = this.listeners = [],
|
|
5
|
+
worker = this.worker = new Worker(new URL('./TickerServer.js', import.meta.url));
|
|
6
|
+
|
|
7
|
+
this.deltaMS = 1000 / targetFPS;
|
|
8
|
+
this.elapsedMS = this.deltaMS;
|
|
9
|
+
|
|
10
|
+
worker.onmessage = ({data}) => {
|
|
11
|
+
this.elapsedMS = data.deltaTime;
|
|
12
|
+
listeners.forEach((listener) => listener(data));
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
this.start();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
add (listener) {
|
|
19
|
+
this.listeners.push(listener);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
remove (listener) {
|
|
23
|
+
const
|
|
24
|
+
i = this.listeners.indexOf(listener);
|
|
25
|
+
|
|
26
|
+
if (i >= 0) {
|
|
27
|
+
this.listeners.splice(i, 1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
start () {
|
|
32
|
+
this.worker.postMessage({
|
|
33
|
+
begin: {
|
|
34
|
+
delta: this.deltaMS
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
stop () {
|
|
40
|
+
this.worker.postMessage({
|
|
41
|
+
stop: true
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get FPS () {
|
|
46
|
+
return 1000 / this.elapsedMS;
|
|
47
|
+
}
|
|
48
|
+
}
|