littlejsengine 1.9.7 → 1.9.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/LICENSE +22 -0
- package/README.md +13 -8
- package/dist/littlejs.d.ts +64 -69
- package/dist/littlejs.esm.js +284 -347
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +280 -343
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +217 -312
- package/examples/box2d/game.js +138 -0
- package/examples/box2d/index.html +25 -0
- package/examples/box2d/scenes.js +412 -0
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +3 -3
- package/examples/breakout/index.html +1 -0
- package/examples/platformer/gameEffects.js +2 -2
- package/examples/platformer/gameLevel.js +0 -1
- package/package.json +1 -1
- package/plugins/Box2D_v2.3.1_min.wasm.js +630 -0
- package/plugins/Box2D_v2.3.1_min.wasm.wasm +0 -0
- package/plugins/box2d.js +873 -0
- package/plugins/newgrounds.js +169 -0
- package/plugins/postProcess.js +101 -0
- package/src/engine.js +44 -26
- package/src/engineAudio.js +20 -12
- package/src/engineDebug.js +68 -33
- package/src/engineDraw.js +1 -1
- package/src/engineExport.js +4 -4
- package/src/engineMedals.js +39 -171
- package/src/engineObject.js +30 -2
- package/src/engineRelease.js +5 -2
- package/src/engineSettings.js +2 -2
- package/src/engineUtilities.js +75 -2
- package/src/engineWebGL.js +1 -94
package/dist/littlejs.release.js
CHANGED
|
@@ -26,13 +26,16 @@ function debugInit (){}
|
|
|
26
26
|
function debugUpdate (){}
|
|
27
27
|
function debugRender (){}
|
|
28
28
|
function debugRect (){}
|
|
29
|
+
function debugPoly (){}
|
|
29
30
|
function debugCircle (){}
|
|
30
31
|
function debugPoint (){}
|
|
31
32
|
function debugLine (){}
|
|
32
|
-
function
|
|
33
|
+
function debugOverlap (){}
|
|
33
34
|
function debugText (){}
|
|
34
35
|
function debugClear (){}
|
|
35
|
-
function debugSaveCanvas (){}
|
|
36
|
+
function debugSaveCanvas (){}
|
|
37
|
+
function debugSaveText (){}
|
|
38
|
+
function debugSaveDataURL(){}
|
|
36
39
|
/**
|
|
37
40
|
* LittleJS Utility Classes and Functions
|
|
38
41
|
* - General purpose math library
|
|
@@ -336,7 +339,7 @@ class RandomGenerator
|
|
|
336
339
|
*/
|
|
337
340
|
function vec2(x=0, y)
|
|
338
341
|
{
|
|
339
|
-
return typeof x
|
|
342
|
+
return typeof x == 'number' ?
|
|
340
343
|
new Vector2(x, y == undefined? x : y) :
|
|
341
344
|
new Vector2(x.x, x.y);
|
|
342
345
|
}
|
|
@@ -365,13 +368,19 @@ class Vector2
|
|
|
365
368
|
* @param {Number} [y] - Y axis location */
|
|
366
369
|
constructor(x=0, y=0)
|
|
367
370
|
{
|
|
368
|
-
ASSERT(typeof x
|
|
371
|
+
ASSERT(typeof x == 'number' && typeof y == 'number');
|
|
369
372
|
/** @property {Number} - X axis location */
|
|
370
373
|
this.x = x;
|
|
371
374
|
/** @property {Number} - Y axis location */
|
|
372
375
|
this.y = y;
|
|
373
376
|
}
|
|
374
377
|
|
|
378
|
+
/** Sets values of this vector and returns self
|
|
379
|
+
* @param {Number} [x] - X axis location
|
|
380
|
+
* @param {Number} [y] - Y axis location
|
|
381
|
+
* @return {Vector2} */
|
|
382
|
+
set(x=0, y=0) { this.x=x; this.y=y; return this; }
|
|
383
|
+
|
|
375
384
|
/** Returns a new vector that is a copy of this
|
|
376
385
|
* @return {Vector2} */
|
|
377
386
|
copy() { return new Vector2(this.x, this.y); }
|
|
@@ -623,6 +632,15 @@ class Color
|
|
|
623
632
|
this.a = a;
|
|
624
633
|
}
|
|
625
634
|
|
|
635
|
+
/** Sets values of this color and returns self
|
|
636
|
+
* @param {Number} [r] - red
|
|
637
|
+
* @param {Number} [g] - green
|
|
638
|
+
* @param {Number} [b] - blue
|
|
639
|
+
* @param {Number} [a] - alpha
|
|
640
|
+
* @return {Color} */
|
|
641
|
+
set(r=1, g=1, b=1, a=1)
|
|
642
|
+
{ this.r=r; this.g=g; this.b=b; this.a=a; return this; }
|
|
643
|
+
|
|
626
644
|
/** Returns a new color that is a copy of this
|
|
627
645
|
* @return {Color} */
|
|
628
646
|
copy() { return new Color(this.r, this.g, this.b, this.a); }
|
|
@@ -784,6 +802,64 @@ class Color
|
|
|
784
802
|
}
|
|
785
803
|
}
|
|
786
804
|
|
|
805
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
806
|
+
// default colors
|
|
807
|
+
|
|
808
|
+
/** Color - White
|
|
809
|
+
* @type {Color}
|
|
810
|
+
* @memberof Utilities */
|
|
811
|
+
const WHITE = rgb();
|
|
812
|
+
|
|
813
|
+
/** Color - Black
|
|
814
|
+
* @type {Color}
|
|
815
|
+
* @memberof Utilities */
|
|
816
|
+
const BLACK = rgb(0,0,0);
|
|
817
|
+
|
|
818
|
+
/** Color - Gray
|
|
819
|
+
* @type {Color}
|
|
820
|
+
* @memberof Utilities */
|
|
821
|
+
const GRAY = rgb(.5,.5,.5);
|
|
822
|
+
|
|
823
|
+
/** Color - Red
|
|
824
|
+
* @type {Color}
|
|
825
|
+
* @memberof Utilities */
|
|
826
|
+
const RED = rgb(1,0,0);
|
|
827
|
+
|
|
828
|
+
/** Color - Orange
|
|
829
|
+
* @type {Color}
|
|
830
|
+
* @memberof Utilities */
|
|
831
|
+
const ORANGE = rgb(1,.5,0);
|
|
832
|
+
|
|
833
|
+
/** Color - Yellow
|
|
834
|
+
* @type {Color}
|
|
835
|
+
* @memberof Utilities */
|
|
836
|
+
const YELLOW = rgb(1,1,0);
|
|
837
|
+
|
|
838
|
+
/** Color - Green
|
|
839
|
+
* @type {Color}
|
|
840
|
+
* @memberof Utilities */
|
|
841
|
+
const GREEN = rgb(0,1,0);
|
|
842
|
+
|
|
843
|
+
/** Color - Cyan
|
|
844
|
+
* @type {Color}
|
|
845
|
+
* @memberof Utilities */
|
|
846
|
+
const CYAN = rgb(0,1,1);
|
|
847
|
+
|
|
848
|
+
/** Color - Blue
|
|
849
|
+
* @type {Color}
|
|
850
|
+
* @memberof Utilities */
|
|
851
|
+
const BLUE = rgb(0,0,1);
|
|
852
|
+
|
|
853
|
+
/** Color - Purple
|
|
854
|
+
* @type {Color}
|
|
855
|
+
* @memberof Utilities */
|
|
856
|
+
const PURPLE = rgb(.5,0,1);
|
|
857
|
+
|
|
858
|
+
/** Color - Magenta
|
|
859
|
+
* @type {Color}
|
|
860
|
+
* @memberof Utilities */
|
|
861
|
+
const MAGENTA = rgb(1,0,1);
|
|
862
|
+
|
|
787
863
|
///////////////////////////////////////////////////////////////////////////////
|
|
788
864
|
|
|
789
865
|
/**
|
|
@@ -864,9 +940,9 @@ let cameraScale = 32;
|
|
|
864
940
|
|
|
865
941
|
/** The max size of the canvas, centered if window is larger
|
|
866
942
|
* @type {Vector2}
|
|
867
|
-
* @default Vector2(1920,
|
|
943
|
+
* @default Vector2(1920,1080)
|
|
868
944
|
* @memberof Settings */
|
|
869
|
-
let canvasMaxSize = vec2(1920,
|
|
945
|
+
let canvasMaxSize = vec2(1920, 1080);
|
|
870
946
|
|
|
871
947
|
/** Fixed size of the canvas, if enabled canvas size never changes
|
|
872
948
|
* - you may also need to set mainCanvasSize if using screen space coords in startup
|
|
@@ -1513,7 +1589,7 @@ class EngineObject
|
|
|
1513
1589
|
if (o.mass) // push away if not fixed
|
|
1514
1590
|
o.velocity = o.velocity.subtract(velocity);
|
|
1515
1591
|
|
|
1516
|
-
debugOverlay && debugPhysics &&
|
|
1592
|
+
debugOverlay && debugPhysics && debugOverlap(this.pos, this.size, o.pos, o.size, '#f00');
|
|
1517
1593
|
continue;
|
|
1518
1594
|
}
|
|
1519
1595
|
|
|
@@ -1575,7 +1651,7 @@ class EngineObject
|
|
|
1575
1651
|
else // bounce if other object is fixed
|
|
1576
1652
|
this.velocity.x *= -elasticity;
|
|
1577
1653
|
}
|
|
1578
|
-
debugOverlay && debugPhysics &&
|
|
1654
|
+
debugOverlay && debugPhysics && debugOverlap(this.pos, this.size, o.pos, o.size, '#f0f');
|
|
1579
1655
|
}
|
|
1580
1656
|
}
|
|
1581
1657
|
if (this.collideTiles)
|
|
@@ -1636,6 +1712,22 @@ class EngineObject
|
|
|
1636
1712
|
for (const child of this.children)
|
|
1637
1713
|
child.destroy(child.parent = 0);
|
|
1638
1714
|
}
|
|
1715
|
+
|
|
1716
|
+
/** Convert from local space to world space
|
|
1717
|
+
* @param {Vector2} pos - local space point */
|
|
1718
|
+
localToWorld(pos) { return this.pos.add(pos.rotate(-this.angle)); }
|
|
1719
|
+
|
|
1720
|
+
/** Convert from world space to local space
|
|
1721
|
+
* @param {Vector2} pos - world space point */
|
|
1722
|
+
worldToLocal(pos) { return pos.subtract(this.pos).rotate(this.angle); }
|
|
1723
|
+
|
|
1724
|
+
/** Convert from local space to world space for a vector (rotation only)
|
|
1725
|
+
* @param {Vector2} vec - local space vector */
|
|
1726
|
+
localToWorldVector(vec) { return vec.rotate(this.angle); }
|
|
1727
|
+
|
|
1728
|
+
/** Convert from world space to local space for a vector (rotation only)
|
|
1729
|
+
* @param {Vector2} vec - world space vector */
|
|
1730
|
+
worldToLocalVector(vec) { return vec.rotate(-this.angle); }
|
|
1639
1731
|
|
|
1640
1732
|
/** Called to check if a tile collision should be resolved
|
|
1641
1733
|
* @param {Number} tileData - the value of the tile at the position
|
|
@@ -1722,6 +1814,18 @@ class EngineObject
|
|
|
1722
1814
|
return text;
|
|
1723
1815
|
}
|
|
1724
1816
|
}
|
|
1817
|
+
|
|
1818
|
+
/** Render debug info for this object */
|
|
1819
|
+
renderDebugInfo()
|
|
1820
|
+
{
|
|
1821
|
+
// show object info for debugging
|
|
1822
|
+
const size = vec2(max(this.size.x, .2), max(this.size.y, .2));
|
|
1823
|
+
const color1 = rgb(this.collideTiles?1:0, this.collideSolidObjects?1:0, this.isSolid?1:0, this.parent?.2:.5);
|
|
1824
|
+
const color2 = this.parent ? rgb(1,1,1,.5) : rgb(0,0,0,.8);
|
|
1825
|
+
drawRect(this.pos, size, color1, this.angle, false);
|
|
1826
|
+
drawRect(this.pos, size.scale(.8), color2, this.angle, false);
|
|
1827
|
+
this.parent && drawLine(this.pos, this.parent.pos, .1, rgb(0,0,1,.5), false);
|
|
1828
|
+
}
|
|
1725
1829
|
}
|
|
1726
1830
|
/**
|
|
1727
1831
|
* LittleJS Drawing System
|
|
@@ -2045,7 +2149,7 @@ function drawCanvas2D(pos, size, angle, mirror, drawFunction, screenSpace, conte
|
|
|
2045
2149
|
context.save();
|
|
2046
2150
|
context.translate(pos.x+.5, pos.y+.5);
|
|
2047
2151
|
context.rotate(angle);
|
|
2048
|
-
context.scale(mirror ? -size.x : size.x, size.y);
|
|
2152
|
+
context.scale(mirror ? -size.x : size.x, -size.y);
|
|
2049
2153
|
drawFunction(context);
|
|
2050
2154
|
context.restore();
|
|
2051
2155
|
}
|
|
@@ -2841,7 +2945,17 @@ class Sound
|
|
|
2841
2945
|
|
|
2842
2946
|
// play the sound
|
|
2843
2947
|
const playbackRate = pitch + pitch * this.randomness*randomnessScale*rand(-1,1);
|
|
2844
|
-
|
|
2948
|
+
this.gainNode = audioContext.createGain();
|
|
2949
|
+
return this.source = playSamples(this.sampleChannels, volume, playbackRate, pan, loop, this.sampleRate, this.gainNode);
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2952
|
+
/** Set the sound volume
|
|
2953
|
+
* @param {Number} [volume] - How much to scale volume by
|
|
2954
|
+
*/
|
|
2955
|
+
setVolume(volume=1)
|
|
2956
|
+
{
|
|
2957
|
+
if (this.gainNode)
|
|
2958
|
+
this.gainNode.gain.value = volume;
|
|
2845
2959
|
}
|
|
2846
2960
|
|
|
2847
2961
|
/** Stop the last instance of this sound that was played */
|
|
@@ -3029,15 +3143,16 @@ function getNoteFrequency(semitoneOffset, rootFrequency=220)
|
|
|
3029
3143
|
let audioSuspended = false;
|
|
3030
3144
|
|
|
3031
3145
|
/** Play cached audio samples with given settings
|
|
3032
|
-
* @param {Array}
|
|
3033
|
-
* @param {Number}
|
|
3034
|
-
* @param {Number}
|
|
3035
|
-
* @param {Number}
|
|
3036
|
-
* @param {Boolean}
|
|
3037
|
-
* @param {Number}
|
|
3146
|
+
* @param {Array} sampleChannels - Array of arrays of samples to play (for stereo playback)
|
|
3147
|
+
* @param {Number} [volume] - How much to scale volume by
|
|
3148
|
+
* @param {Number} [rate] - The playback rate to use
|
|
3149
|
+
* @param {Number} [pan] - How much to apply stereo panning
|
|
3150
|
+
* @param {Boolean} [loop] - True if the sound should loop when it reaches the end
|
|
3151
|
+
* @param {Number} [sampleRate=44100] - Sample rate for the sound
|
|
3152
|
+
* @param {GainNode} [gainNode] - Optional gain node for volume control while playing
|
|
3038
3153
|
* @return {AudioBufferSourceNode} - The audio node of the sound played
|
|
3039
3154
|
* @memberof Audio */
|
|
3040
|
-
function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sampleRate=zzfxR)
|
|
3155
|
+
function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sampleRate=zzfxR, gainNode)
|
|
3041
3156
|
{
|
|
3042
3157
|
if (!soundEnable || headlessMode) return;
|
|
3043
3158
|
|
|
@@ -3063,11 +3178,8 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
3063
3178
|
source.playbackRate.value = rate;
|
|
3064
3179
|
source.loop = loop;
|
|
3065
3180
|
|
|
3066
|
-
// set master gain volume
|
|
3067
|
-
setSoundVolume(soundVolume);
|
|
3068
|
-
|
|
3069
3181
|
// create and connect gain node
|
|
3070
|
-
|
|
3182
|
+
gainNode = gainNode || audioContext.createGain();
|
|
3071
3183
|
gainNode.gain.value = volume;
|
|
3072
3184
|
gainNode.connect(audioGainNode);
|
|
3073
3185
|
|
|
@@ -4048,9 +4160,9 @@ class Particle extends EngineObject
|
|
|
4048
4160
|
|
|
4049
4161
|
|
|
4050
4162
|
/** List of all medals
|
|
4051
|
-
* @type {
|
|
4163
|
+
* @type {Object}
|
|
4052
4164
|
* @memberof Medals */
|
|
4053
|
-
const medals =
|
|
4165
|
+
const medals = {};
|
|
4054
4166
|
|
|
4055
4167
|
// Engine internal variables not exposed to documentation
|
|
4056
4168
|
let medalsDisplayQueue = [], medalsSaveName, medalsDisplayTimeLast;
|
|
@@ -4066,9 +4178,45 @@ function medalsInit(saveName)
|
|
|
4066
4178
|
{
|
|
4067
4179
|
// check if medals are unlocked
|
|
4068
4180
|
medalsSaveName = saveName;
|
|
4069
|
-
|
|
4181
|
+
if (!debugMedals)
|
|
4182
|
+
medalsForEach(medal=> medal.unlocked = (localStorage[medal.storageKey()] | 0));
|
|
4183
|
+
|
|
4184
|
+
// engine automatically renders medals
|
|
4185
|
+
addPluginRender(function()
|
|
4186
|
+
{
|
|
4187
|
+
if (!medalsDisplayQueue.length)
|
|
4188
|
+
return;
|
|
4189
|
+
|
|
4190
|
+
// update first medal in queue
|
|
4191
|
+
const medal = medalsDisplayQueue[0];
|
|
4192
|
+
const time = timeReal - medalsDisplayTimeLast;
|
|
4193
|
+
if (!medalsDisplayTimeLast)
|
|
4194
|
+
medalsDisplayTimeLast = timeReal;
|
|
4195
|
+
else if (time > medalDisplayTime)
|
|
4196
|
+
{
|
|
4197
|
+
medalsDisplayTimeLast = 0;
|
|
4198
|
+
medalsDisplayQueue.shift();
|
|
4199
|
+
}
|
|
4200
|
+
else
|
|
4201
|
+
{
|
|
4202
|
+
// slide on/off medals
|
|
4203
|
+
const slideOffTime = medalDisplayTime - medalDisplaySlideTime;
|
|
4204
|
+
const hidePercent =
|
|
4205
|
+
time < medalDisplaySlideTime ? 1 - time / medalDisplaySlideTime :
|
|
4206
|
+
time > slideOffTime ? (time - slideOffTime) / medalDisplaySlideTime : 0;
|
|
4207
|
+
medal.render(hidePercent);
|
|
4208
|
+
}
|
|
4209
|
+
});
|
|
4070
4210
|
}
|
|
4071
4211
|
|
|
4212
|
+
/** Calls a function for each medal
|
|
4213
|
+
* @param {Function} callback
|
|
4214
|
+
* @memberof Medals */
|
|
4215
|
+
function medalsForEach(callback)
|
|
4216
|
+
{ Object.values(medals).forEach(medal=>callback(medal)); }
|
|
4217
|
+
|
|
4218
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
4219
|
+
|
|
4072
4220
|
/**
|
|
4073
4221
|
* Medal - Tracks an unlockable medal
|
|
4074
4222
|
* @example
|
|
@@ -4113,7 +4261,6 @@ class Medal
|
|
|
4113
4261
|
ASSERT(medalsSaveName, 'save name must be set');
|
|
4114
4262
|
localStorage[this.storageKey()] = this.unlocked = 1;
|
|
4115
4263
|
medalsDisplayQueue.push(this);
|
|
4116
|
-
newgrounds && newgrounds.unlockMedal(this.id);
|
|
4117
4264
|
}
|
|
4118
4265
|
|
|
4119
4266
|
/** Render a medal
|
|
@@ -4161,173 +4308,6 @@ class Medal
|
|
|
4161
4308
|
|
|
4162
4309
|
// Get local storage key used by the medal
|
|
4163
4310
|
storageKey() { return medalsSaveName + '_' + this.id; }
|
|
4164
|
-
}
|
|
4165
|
-
|
|
4166
|
-
// engine automatically renders medals
|
|
4167
|
-
function medalsRender()
|
|
4168
|
-
{
|
|
4169
|
-
if (!medalsDisplayQueue.length)
|
|
4170
|
-
return;
|
|
4171
|
-
|
|
4172
|
-
// update first medal in queue
|
|
4173
|
-
const medal = medalsDisplayQueue[0];
|
|
4174
|
-
const time = timeReal - medalsDisplayTimeLast;
|
|
4175
|
-
if (!medalsDisplayTimeLast)
|
|
4176
|
-
medalsDisplayTimeLast = timeReal;
|
|
4177
|
-
else if (time > medalDisplayTime)
|
|
4178
|
-
{
|
|
4179
|
-
medalsDisplayTimeLast = 0;
|
|
4180
|
-
medalsDisplayQueue.shift();
|
|
4181
|
-
}
|
|
4182
|
-
else
|
|
4183
|
-
{
|
|
4184
|
-
// slide on/off medals
|
|
4185
|
-
const slideOffTime = medalDisplayTime - medalDisplaySlideTime;
|
|
4186
|
-
const hidePercent =
|
|
4187
|
-
time < medalDisplaySlideTime ? 1 - time / medalDisplaySlideTime :
|
|
4188
|
-
time > slideOffTime ? (time - slideOffTime) / medalDisplaySlideTime : 0;
|
|
4189
|
-
medal.render(hidePercent);
|
|
4190
|
-
}
|
|
4191
|
-
}
|
|
4192
|
-
|
|
4193
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
4194
|
-
|
|
4195
|
-
// global Newgrounds object
|
|
4196
|
-
let newgrounds;
|
|
4197
|
-
|
|
4198
|
-
/** This can used to enable Newgrounds functionality
|
|
4199
|
-
* @param {Number} app_id - The newgrounds App ID
|
|
4200
|
-
* @param {String} [cipher] - The encryption Key (AES-128/Base64)
|
|
4201
|
-
* @param {Object} [cryptoJS] - An instance of CryptoJS, if there is a cipher
|
|
4202
|
-
* @memberof Medals */
|
|
4203
|
-
function newgroundsInit(app_id, cipher, cryptoJS)
|
|
4204
|
-
{ newgrounds = new Newgrounds(app_id, cipher, cryptoJS); }
|
|
4205
|
-
|
|
4206
|
-
/**
|
|
4207
|
-
* Newgrounds API wrapper object
|
|
4208
|
-
* @example
|
|
4209
|
-
* // create a newgrounds object, replace the app id with your own
|
|
4210
|
-
* const app_id = '53123:1ZuSTQ9l';
|
|
4211
|
-
* newgrounds = new Newgrounds(app_id);
|
|
4212
|
-
*/
|
|
4213
|
-
class Newgrounds
|
|
4214
|
-
{
|
|
4215
|
-
/** Create a newgrounds object
|
|
4216
|
-
* @param {Number} app_id - The newgrounds App ID
|
|
4217
|
-
* @param {String} [cipher] - The encryption Key (AES-128/Base64)
|
|
4218
|
-
* @param {Object} [cryptoJS] - An instance of CryptoJS, if there is a cipher */
|
|
4219
|
-
constructor(app_id, cipher, cryptoJS)
|
|
4220
|
-
{
|
|
4221
|
-
ASSERT(!newgrounds && app_id>0, 'there can only be one newgrounds object');
|
|
4222
|
-
ASSERT(!cipher || cryptoJS, 'must provide cryptojs if there is a cipher');
|
|
4223
|
-
|
|
4224
|
-
this.app_id = app_id;
|
|
4225
|
-
this.cipher = cipher;
|
|
4226
|
-
this.cryptoJS = cryptoJS;
|
|
4227
|
-
this.host = location ? location.hostname : '';
|
|
4228
|
-
|
|
4229
|
-
// get session id from url search params
|
|
4230
|
-
const url = new URL(location.href);
|
|
4231
|
-
this.session_id = url.searchParams.get('ngio_session_id');
|
|
4232
|
-
|
|
4233
|
-
if (!this.session_id)
|
|
4234
|
-
return; // only use newgrounds when logged in
|
|
4235
|
-
|
|
4236
|
-
// get medals
|
|
4237
|
-
const medalsResult = this.call('Medal.getList');
|
|
4238
|
-
this.medals = medalsResult ? medalsResult.result.data['medals'] : [];
|
|
4239
|
-
debugMedals && console.log(this.medals);
|
|
4240
|
-
for (const newgroundsMedal of this.medals)
|
|
4241
|
-
{
|
|
4242
|
-
const medal = medals[newgroundsMedal['id']];
|
|
4243
|
-
if (medal)
|
|
4244
|
-
{
|
|
4245
|
-
// copy newgrounds medal data
|
|
4246
|
-
medal.image = new Image;
|
|
4247
|
-
medal.image.src = newgroundsMedal['icon'];
|
|
4248
|
-
medal.name = newgroundsMedal['name'];
|
|
4249
|
-
medal.description = newgroundsMedal['description'];
|
|
4250
|
-
medal.unlocked = newgroundsMedal['unlocked'];
|
|
4251
|
-
medal.difficulty = newgroundsMedal['difficulty'];
|
|
4252
|
-
medal.value = newgroundsMedal['value'];
|
|
4253
|
-
|
|
4254
|
-
if (medal.value)
|
|
4255
|
-
medal.description = medal.description + ' (' + medal.value + ')';
|
|
4256
|
-
}
|
|
4257
|
-
}
|
|
4258
|
-
|
|
4259
|
-
// get scoreboards
|
|
4260
|
-
const scoreboardResult = this.call('ScoreBoard.getBoards');
|
|
4261
|
-
this.scoreboards = scoreboardResult ? scoreboardResult.result.data.scoreboards : [];
|
|
4262
|
-
debugMedals && console.log(this.scoreboards);
|
|
4263
|
-
|
|
4264
|
-
const keepAliveMS = 5 * 60 * 1e3;
|
|
4265
|
-
setInterval(()=>this.call('Gateway.ping', 0, true), keepAliveMS);
|
|
4266
|
-
}
|
|
4267
|
-
|
|
4268
|
-
/** Send message to unlock a medal by id
|
|
4269
|
-
* @param {Number} id - The medal id */
|
|
4270
|
-
unlockMedal(id) { return this.call('Medal.unlock', {'id':id}, true); }
|
|
4271
|
-
|
|
4272
|
-
/** Send message to post score
|
|
4273
|
-
* @param {Number} id - The scoreboard id
|
|
4274
|
-
* @param {Number} value - The score value */
|
|
4275
|
-
postScore(id, value) { return this.call('ScoreBoard.postScore', {'id':id, 'value':value}, true); }
|
|
4276
|
-
|
|
4277
|
-
/** Get scores from a scoreboard
|
|
4278
|
-
* @param {Number} id - The scoreboard id
|
|
4279
|
-
* @param {String} [user] - A user's id or name
|
|
4280
|
-
* @param {Number} [social] - If true, only social scores will be loaded
|
|
4281
|
-
* @param {Number} [skip] - Number of scores to skip before start
|
|
4282
|
-
* @param {Number} [limit] - Number of scores to include in the list
|
|
4283
|
-
* @return {Object} - The response JSON object
|
|
4284
|
-
*/
|
|
4285
|
-
getScores(id, user, social=0, skip=0, limit=10)
|
|
4286
|
-
{ return this.call('ScoreBoard.getScores', {'id':id, 'user':user, 'social':social, 'skip':skip, 'limit':limit}); }
|
|
4287
|
-
|
|
4288
|
-
/** Send message to log a view */
|
|
4289
|
-
logView() { return this.call('App.logView', {'host':this.host}, true); }
|
|
4290
|
-
|
|
4291
|
-
/** Send a message to call a component of the Newgrounds API
|
|
4292
|
-
* @param {String} component - Name of the component
|
|
4293
|
-
* @param {Object} [parameters] - Parameters to use for call
|
|
4294
|
-
* @param {Boolean} [async] - If true, don't wait for response before continuing
|
|
4295
|
-
* @return {Object} - The response JSON object
|
|
4296
|
-
*/
|
|
4297
|
-
call(component, parameters, async=false)
|
|
4298
|
-
{
|
|
4299
|
-
const call = {'component':component, 'parameters':parameters};
|
|
4300
|
-
if (this.cipher)
|
|
4301
|
-
{
|
|
4302
|
-
// encrypt using AES-128 Base64 with cryptoJS
|
|
4303
|
-
const cryptoJS = this.cryptoJS;
|
|
4304
|
-
const aesKey = cryptoJS['enc']['Base64']['parse'](this.cipher);
|
|
4305
|
-
const iv = cryptoJS['lib']['WordArray']['random'](16);
|
|
4306
|
-
const encrypted = cryptoJS['AES']['encrypt'](JSON.stringify(call), aesKey, {'iv':iv});
|
|
4307
|
-
call['secure'] = cryptoJS['enc']['Base64']['stringify'](iv.concat(encrypted['ciphertext']));
|
|
4308
|
-
call['parameters'] = 0;
|
|
4309
|
-
}
|
|
4310
|
-
|
|
4311
|
-
// build the input object
|
|
4312
|
-
const input =
|
|
4313
|
-
{
|
|
4314
|
-
'app_id': this.app_id,
|
|
4315
|
-
'session_id': this.session_id,
|
|
4316
|
-
'call': call
|
|
4317
|
-
};
|
|
4318
|
-
|
|
4319
|
-
// build post data
|
|
4320
|
-
const formData = new FormData();
|
|
4321
|
-
formData.append('input', JSON.stringify(input));
|
|
4322
|
-
|
|
4323
|
-
// send post data
|
|
4324
|
-
const xmlHttp = new XMLHttpRequest();
|
|
4325
|
-
const url = 'https://newgrounds.io/gateway_v3.php';
|
|
4326
|
-
xmlHttp.open('POST', url, !debugMedals && async);
|
|
4327
|
-
xmlHttp.send(formData);
|
|
4328
|
-
debugMedals && console.log(xmlHttp.responseText);
|
|
4329
|
-
return xmlHttp.responseText && JSON.parse(xmlHttp.responseText);
|
|
4330
|
-
}
|
|
4331
4311
|
}
|
|
4332
4312
|
/**
|
|
4333
4313
|
* LittleJS WebGL Interface
|
|
@@ -4418,7 +4398,7 @@ function glPreRender()
|
|
|
4418
4398
|
|
|
4419
4399
|
// clear and set to same size as main canvas
|
|
4420
4400
|
glContext.viewport(0, 0, glCanvas.width=mainCanvas.width, glCanvas.height=mainCanvas.height);
|
|
4421
|
-
|
|
4401
|
+
glContext.clear(gl_COLOR_BUFFER_BIT);
|
|
4422
4402
|
|
|
4423
4403
|
// set up the shader
|
|
4424
4404
|
glContext.useProgram(glShader);
|
|
@@ -4601,99 +4581,6 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdd
|
|
|
4601
4581
|
glInstanceCount++;
|
|
4602
4582
|
}
|
|
4603
4583
|
|
|
4604
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
4605
|
-
// post processing - can be enabled to pass other canvases through a final shader
|
|
4606
|
-
|
|
4607
|
-
let glPostShader, glPostTexture, glPostIncludeOverlay;
|
|
4608
|
-
|
|
4609
|
-
/** Set up a post processing shader
|
|
4610
|
-
* @param {String} shaderCode
|
|
4611
|
-
* @param {Boolean} includeOverlay
|
|
4612
|
-
* @memberof WebGL */
|
|
4613
|
-
function glInitPostProcess(shaderCode, includeOverlay=false)
|
|
4614
|
-
{
|
|
4615
|
-
ASSERT(!glPostShader, 'can only have 1 post effects shader');
|
|
4616
|
-
if (headlessMode) return;
|
|
4617
|
-
if (!shaderCode) // default shader pass through
|
|
4618
|
-
shaderCode = 'void mainImage(out vec4 c,vec2 p){c=texture(iChannel0,p/iResolution.xy);}';
|
|
4619
|
-
|
|
4620
|
-
// create the shader
|
|
4621
|
-
glPostShader = glCreateProgram(
|
|
4622
|
-
'#version 300 es\n' + // specify GLSL ES version
|
|
4623
|
-
'precision highp float;'+ // use highp for better accuracy
|
|
4624
|
-
'in vec2 p;'+ // position
|
|
4625
|
-
'void main(){'+ // shader entry point
|
|
4626
|
-
'gl_Position=vec4(p+p-1.,1,1);'+ // set position
|
|
4627
|
-
'}' // end of shader
|
|
4628
|
-
,
|
|
4629
|
-
'#version 300 es\n' + // specify GLSL ES version
|
|
4630
|
-
'precision highp float;'+ // use highp for better accuracy
|
|
4631
|
-
'uniform sampler2D iChannel0;'+ // input texture
|
|
4632
|
-
'uniform vec3 iResolution;'+ // size of output texture
|
|
4633
|
-
'uniform float iTime;'+ // time
|
|
4634
|
-
'out vec4 c;'+ // out color
|
|
4635
|
-
'\n' + shaderCode + '\n'+ // insert custom shader code
|
|
4636
|
-
'void main(){'+ // shader entry point
|
|
4637
|
-
'mainImage(c,gl_FragCoord.xy);'+ // call post process function
|
|
4638
|
-
'c.a=1.;'+ // always use full alpha
|
|
4639
|
-
'}' // end of shader
|
|
4640
|
-
);
|
|
4641
|
-
|
|
4642
|
-
// create buffer and texture
|
|
4643
|
-
glPostTexture = glCreateTexture(undefined);
|
|
4644
|
-
glPostIncludeOverlay = includeOverlay;
|
|
4645
|
-
|
|
4646
|
-
// hide the original 2d canvas
|
|
4647
|
-
mainCanvas.style.visibility = 'hidden';
|
|
4648
|
-
if (glPostIncludeOverlay)
|
|
4649
|
-
overlayCanvas.style.visibility = 'hidden';
|
|
4650
|
-
}
|
|
4651
|
-
|
|
4652
|
-
// Render the post processing shader, called automatically by the engine
|
|
4653
|
-
function glRenderPostProcess()
|
|
4654
|
-
{
|
|
4655
|
-
if (!glPostShader || headlessMode) return;
|
|
4656
|
-
|
|
4657
|
-
// prepare to render post process shader
|
|
4658
|
-
if (glEnable)
|
|
4659
|
-
{
|
|
4660
|
-
glFlush(); // clear out the buffer
|
|
4661
|
-
mainContext.drawImage(glCanvas, 0, 0); // copy to the main canvas
|
|
4662
|
-
}
|
|
4663
|
-
else
|
|
4664
|
-
{
|
|
4665
|
-
// set the viewport
|
|
4666
|
-
glContext.viewport(0, 0, glCanvas.width = mainCanvas.width, glCanvas.height = mainCanvas.height);
|
|
4667
|
-
}
|
|
4668
|
-
|
|
4669
|
-
// copy overlay canvas so it will be included in post processing
|
|
4670
|
-
glPostIncludeOverlay && mainContext.drawImage(overlayCanvas, 0, 0);
|
|
4671
|
-
|
|
4672
|
-
// setup shader program to draw one triangle
|
|
4673
|
-
glContext.useProgram(glPostShader);
|
|
4674
|
-
glContext.bindBuffer(gl_ARRAY_BUFFER, glGeometryBuffer);
|
|
4675
|
-
glContext.pixelStorei(gl_UNPACK_FLIP_Y_WEBGL, 1);
|
|
4676
|
-
glContext.disable(gl_BLEND);
|
|
4677
|
-
|
|
4678
|
-
// set textures, pass in the 2d canvas and gl canvas in separate texture channels
|
|
4679
|
-
glContext.activeTexture(gl_TEXTURE0);
|
|
4680
|
-
glContext.bindTexture(gl_TEXTURE_2D, glPostTexture);
|
|
4681
|
-
glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, mainCanvas);
|
|
4682
|
-
|
|
4683
|
-
// set vertex position attribute
|
|
4684
|
-
const vertexByteStride = 8;
|
|
4685
|
-
const pLocation = glContext.getAttribLocation(glPostShader, 'p');
|
|
4686
|
-
glContext.enableVertexAttribArray(pLocation);
|
|
4687
|
-
glContext.vertexAttribPointer(pLocation, 2, gl_FLOAT, false, vertexByteStride, 0);
|
|
4688
|
-
|
|
4689
|
-
// set uniforms and draw
|
|
4690
|
-
const uniformLocation = (name)=>glContext.getUniformLocation(glPostShader, name);
|
|
4691
|
-
glContext.uniform1i(uniformLocation('iChannel0'), 0);
|
|
4692
|
-
glContext.uniform1f(uniformLocation('iTime'), time);
|
|
4693
|
-
glContext.uniform3f(uniformLocation('iResolution'), mainCanvas.width, mainCanvas.height, 1);
|
|
4694
|
-
glContext.drawArrays(gl_TRIANGLE_STRIP, 0, 4);
|
|
4695
|
-
}
|
|
4696
|
-
|
|
4697
4584
|
///////////////////////////////////////////////////////////////////////////////
|
|
4698
4585
|
// store gl constants as integers so their name doesn't use space in minifed
|
|
4699
4586
|
const
|
|
@@ -4758,7 +4645,7 @@ const engineName = 'LittleJS';
|
|
|
4758
4645
|
* @type {String}
|
|
4759
4646
|
* @default
|
|
4760
4647
|
* @memberof Engine */
|
|
4761
|
-
const engineVersion = '1.9.
|
|
4648
|
+
const engineVersion = '1.9.8';
|
|
4762
4649
|
|
|
4763
4650
|
/** Frames per second to update
|
|
4764
4651
|
* @type {Number}
|
|
@@ -4812,6 +4699,22 @@ function setPaused(isPaused) { paused = isPaused; }
|
|
|
4812
4699
|
let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
|
|
4813
4700
|
|
|
4814
4701
|
///////////////////////////////////////////////////////////////////////////////
|
|
4702
|
+
// plugin hooks
|
|
4703
|
+
|
|
4704
|
+
const pluginUpdateList = [], pluginRenderList = [];
|
|
4705
|
+
|
|
4706
|
+
/** Add a new update function for a plugin
|
|
4707
|
+
* @param {Function} updateFunction
|
|
4708
|
+
* @memberof Engine */
|
|
4709
|
+
function addPluginUpdate(updateFunction) { pluginUpdateList.push(updateFunction); }
|
|
4710
|
+
|
|
4711
|
+
/** Add a new render function for a plugin
|
|
4712
|
+
* @param {Function} renderFunction
|
|
4713
|
+
* @memberof Engine */
|
|
4714
|
+
function addPluginRender(renderFunction) { pluginRenderList.push(renderFunction); }
|
|
4715
|
+
|
|
4716
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
4717
|
+
// Main engine functions
|
|
4815
4718
|
|
|
4816
4719
|
/** Startup LittleJS engine with your callback functions
|
|
4817
4720
|
* @param {Function} gameInit - Called once after the engine starts up, setup the game
|
|
@@ -4887,6 +4790,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4887
4790
|
// update game and objects
|
|
4888
4791
|
inputUpdate();
|
|
4889
4792
|
gameUpdate();
|
|
4793
|
+
pluginUpdateList.forEach(f=>f());
|
|
4890
4794
|
engineObjectsUpdate();
|
|
4891
4795
|
|
|
4892
4796
|
// do post update
|
|
@@ -4908,8 +4812,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4908
4812
|
for (const o of engineObjects)
|
|
4909
4813
|
o.destroyed || o.render();
|
|
4910
4814
|
gameRenderPost();
|
|
4911
|
-
|
|
4912
|
-
medalsRender();
|
|
4815
|
+
pluginRenderList.forEach(f=>f());
|
|
4913
4816
|
touchGamepadRender();
|
|
4914
4817
|
debugRender();
|
|
4915
4818
|
glCopyToContext(mainContext);
|
|
@@ -5199,21 +5102,23 @@ function drawEngineSplashScreen(t)
|
|
|
5199
5102
|
x.setLineDash([99*p2,99]);
|
|
5200
5103
|
|
|
5201
5104
|
// cab top
|
|
5202
|
-
rect(7,
|
|
5203
|
-
rect(7,
|
|
5204
|
-
rect(25,
|
|
5205
|
-
rect(25,
|
|
5206
|
-
rect(25,
|
|
5105
|
+
rect(7,16,18,-8,color(2,2));
|
|
5106
|
+
rect(7,8,18,4,color(2,3));
|
|
5107
|
+
rect(25,8,8,8,color(2,1));
|
|
5108
|
+
rect(25,8,-18,8);
|
|
5109
|
+
rect(25,8,8,8);
|
|
5207
5110
|
|
|
5208
5111
|
// cab
|
|
5209
|
-
rect(25,
|
|
5210
|
-
rect(11,
|
|
5211
|
-
rect(11,
|
|
5212
|
-
rect(11,
|
|
5213
|
-
rect(
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
rect(
|
|
5112
|
+
rect(25,16,7,23,color());
|
|
5113
|
+
rect(11,39,14,-23,color(1,1));
|
|
5114
|
+
rect(11,16,14,18,color(1,2));
|
|
5115
|
+
rect(11,16,14,8,color(1,3));
|
|
5116
|
+
rect(25,16,-14,24);
|
|
5117
|
+
|
|
5118
|
+
// cab window
|
|
5119
|
+
rect(15,29,6,-9,color(2,2));
|
|
5120
|
+
circle(15,21,5,0,PI/2,color(2,4),1);
|
|
5121
|
+
rect(21,21,-6,9);
|
|
5217
5122
|
|
|
5218
5123
|
// little stack
|
|
5219
5124
|
rect(37,14,9,6,color(3,2));
|
|
@@ -5221,16 +5126,16 @@ function drawEngineSplashScreen(t)
|
|
|
5221
5126
|
rect(37,14,9,6);
|
|
5222
5127
|
|
|
5223
5128
|
// big stack
|
|
5224
|
-
rect(50,20,10,-8,color(0,1))
|
|
5225
|
-
rect(50,20,6.5,-8,color(0,2))
|
|
5226
|
-
rect(50,20,3.5,-8,color(0,3))
|
|
5227
|
-
rect(50,20,10,-8)
|
|
5228
|
-
circle(55,2,11.4,.5,PI-.5,color(3,3))
|
|
5229
|
-
circle(55,2,11.4,.5,PI/2,color(3,2),1)
|
|
5230
|
-
circle(55,2,11.4,.5,PI-.5)
|
|
5231
|
-
rect(45,7,20,-7,color(0,2))
|
|
5232
|
-
rect(45,-1,20,4,color(0,3))
|
|
5233
|
-
rect(45,-1,20,8)
|
|
5129
|
+
rect(50,20,10,-8,color(0,1));
|
|
5130
|
+
rect(50,20,6.5,-8,color(0,2));
|
|
5131
|
+
rect(50,20,3.5,-8,color(0,3));
|
|
5132
|
+
rect(50,20,10,-8);
|
|
5133
|
+
circle(55,2,11.4,.5,PI-.5,color(3,3));
|
|
5134
|
+
circle(55,2,11.4,.5,PI/2,color(3,2),1);
|
|
5135
|
+
circle(55,2,11.4,.5,PI-.5);
|
|
5136
|
+
rect(45,7,20,-7,color(0,2));
|
|
5137
|
+
rect(45,-1,20,4,color(0,3));
|
|
5138
|
+
rect(45,-1,20,8);
|
|
5234
5139
|
|
|
5235
5140
|
// engine
|
|
5236
5141
|
for (let i=5; i--;)
|