littlejsengine 1.6.4 → 1.6.92
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/README.md +61 -41
- package/build/littlejs.d.ts +160 -165
- package/build/littlejs.esm.js +451 -367
- package/build/littlejs.esm.min.js +1 -1
- package/build/littlejs.js +408 -314
- package/build/littlejs.min.js +1 -1
- package/build/littlejs.release.js +2573 -2470
- package/examples/breakout/game.js +5 -1
- package/examples/breakout/index.html +5 -5
- package/examples/breakoutTutorial/README.md +6 -6
- package/examples/breakoutTutorial/game.js +3 -0
- package/examples/breakoutTutorial/index.html +3 -3
- package/examples/electron/build.js +105 -0
- package/examples/electron/game.js +4 -2
- package/examples/electron/index.html +13 -2
- package/examples/electron/package.json +5 -3
- package/examples/empty/game.js +3 -1
- package/examples/empty/index.html +1 -1
- package/examples/favicon.png +0 -0
- package/examples/js13k/build.bat +2 -0
- package/examples/js13k/build.js +110 -0
- package/examples/js13k/game.js +109 -0
- package/examples/js13k/index.html +18 -0
- package/examples/js13k/tiles.png +0 -0
- package/examples/module/game.js +9 -3
- package/examples/module/index.html +2 -2
- package/examples/particles/index.html +7 -13
- package/examples/platformer/game.js +5 -2
- package/examples/platformer/gameEffects.js +1 -2
- package/examples/platformer/gamePlayer.js +2 -2
- package/examples/platformer/index.html +8 -8
- package/examples/puzzle/game.js +6 -4
- package/examples/puzzle/index.html +4 -4
- package/examples/starter/build.bat +2 -78
- package/examples/starter/build.js +109 -0
- package/examples/starter/game.js +4 -1
- package/examples/starter/index.html +15 -18
- package/examples/stress/index.html +2 -4
- package/examples/typescript/build.bat +2 -14
- package/examples/typescript/build.js +31 -0
- package/examples/typescript/game.js +94 -89
- package/examples/typescript/game.ts +9 -3
- package/examples/typescript/index.html +2 -2
- package/package.json +3 -3
- package/src/engine.js +30 -31
- package/src/engineAudio.js +44 -20
- package/src/engineBuild.bat +2 -132
- package/src/engineBuild.js +143 -0
- package/src/engineDebug.js +21 -32
- package/src/engineDraw.js +36 -28
- package/src/engineExport.js +41 -51
- package/src/engineInput.js +33 -20
- package/src/engineMedals.js +31 -8
- package/src/engineObject.js +34 -32
- package/src/engineParticles.js +9 -12
- package/src/engineRelease.js +18 -20
- package/src/engineSettings.js +4 -4
- package/src/engineTileLayer.js +49 -32
- package/src/engineUtilities.js +96 -74
- package/src/engineWebGL.js +8 -8
- package/examples/electron/build.bat +0 -52
package/src/engineInput.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LittleJS Input System
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* - Tracks key down, pressed, and released
|
|
4
|
+
* - Also tracks mouse buttons, position, and wheel
|
|
5
|
+
* - Supports multiple gamepads
|
|
6
|
+
* - Virtual gamepad for touch devices with touchGamepadSize
|
|
7
7
|
* @namespace Input
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -14,25 +14,28 @@
|
|
|
14
14
|
* @param {Number} [device=0]
|
|
15
15
|
* @return {Boolean}
|
|
16
16
|
* @memberof Input */
|
|
17
|
-
|
|
17
|
+
function keyIsDown(key, device=0)
|
|
18
|
+
{ return inputData[device] && inputData[device][key] & 1; }
|
|
18
19
|
|
|
19
20
|
/** Returns true if device key was pressed this frame
|
|
20
21
|
* @param {Number} key
|
|
21
22
|
* @param {Number} [device=0]
|
|
22
23
|
* @return {Boolean}
|
|
23
24
|
* @memberof Input */
|
|
24
|
-
|
|
25
|
+
function keyWasPressed(key, device=0)
|
|
26
|
+
{ return inputData[device] && inputData[device][key] & 2 ? 1 : 0; }
|
|
25
27
|
|
|
26
28
|
/** Returns true if device key was released this frame
|
|
27
29
|
* @param {Number} key
|
|
28
30
|
* @param {Number} [device=0]
|
|
29
31
|
* @return {Boolean}
|
|
30
32
|
* @memberof Input */
|
|
31
|
-
|
|
33
|
+
function keyWasReleased(key, device=0)
|
|
34
|
+
{ return inputData[device] && inputData[device][key] & 4 ? 1 : 0; }
|
|
32
35
|
|
|
33
36
|
/** Clears all input
|
|
34
37
|
* @memberof Input */
|
|
35
|
-
|
|
38
|
+
function clearInput() { inputData = [[]]; }
|
|
36
39
|
|
|
37
40
|
/** Returns true if mouse button is down
|
|
38
41
|
* @function
|
|
@@ -85,28 +88,32 @@ let preventDefaultInput = 0;
|
|
|
85
88
|
* @param {Number} [gamepad=0]
|
|
86
89
|
* @return {Boolean}
|
|
87
90
|
* @memberof Input */
|
|
88
|
-
|
|
91
|
+
function gamepadIsDown(button, gamepad=0)
|
|
92
|
+
{ return keyIsDown(button, gamepad+1); }
|
|
89
93
|
|
|
90
94
|
/** Returns true if gamepad button was pressed
|
|
91
95
|
* @param {Number} button
|
|
92
96
|
* @param {Number} [gamepad=0]
|
|
93
97
|
* @return {Boolean}
|
|
94
98
|
* @memberof Input */
|
|
95
|
-
|
|
99
|
+
function gamepadWasPressed(button, gamepad=0)
|
|
100
|
+
{ return keyWasPressed(button, gamepad+1); }
|
|
96
101
|
|
|
97
102
|
/** Returns true if gamepad button was released
|
|
98
103
|
* @param {Number} button
|
|
99
104
|
* @param {Number} [gamepad=0]
|
|
100
105
|
* @return {Boolean}
|
|
101
106
|
* @memberof Input */
|
|
102
|
-
|
|
107
|
+
function gamepadWasReleased(button, gamepad=0)
|
|
108
|
+
{ return keyWasReleased(button, gamepad+1); }
|
|
103
109
|
|
|
104
110
|
/** Returns gamepad stick value
|
|
105
111
|
* @param {Number} stick
|
|
106
112
|
* @param {Number} [gamepad=0]
|
|
107
113
|
* @return {Vector2}
|
|
108
114
|
* @memberof Input */
|
|
109
|
-
|
|
115
|
+
function gamepadStick(stick, gamepad=0)
|
|
116
|
+
{ return stickData[gamepad] ? stickData[gamepad][stick] || vec2() : vec2(); }
|
|
110
117
|
|
|
111
118
|
///////////////////////////////////////////////////////////////////////////////
|
|
112
119
|
// Input update called by engine
|
|
@@ -145,12 +152,18 @@ onkeydown = (e)=>
|
|
|
145
152
|
e.repeat || (inputData[isUsingGamepad = 0][remapKey(e.which)] = 3);
|
|
146
153
|
preventDefaultInput && e.preventDefault();
|
|
147
154
|
}
|
|
155
|
+
|
|
148
156
|
onkeyup = (e)=>
|
|
149
157
|
{
|
|
150
158
|
if (debug && e.target != document.body) return;
|
|
151
159
|
inputData[0][remapKey(e.which)] = 4;
|
|
152
160
|
}
|
|
153
|
-
|
|
161
|
+
|
|
162
|
+
function remapKey(c)
|
|
163
|
+
{
|
|
164
|
+
return inputWASDEmulateDirection ?
|
|
165
|
+
c==87?38 : c==83?40 : c==65?37 : c==68?39 : c : c;
|
|
166
|
+
}
|
|
154
167
|
|
|
155
168
|
///////////////////////////////////////////////////////////////////////////////
|
|
156
169
|
// Mouse event handlers
|
|
@@ -159,10 +172,10 @@ onmousedown = (e)=> {inputData[isUsingGamepad = 0][e.button] = 3; onmousemove(e)
|
|
|
159
172
|
onmouseup = (e)=> inputData[0][e.button] = inputData[0][e.button] & 2 | 4;
|
|
160
173
|
onmousemove = (e)=> mousePosScreen = mouseToScreen(e);
|
|
161
174
|
onwheel = (e)=> e.ctrlKey || (mouseWheel = sign(e.deltaY));
|
|
162
|
-
oncontextmenu = (e)=>
|
|
175
|
+
oncontextmenu = (e)=> false; // prevent right click menu
|
|
163
176
|
|
|
164
177
|
// convert a mouse or touch event position to screen space
|
|
165
|
-
|
|
178
|
+
function mouseToScreen(mousePos)
|
|
166
179
|
{
|
|
167
180
|
if (!mainCanvas)
|
|
168
181
|
return vec2(); // fix bug that can occur if user clicks before page loads
|
|
@@ -208,8 +221,7 @@ function gamepadsUpdate()
|
|
|
208
221
|
if (gamepad)
|
|
209
222
|
{
|
|
210
223
|
// read clamp dead zone of analog sticks
|
|
211
|
-
const deadZone = .3, deadZoneMax = .8
|
|
212
|
-
const applyDeadZone = (v)=>
|
|
224
|
+
const deadZone = .3, deadZoneMax = .8, applyDeadZone = (v)=>
|
|
213
225
|
v > deadZone ? percent( v, deadZone, deadZoneMax) :
|
|
214
226
|
v < -deadZone ? -percent(-v, deadZone, deadZoneMax) : 0;
|
|
215
227
|
|
|
@@ -242,11 +254,12 @@ function gamepadsUpdate()
|
|
|
242
254
|
/** Pulse the vibration hardware if it exists
|
|
243
255
|
* @param {Number} [pattern=100] - a single value in miliseconds or vibration interval array
|
|
244
256
|
* @memberof Input */
|
|
245
|
-
|
|
257
|
+
function vibrate(pattern)
|
|
258
|
+
{ vibrateEnable && navigator && navigator.vibrate && navigator.vibrate(pattern); }
|
|
246
259
|
|
|
247
260
|
/** Cancel any ongoing vibration
|
|
248
261
|
* @memberof Input */
|
|
249
|
-
|
|
262
|
+
function vibrateStop() { vibrate(0); }
|
|
250
263
|
|
|
251
264
|
///////////////////////////////////////////////////////////////////////////////
|
|
252
265
|
// Touch input
|
|
@@ -418,7 +431,7 @@ function touchGamepadRender()
|
|
|
418
431
|
const rightCenter = vec2(mainCanvasSize.x-touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
419
432
|
for (let i=4; i--;)
|
|
420
433
|
{
|
|
421
|
-
const pos = rightCenter.add((
|
|
434
|
+
const pos = rightCenter.add(vec2().setAngle(i*PI/2, touchGamepadSize/2));
|
|
422
435
|
overlayContext.fillStyle = touchGamepadButtons[i] ? '#fff' : '#000';
|
|
423
436
|
overlayContext.beginPath();
|
|
424
437
|
overlayContext.arc(pos.x, pos.y, touchGamepadSize/4, 0,9);
|
package/src/engineMedals.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LittleJS Medal System
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* - Tracks and displays medals
|
|
4
|
+
* - Saves medals to local storage
|
|
5
|
+
* - Newgrounds integration
|
|
6
6
|
* @namespace Medals
|
|
7
7
|
*/
|
|
8
8
|
|
|
@@ -19,8 +19,8 @@ let medalsDisplayQueue = [], medalsSaveName, medalsDisplayTimeLast;
|
|
|
19
19
|
///////////////////////////////////////////////////////////////////////////////
|
|
20
20
|
|
|
21
21
|
/** Initialize medals with a save name used for storage
|
|
22
|
-
*
|
|
23
|
-
*
|
|
22
|
+
* - Call this after creating all medals
|
|
23
|
+
* - Checks if medals are unlocked
|
|
24
24
|
* @param {String} saveName
|
|
25
25
|
* @memberof Medals */
|
|
26
26
|
function medalsInit(saveName)
|
|
@@ -290,9 +290,32 @@ class Newgrounds
|
|
|
290
290
|
CryptoJS()
|
|
291
291
|
{
|
|
292
292
|
///////////////////////////////////////////////////////////////////////////////
|
|
293
|
-
// Crypto-JS - https://github.com/brix/crypto-js
|
|
294
|
-
//
|
|
295
|
-
|
|
293
|
+
// Crypto-JS - https://github.com/brix/crypto-js - MIT License
|
|
294
|
+
//
|
|
295
|
+
// [The MIT License (MIT)](http://opensource.org/licenses/MIT)
|
|
296
|
+
//
|
|
297
|
+
// Copyright (c) 2009-2013 Jeff Mott
|
|
298
|
+
// Copyright (c) 2013-2016 Evan Vosberg
|
|
299
|
+
//
|
|
300
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
301
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
302
|
+
// in the Software without restriction, including without limitation the rights
|
|
303
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
304
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
305
|
+
// furnished to do so, subject to the following conditions:
|
|
306
|
+
//
|
|
307
|
+
// The above copyright notice and this permission notice shall be included in
|
|
308
|
+
// all copies or substantial portions of the Software.
|
|
309
|
+
//
|
|
310
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
311
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
312
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
313
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
314
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
315
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
316
|
+
// THE SOFTWARE.
|
|
296
317
|
return eval(Function("[M='GBMGXz^oVYPPKKbB`agTXU|LxPc_ZBcMrZvCr~wyGfWrwk@ATqlqeTp^N?p{we}jIpEnB_sEr`l?YDkDhWhprc|Er|XETG?pTl`e}dIc[_N~}fzRycIfpW{HTolvoPB_FMe_eH~BTMx]yyOhv?biWPCGc]kABencBhgERHGf{OL`Dj`c^sh@canhy[secghiyotcdOWgO{tJIE^JtdGQRNSCrwKYciZOa]Y@tcRATYKzv|sXpboHcbCBf`}SKeXPFM|RiJsSNaIb]QPc[D]Jy_O^XkOVTZep`ONmntLL`Qz~UupHBX_Ia~WX]yTRJIxG`ioZ{fefLJFhdyYoyLPvqgH?b`[TMnTwwfzDXhfM?rKs^aFr|nyBdPmVHTtAjXoYUloEziWDCw_suyYT~lSMksI~ZNCS[Bex~j]Vz?kx`gdYSEMCsHpjbyxQvw|XxX_^nQYue{sBzVWQKYndtYQMWRef{bOHSfQhiNdtR{o?cUAHQAABThwHPT}F{VvFmgN`E@FiFYS`UJmpQNM`X|tPKHlccT}z}k{sACHL?Rt@MkWplxO`ASgh?hBsuuP|xD~LSH~KBlRs]t|l|_tQAroDRqWS^SEr[sYdPB}TAROtW{mIkE|dWOuLgLmJrucGLpebrAFKWjikTUzS|j}M}szasKOmrjy[?hpwnEfX[jGpLt@^v_eNwSQHNwtOtDgWD{rk|UgASs@mziIXrsHN_|hZuxXlPJOsA^^?QY^yGoCBx{ekLuZzRqQZdsNSx@ezDAn{XNj@fRXIwrDX?{ZQHwTEfu@GhxDOykqts|n{jOeZ@c`dvTY?e^]ATvWpb?SVyg]GC?SlzteilZJAL]mlhLjYZazY__qcVFYvt@|bIQnSno@OXyt]OulzkWqH`rYFWrwGs`v|~XeTsIssLrbmHZCYHiJrX}eEzSssH}]l]IhPQhPoQ}rCXLyhFIT[clhzYOvyHqigxmjz`phKUU^TPf[GRAIhNqSOdayFP@FmKmuIzMOeoqdpxyCOwCthcLq?n`L`tLIBboNn~uXeFcPE{C~mC`h]jUUUQe^`UqvzCutYCgct|SBrAeiYQW?X~KzCz}guXbsUw?pLsg@hDArw?KeJD[BN?GD@wgFWCiHq@Ypp_QKFixEKWqRp]oJFuVIEvjDcTFu~Zz]a{IcXhWuIdMQjJ]lwmGQ|]g~c]Hl]pl`Pd^?loIcsoNir_kikBYyg?NarXZEGYspt_vLBIoj}LI[uBFvm}tbqvC|xyR~a{kob|HlctZslTGtPDhBKsNsoZPuH`U`Fqg{gKnGSHVLJ^O`zmNgMn~{rsQuoymw^JY?iUBvw_~mMr|GrPHTERS[MiNpY[Mm{ggHpzRaJaoFomtdaQ_?xuTRm}@KjU~RtPsAdxa|uHmy}n^i||FVL[eQAPrWfLm^ndczgF~Nk~aplQvTUpHvnTya]kOenZlLAQIm{lPl@CCTchvCF[fI{^zPkeYZTiamoEcKmBMfZhk_j_~Fjp|wPVZlkh_nHu]@tP|hS@^G^PdsQ~f[RqgTDqezxNFcaO}HZhb|MMiNSYSAnQWCDJukT~e|OTgc}sf[cnr?fyzTa|EwEtRG|I~|IO}O]S|rp]CQ}}DWhSjC_|z|oY|FYl@WkCOoPuWuqr{fJu?Brs^_EBI[@_OCKs}?]O`jnDiXBvaIWhhMAQDNb{U`bqVR}oqVAvR@AZHEBY@depD]OLh`kf^UsHhzKT}CS}HQKy}Q~AeMydXPQztWSSzDnghULQgMAmbWIZ|lWWeEXrE^EeNoZApooEmrXe{NAnoDf`m}UNlRdqQ@jOc~HLOMWs]IDqJHYoMziEedGBPOxOb?[X`KxkFRg@`mgFYnP{hSaxwZfBQqTm}_?RSEaQga]w[vxc]hMne}VfSlqUeMo_iqmd`ilnJXnhdj^EEFifvZyxYFRf^VaqBhLyrGlk~qowqzHOBlOwtx?i{m~`n^G?Yxzxux}b{LSlx]dS~thO^lYE}bzKmUEzwW^{rPGhbEov[Plv??xtyKJshbG`KuO?hjBdS@Ru}iGpvFXJRrvOlrKN?`I_n_tplk}kgwSXuKylXbRQ]]?a|{xiT[li?k]CJpwy^o@ebyGQrPfF`aszGKp]baIx~H?ElETtFh]dz[OjGl@C?]VDhr}OE@V]wLTc[WErXacM{We`F|utKKjgllAxvsVYBZ@HcuMgLboFHVZmi}eIXAIFhS@A@FGRbjeoJWZ_NKd^oEH`qgy`q[Tq{x?LRP|GfBFFJV|fgZs`MLbpPYUdIV^]mD@FG]pYAT^A^RNCcXVrPsgk{jTrAIQPs_`mD}rOqAZA[}RETFz]WkXFTz_m{N@{W@_fPKZLT`@aIqf|L^Mb|crNqZ{BVsijzpGPEKQQZGlApDn`ruH}cvF|iXcNqK}cxe_U~HRnKV}sCYb`D~oGvwG[Ca|UaybXea~DdD~LiIbGRxJ_VGheI{ika}KC[OZJLn^IBkPrQj_EuoFwZ}DpoBRcK]Q}?EmTv~i_Tul{bky?Iit~tgS|o}JL_VYcCQdjeJ_MfaA`FgCgc[Ii|CBHwq~nbJeYTK{e`CNstKfTKPzw{jdhp|qsZyP_FcugxCFNpKitlR~vUrx^NrSVsSTaEgnxZTmKc`R|lGJeX}ccKLsQZQhsFkeFd|ckHIVTlGMg`~uPwuHRJS_CPuN_ogXe{Ba}dO_UBhuNXby|h?JlgBIqMKx^_u{molgL[W_iavNQuOq?ap]PGB`clAicnl@k~pA?MWHEZ{HuTLsCpOxxrKlBh]FyMjLdFl|nMIvTHyGAlPogqfZ?PlvlFJvYnDQd}R@uAhtJmDfe|iJqdkYr}r@mEjjIetDl_I`TELfoR|qTBu@Tic[BaXjP?dCS~MUK[HPRI}OUOwAaf|_}HZzrwXvbnNgltjTwkBE~MztTQhtRSWoQHajMoVyBBA`kdgK~h`o[J`dm~pm]tk@i`[F~F]DBlJKklrkR]SNw@{aG~Vhl`KINsQkOy?WhcqUMTGDOM_]bUjVd|Yh_KUCCgIJ|LDIGZCPls{RzbVWVLEhHvWBzKq|^N?DyJB|__aCUjoEgsARki}j@DQXS`RNU|DJ^a~d{sh_Iu{ONcUtSrGWW@cvUjefHHi}eSSGrNtO?cTPBShLqzwMVjWQQCCFB^culBjZHEK_{dO~Q`YhJYFn]jq~XSnG@[lQr]eKrjXpG~L^h~tDgEma^AUFThlaR{xyuP@[^VFwXSeUbVetufa@dX]CLyAnDV@Bs[DnpeghJw^?UIana}r_CKGDySoRudklbgio}kIDpA@McDoPK?iYcG?_zOmnWfJp}a[JLR[stXMo?_^Ng[whQlrDbrawZeSZ~SJstIObdDSfAA{MV}?gNunLOnbMv_~KFQUAjIMj^GkoGxuYtYbGDImEYiwEMyTpMxN_LSnSMdl{bg@dtAnAMvhDTBR_FxoQgANniRqxd`pWv@rFJ|mWNWmh[GMJz_Nq`BIN@KsjMPASXORcdHjf~rJfgZYe_uulzqM_KdPlMsuvU^YJuLtofPhGonVOQxCMuXliNvJIaoC?hSxcxKVVxWlNs^ENDvCtSmO~WxI[itnjs^RDvI@KqG}YekaSbTaB]ki]XM@[ZnDAP~@|BzLRgOzmjmPkRE@_sobkT|SszXK[rZN?F]Z_u}Yue^[BZgLtR}FHzWyxWEX^wXC]MJmiVbQuBzkgRcKGUhOvUc_bga|Tx`KEM`JWEgTpFYVeXLCm|mctZR@uKTDeUONPozBeIkrY`cz]]~WPGMUf`MNUGHDbxZuO{gmsKYkAGRPqjc|_FtblEOwy}dnwCHo]PJhN~JoteaJ?dmYZeB^Xd?X^pOKDbOMF@Ugg^hETLdhwlA}PL@_ur|o{VZosP?ntJ_kG][g{Zq`Tu]dzQlSWiKfnxDnk}KOzp~tdFstMobmy[oPYjyOtUzMWdjcNSUAjRuqhLS@AwB^{BFnqjCmmlk?jpn}TksS{KcKkDboXiwK]qMVjm~V`LgWhjS^nLGwfhAYrjDSBL_{cRus~{?xar_xqPlArrYFd?pHKdMEZzzjJpfC?Hv}mAuIDkyBxFpxhstTx`IO{rp}XGuQ]VtbHerlRc_LFGWK[XluFcNGUtDYMZny[M^nVKVeMllQI[xtvwQnXFlWYqxZZFp_|]^oWX[{pOMpxXxvkbyJA[DrPzwD|LW|QcV{Nw~U^dgguSpG]ClmO@j_TENIGjPWwgdVbHganhM?ema|dBaqla|WBd`poj~klxaasKxGG^xbWquAl~_lKWxUkDFagMnE{zHug{b`A~IYcQYBF_E}wiA}K@yxWHrZ{[d~|ARsYsjeNWzkMs~IOqqp[yzDE|WFrivsidTcnbHFRoW@XpAV`lv_zj?B~tPCppRjgbbDTALeFaOf?VcjnKTQMLyp{NwdylHCqmo?oelhjWuXj~}{fpuX`fra?GNkDiChYgVSh{R[BgF~eQa^WVz}ATI_CpY?g_diae]|ijH`TyNIF}|D_xpmBq_JpKih{Ba|sWzhnAoyraiDvk`h{qbBfsylBGmRH}DRPdryEsSaKS~tIaeF[s]I~xxHVrcNe@Jjxa@jlhZueLQqHh_]twVMqG_EGuwyab{nxOF?`HCle}nBZzlTQjkLmoXbXhOtBglFoMz?eqre`HiE@vNwBulglmQjj]DB@pPkPUgA^sjOAUNdSu_`oAzar?n?eMnw{{hYmslYi[TnlJD'",...']charCodeAtUinyxpf',"for(;e<10359;c[e++]=p-=128,A=A?p-A&&A:p==34&&p)for(p=1;p<128;y=f.map((n,x)=>(U=r[n]*2+1,U=Math.log(U/(h-U)),t-=a[x]*U,U/500)),t=~-h/(1+Math.exp(t))|1,i=o%h<t,o=o%h+(i?t:h-t)*(o>>17)-!i*t,f.map((n,x)=>(U=r[n]+=(i*h/2-r[n]<<13)/((C[n]+=C[n]<5)+1/20)>>13,a[x]+=y[x]*(i-t/h))),p=p*2+i)for(f='010202103203210431053105410642065206541'.split(t=0).map((n,x)=>(U=0,[...n].map((n,x)=>(U=U*997+(c[e-n]|0)|0)),h*32-1&U*997+p+!!A*129)*12+x);o<h*32;o=o*64|M.charCodeAt(d++)&63);for(C=String.fromCharCode(...c);r=/[\0-#?@\\\\~]/.exec(C);)with(C.split(r))C=join(shift());return C")([],[],1<<17,[0,0,0,0,0,0,0,0,0,0,0,0],new Uint16Array(51e6).fill(1<<15),new Uint8Array(51e6),0,0,0,0));
|
|
318
|
+
// end of Crypto-JS
|
|
319
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
297
320
|
}
|
|
298
321
|
}
|
package/src/engineObject.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*/
|
|
1
|
+
/**
|
|
2
|
+
* LittleJS Object System
|
|
3
|
+
*/
|
|
4
4
|
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* LittleJS Object Base Object Class
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
9
|
+
* - Base object class used by the engine
|
|
10
|
+
* - Automatically adds self to object list
|
|
11
|
+
* - Will be updated and rendered each frame
|
|
12
|
+
* - Renders as a sprite from a tilesheet by default
|
|
13
|
+
* - Can have color and addtive color applied
|
|
14
|
+
* - 2d Physics and collision system
|
|
15
|
+
* - Sorted by renderOrder
|
|
16
|
+
* - Objects can have children attached
|
|
17
|
+
* - Parents are updated before children, and set child transform
|
|
18
|
+
* - Call destroy() to get rid of objects
|
|
19
|
+
*
|
|
20
|
+
* The physics system used by objects is simple and fast with some caveats...
|
|
21
|
+
* - Collision uses the axis aligned size, the object's rotation angle is only for rendering
|
|
22
|
+
* - Objects are guaranteed to not intersect tile collision from physics
|
|
23
|
+
* - If an object starts or is moved inside tile collision, it will not collide with that tile
|
|
24
|
+
* - Collision for objects can be set to be solid to block other objects
|
|
25
|
+
* - Objects may get pushed into overlapping other solid objects, if so they will push away
|
|
26
|
+
* - Solid objects are more performance intensive and should be used sparingly
|
|
27
27
|
* @example
|
|
28
28
|
* // create an engine object, normally you would first extend the class with your own
|
|
29
29
|
* const pos = vec2(2,3);
|
|
@@ -78,7 +78,7 @@ class EngineObject
|
|
|
78
78
|
/** @property {Number} [renderOrder=0] - Objects are sorted by render order */
|
|
79
79
|
this.renderOrder = renderOrder;
|
|
80
80
|
/** @property {Vector2} [velocity=Vector2()] - Velocity of the object */
|
|
81
|
-
this.velocity =
|
|
81
|
+
this.velocity = vec2();
|
|
82
82
|
/** @property {Number} [angleVelocity=0] - Angular velocity of the object */
|
|
83
83
|
this.angleVelocity = 0;
|
|
84
84
|
|
|
@@ -138,15 +138,17 @@ class EngineObject
|
|
|
138
138
|
for (const o of engineObjectsCollide)
|
|
139
139
|
{
|
|
140
140
|
// non solid objects don't collide with eachother
|
|
141
|
-
if (!this.isSolid
|
|
141
|
+
if (!this.isSolid && !o.isSolid || o.destroyed || o.parent || o == this)
|
|
142
142
|
continue;
|
|
143
143
|
|
|
144
144
|
// check collision
|
|
145
145
|
if (!isOverlapping(this.pos, this.size, o.pos, o.size))
|
|
146
146
|
continue;
|
|
147
147
|
|
|
148
|
-
//
|
|
149
|
-
|
|
148
|
+
// notify objects of collision and check if should be resolved
|
|
149
|
+
const collide1 = this.collideWithObject(o);
|
|
150
|
+
const collide2 = o.collideWithObject(this);
|
|
151
|
+
if (!collide1 || !collide2)
|
|
150
152
|
continue;
|
|
151
153
|
|
|
152
154
|
if (isOverlapping(oldPos, this.size, o.pos, o.size))
|
|
@@ -171,7 +173,7 @@ class EngineObject
|
|
|
171
173
|
const isBlockedY = abs(oldPos.x - o.pos.x)*2 < sizeBoth.x;
|
|
172
174
|
const elasticity = max(this.elasticity, o.elasticity);
|
|
173
175
|
|
|
174
|
-
if (smallStepUp
|
|
176
|
+
if (smallStepUp || isBlockedY || !isBlockedX) // resolve y collision
|
|
175
177
|
{
|
|
176
178
|
// push outside object collision
|
|
177
179
|
this.pos.y = o.pos.y + (sizeBoth.y/2 + epsilon) * sign(oldPos.y - o.pos.y);
|
|
@@ -200,7 +202,7 @@ class EngineObject
|
|
|
200
202
|
o.velocity.y = lerp(elasticity, inelastic, elastic1);
|
|
201
203
|
}
|
|
202
204
|
}
|
|
203
|
-
if (!smallStepUp
|
|
205
|
+
if (!smallStepUp && isBlockedX) // resolve x collision
|
|
204
206
|
{
|
|
205
207
|
// push outside collision
|
|
206
208
|
this.pos.x = o.pos.x + (sizeBoth.x/2 + epsilon) * sign(oldPos.x - o.pos.x);
|
|
@@ -235,9 +237,9 @@ class EngineObject
|
|
|
235
237
|
if (!tileCollisionTest(oldPos, this.size, this))
|
|
236
238
|
{
|
|
237
239
|
// test which side we bounced off (or both if a corner)
|
|
238
|
-
const isBlockedY = tileCollisionTest(
|
|
239
|
-
const isBlockedX = tileCollisionTest(
|
|
240
|
-
if (isBlockedY
|
|
240
|
+
const isBlockedY = tileCollisionTest(vec2(oldPos.x, this.pos.y), this.size, this);
|
|
241
|
+
const isBlockedX = tileCollisionTest(vec2(this.pos.x, oldPos.y), this.size, this);
|
|
242
|
+
if (isBlockedY || !isBlockedX)
|
|
241
243
|
{
|
|
242
244
|
// set if landed on ground
|
|
243
245
|
this.groundObject = wasMovingDown;
|
|
@@ -300,7 +302,7 @@ class EngineObject
|
|
|
300
302
|
* @param {EngineObject} object - the object to test against
|
|
301
303
|
* @return {Boolean} - true if the collision should be resolved
|
|
302
304
|
*/
|
|
303
|
-
collideWithObject(
|
|
305
|
+
collideWithObject(object) { return 1; }
|
|
304
306
|
|
|
305
307
|
/** How long since the object was created
|
|
306
308
|
* @return {Number} */
|
|
@@ -308,7 +310,7 @@ class EngineObject
|
|
|
308
310
|
|
|
309
311
|
/** Apply acceleration to this object (adjust velocity, not affected by mass)
|
|
310
312
|
* @param {Vector2} acceleration */
|
|
311
|
-
applyAcceleration(
|
|
313
|
+
applyAcceleration(acceleration) { if (this.mass) this.velocity = this.velocity.add(acceleration); }
|
|
312
314
|
|
|
313
315
|
/** Apply force to this object (adjust velocity, affected by mass)
|
|
314
316
|
* @param {Vector2} force */
|
package/src/engineParticles.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
- Updates particle physics
|
|
5
|
-
- Fast particle rendering
|
|
6
|
-
*/
|
|
1
|
+
/**
|
|
2
|
+
* LittleJS Particle System
|
|
3
|
+
*/
|
|
7
4
|
|
|
8
5
|
'use strict';
|
|
9
6
|
|
|
@@ -88,7 +85,7 @@ class ParticleEmitter extends EngineObject
|
|
|
88
85
|
localSpace
|
|
89
86
|
)
|
|
90
87
|
{
|
|
91
|
-
super(pos,
|
|
88
|
+
super(pos, vec2(), tileIndex, tileSize, angle, undefined, renderOrder);
|
|
92
89
|
|
|
93
90
|
// emitter settings
|
|
94
91
|
/** @property {Number} - World space size of the emitter (float for circle diameter, vec2 for rect) */
|
|
@@ -155,7 +152,7 @@ class ParticleEmitter extends EngineObject
|
|
|
155
152
|
this.parent && super.update();
|
|
156
153
|
|
|
157
154
|
// update emitter
|
|
158
|
-
if (!this.emitTime
|
|
155
|
+
if (!this.emitTime || this.getAliveTime() <= this.emitTime)
|
|
159
156
|
{
|
|
160
157
|
// emit particles
|
|
161
158
|
if (this.emitRate * particleEmitRateScale)
|
|
@@ -177,7 +174,7 @@ class ParticleEmitter extends EngineObject
|
|
|
177
174
|
{
|
|
178
175
|
// spawn a particle
|
|
179
176
|
let pos = this.emitSize.x != undefined ? // check if vec2 was used for size
|
|
180
|
-
(
|
|
177
|
+
vec2(rand(-.5,.5), rand(-.5,.5))
|
|
181
178
|
.multiply(this.emitSize).rotate(this.angle) // box emitter
|
|
182
179
|
: randInCircle(this.emitSize/2); // circle emitter
|
|
183
180
|
let angle = rand(this.particleConeAngle, -this.particleConeAngle);
|
|
@@ -207,7 +204,7 @@ class ParticleEmitter extends EngineObject
|
|
|
207
204
|
// build particle settings
|
|
208
205
|
particle.colorStart = colorStart;
|
|
209
206
|
particle.colorEndDelta = colorEnd.subtract(colorStart);
|
|
210
|
-
particle.velocity = (
|
|
207
|
+
particle.velocity = vec2().setAngle(velocityAngle, speed);
|
|
211
208
|
particle.angleVelocity = angleSpeed;
|
|
212
209
|
particle.lifeTime = particleTime;
|
|
213
210
|
particle.sizeStart = sizeStart;
|
|
@@ -252,7 +249,7 @@ class Particle extends EngineObject
|
|
|
252
249
|
* @param {Number} [angle=0] - Angle to rotate the particle
|
|
253
250
|
*/
|
|
254
251
|
constructor(pos, tileIndex, tileSize, angle)
|
|
255
|
-
{ super(pos,
|
|
252
|
+
{ super(pos, vec2(), tileIndex, tileSize, angle); }
|
|
256
253
|
|
|
257
254
|
/** Render the particle, automatically called each frame, sorted by renderOrder */
|
|
258
255
|
render()
|
|
@@ -260,7 +257,7 @@ class Particle extends EngineObject
|
|
|
260
257
|
// modulate size and color
|
|
261
258
|
const p = min((time - this.spawnTime) / this.lifeTime, 1);
|
|
262
259
|
const radius = this.sizeStart + p * this.sizeEndDelta;
|
|
263
|
-
const size =
|
|
260
|
+
const size = vec2(radius);
|
|
264
261
|
const fadeRate = this.fadeRate/2;
|
|
265
262
|
const color = new Color(
|
|
266
263
|
this.colorStart.r + p * this.colorEndDelta.r,
|
package/src/engineRelease.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*/
|
|
1
|
+
/**
|
|
2
|
+
* LittleJS - Release Build
|
|
3
|
+
* MIT License - Copyright 2021 Frank Force
|
|
4
|
+
* - This file is used for release builds in place of engineDebug.js
|
|
5
|
+
* - Debug functionality is disabled to reduce size and increase performance
|
|
6
|
+
*/
|
|
8
7
|
|
|
9
8
|
'use strict';
|
|
10
9
|
|
|
11
10
|
let showWatermark = 0;
|
|
12
|
-
let godMode = 0;
|
|
13
11
|
let debugKeyCode = 0;
|
|
14
12
|
const debug = 0;
|
|
15
13
|
const debugOverlay = 0;
|
|
@@ -20,15 +18,15 @@ const debugGamepads = 0;
|
|
|
20
18
|
const debugMedals = 0;
|
|
21
19
|
|
|
22
20
|
// debug commands are automatically removed from the final build
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
21
|
+
function ASSERT (){}
|
|
22
|
+
function debugInit (){}
|
|
23
|
+
function debugUpdate (){}
|
|
24
|
+
function debugRender (){}
|
|
25
|
+
function debugRect (){}
|
|
26
|
+
function debugCircle (){}
|
|
27
|
+
function debugPoint (){}
|
|
28
|
+
function debugLine (){}
|
|
29
|
+
function debugAABB (){}
|
|
30
|
+
function debugText (){}
|
|
31
|
+
function debugClear (){}
|
|
32
|
+
function debugSaveCanvas (){}
|
package/src/engineSettings.js
CHANGED
|
@@ -36,11 +36,11 @@ let canvasMaxSize = vec2(1920, 1200);
|
|
|
36
36
|
* @memberof Settings */
|
|
37
37
|
let canvasFixedSize = vec2();
|
|
38
38
|
|
|
39
|
-
/** Disables
|
|
39
|
+
/** Disables filtering for crisper pixel art if true
|
|
40
40
|
* @type {Boolean}
|
|
41
41
|
* @default
|
|
42
42
|
* @memberof Settings */
|
|
43
|
-
let
|
|
43
|
+
let canvasPixelated = 1;
|
|
44
44
|
|
|
45
45
|
/** Default font used for text rendering
|
|
46
46
|
* @type {String}
|
|
@@ -157,8 +157,8 @@ let gamepadDirectionEmulateStick = 1;
|
|
|
157
157
|
let inputWASDEmulateDirection = 1;
|
|
158
158
|
|
|
159
159
|
/** True if touch gamepad should appear on mobile devices
|
|
160
|
-
*
|
|
161
|
-
*
|
|
160
|
+
* - Supports left analog stick, 4 face buttons and start button (button 9)
|
|
161
|
+
* - Must be set by end of gameInit to be activated
|
|
162
162
|
* @type {Boolean}
|
|
163
163
|
* @default 0
|
|
164
164
|
* @memberof Settings */
|
package/src/engineTileLayer.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LittleJS Tile Layer System
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
3
|
+
* - Caches arrays of tiles to off screen canvas for fast rendering
|
|
4
|
+
* - Unlimted numbers of layers, allocates canvases as needed
|
|
5
|
+
* - Interfaces with EngineObject for collision
|
|
6
|
+
* - Collision layer is separate from visible layers
|
|
7
|
+
* - It is recommended to have a visible layer that matches the collision
|
|
8
|
+
* - Tile layers can be drawn to using their context with canvas2d
|
|
9
|
+
* - Drawn directly to the main canvas without using WebGL
|
|
10
10
|
* @namespace TileCollision
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -37,15 +37,19 @@ function initTileCollision(size)
|
|
|
37
37
|
* @param {Vector2} pos
|
|
38
38
|
* @param {Number} [data=0]
|
|
39
39
|
* @memberof TileCollision */
|
|
40
|
-
|
|
40
|
+
function setTileCollisionData(pos, data=0)
|
|
41
|
+
{
|
|
41
42
|
pos.arrayCheck(tileCollisionSize) && (tileCollision[(pos.y|0)*tileCollisionSize.x+pos.x|0] = data);
|
|
43
|
+
}
|
|
42
44
|
|
|
43
45
|
/** Get tile collision data
|
|
44
46
|
* @param {Vector2} pos
|
|
45
47
|
* @return {Number}
|
|
46
48
|
* @memberof TileCollision */
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
function getTileCollisionData(pos)
|
|
50
|
+
{
|
|
51
|
+
return pos.arrayCheck(tileCollisionSize) ? tileCollision[(pos.y|0)*tileCollisionSize.x+pos.x|0] : 0;
|
|
52
|
+
}
|
|
49
53
|
|
|
50
54
|
/** Check if collision with another object should occur
|
|
51
55
|
* @param {Vector2} pos
|
|
@@ -63,12 +67,12 @@ function tileCollisionTest(pos, size=vec2(), object)
|
|
|
63
67
|
for (let x = minX; x < maxX; ++x)
|
|
64
68
|
{
|
|
65
69
|
const tileData = tileCollision[y*tileCollisionSize.x+x];
|
|
66
|
-
if (tileData && (!object || object.collideWithTile(tileData,
|
|
70
|
+
if (tileData && (!object || object.collideWithTile(tileData, vec2(x, y))))
|
|
67
71
|
return 1;
|
|
68
72
|
}
|
|
69
73
|
}
|
|
70
74
|
|
|
71
|
-
/** Return the center of tile if any that is hit (
|
|
75
|
+
/** Return the center of tile if any that is hit (does not return the exact intersection)
|
|
72
76
|
* @param {Vector2} posStart
|
|
73
77
|
* @param {Vector2} posEnd
|
|
74
78
|
* @param {EngineObject} [object]
|
|
@@ -77,28 +81,41 @@ function tileCollisionTest(pos, size=vec2(), object)
|
|
|
77
81
|
function tileCollisionRaycast(posStart, posEnd, object)
|
|
78
82
|
{
|
|
79
83
|
// test if a ray collides with tiles from start to end
|
|
80
|
-
// todo: a way to get the exact hit point, it must still
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
+
// todo: a way to get the exact hit point, it must still be inside the hit tile
|
|
85
|
+
const delta = posEnd.subtract(posStart);
|
|
86
|
+
const totalLength = delta.length();
|
|
87
|
+
const normalizedDelta = delta.normalize();
|
|
88
|
+
const unit = vec2(abs(1/normalizedDelta.x), abs(1/normalizedDelta.y));
|
|
89
|
+
const flooredPosStart = posStart.floor();
|
|
84
90
|
|
|
85
|
-
|
|
91
|
+
// setup iteration variables
|
|
92
|
+
let pos = flooredPosStart;
|
|
93
|
+
let xi = unit.x * (delta.x < 0 ? posStart.x - pos.x : pos.x - posStart.x + 1);
|
|
94
|
+
let yi = unit.y * (delta.y < 0 ? posStart.y - pos.y : pos.y - posStart.y + 1);
|
|
95
|
+
|
|
96
|
+
while (1)
|
|
86
97
|
{
|
|
87
|
-
|
|
88
|
-
|
|
98
|
+
// check for tile collision
|
|
99
|
+
const tileData = getTileCollisionData(pos);
|
|
100
|
+
if (tileData && (!object || object.collideWithTile(tileData, pos)))
|
|
89
101
|
{
|
|
90
|
-
debugRaycast && debugLine(posStart, posEnd, '#f00'
|
|
91
|
-
debugRaycast && debugPoint(
|
|
92
|
-
return
|
|
102
|
+
debugRaycast && debugLine(posStart, posEnd, '#f00', .02);
|
|
103
|
+
debugRaycast && debugPoint(pos.add(vec2(.5)), '#ff0');
|
|
104
|
+
return pos.add(vec2(.5));
|
|
93
105
|
}
|
|
94
106
|
|
|
95
|
-
//
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
107
|
+
// check if past the end
|
|
108
|
+
if (xi > totalLength && yi > totalLength)
|
|
109
|
+
break;
|
|
110
|
+
|
|
111
|
+
// get coordinates of the next tile to check
|
|
112
|
+
if (xi > yi)
|
|
113
|
+
pos.y += sign(delta.y), yi += unit.y;
|
|
114
|
+
else
|
|
115
|
+
pos.x += sign(delta.x), xi += unit.x;
|
|
100
116
|
}
|
|
101
|
-
|
|
117
|
+
|
|
118
|
+
debugRaycast && debugLine(posStart, posEnd, '#00f', .02);
|
|
102
119
|
}
|
|
103
120
|
|
|
104
121
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -139,10 +156,10 @@ class TileLayerData
|
|
|
139
156
|
|
|
140
157
|
/**
|
|
141
158
|
* Tile layer object - cached rendering system for tile layers
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
159
|
+
* - Each Tile layer is rendered to an off screen canvas
|
|
160
|
+
* - To allow dynamic modifications, layers are rendered using canvas 2d
|
|
161
|
+
* - Some devices like mobile phones are limited to 4k texture resolution
|
|
162
|
+
* - So with 16x16 tiles this limits layers to 256x256 on mobile devices
|
|
146
163
|
* @extends EngineObject
|
|
147
164
|
* @example
|
|
148
165
|
* // create tile collision and visible tile layer
|