littlejsengine 1.6.0 → 1.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -34
- package/build/littlejs.d.ts +104 -92
- package/build/littlejs.esm.js +414 -342
- package/build/littlejs.esm.min.js +1 -1
- package/build/littlejs.js +365 -296
- package/build/littlejs.min.js +1 -1
- package/build/littlejs.release.js +359 -291
- package/examples/breakout/game.js +5 -0
- package/examples/breakout/gameObjects.js +41 -48
- package/examples/breakout/index.html +3 -3
- package/examples/breakoutTutorial/README.md +514 -0
- package/examples/breakoutTutorial/game.js +181 -0
- package/examples/breakoutTutorial/images/1.png +0 -0
- package/examples/breakoutTutorial/images/10.png +0 -0
- package/examples/breakoutTutorial/images/11.png +0 -0
- package/examples/breakoutTutorial/images/2.png +0 -0
- package/examples/breakoutTutorial/images/3.png +0 -0
- package/examples/breakoutTutorial/images/4.png +0 -0
- package/examples/breakoutTutorial/images/5.png +0 -0
- package/examples/breakoutTutorial/images/6.png +0 -0
- package/examples/breakoutTutorial/images/7.png +0 -0
- package/examples/breakoutTutorial/images/8.png +0 -0
- package/examples/breakoutTutorial/images/9.png +0 -0
- package/examples/breakoutTutorial/index.html +10 -0
- package/examples/empty/game.js +10 -0
- package/examples/favicon.png +0 -0
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +1 -1
- package/examples/platformer/gameLevel.js +1 -1
- package/examples/platformer/gamePlayer.js +1 -1
- package/examples/platformer/index.html +6 -6
- package/examples/puzzle/game.js +1 -1
- package/examples/puzzle/index.html +2 -2
- package/examples/starter/build.bat +3 -2
- package/examples/starter/game.js +9 -9
- package/examples/starter/index.html +13 -13
- package/examples/stress/index.html +1 -1
- package/examples/typescript/game.js +89 -89
- package/examples/typescript/game.ts +10 -10
- package/examples/typescript/index.html +1 -1
- package/package.json +4 -4
- package/src/engine.js +29 -31
- package/src/engineAudio.js +53 -29
- package/src/engineBuild.bat +3 -1
- package/src/engineDebug.js +25 -24
- package/src/engineDraw.js +43 -39
- package/src/engineExport.js +49 -46
- package/src/engineInput.js +83 -74
- package/src/engineMedals.js +31 -8
- package/src/engineObject.js +25 -25
- package/src/engineParticles.js +3 -6
- package/src/engineRelease.js +19 -19
- package/src/engineSettings.js +4 -4
- package/src/engineTileLayer.js +18 -14
- package/src/engineUtilities.js +43 -34
- package/src/engineWebGL.js +8 -8
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
|
|
@@ -292,6 +305,9 @@ if (isTouchDevice)
|
|
|
292
305
|
return true;
|
|
293
306
|
}
|
|
294
307
|
|
|
308
|
+
// try to create touch game pad
|
|
309
|
+
touchGamepadEnable && touchGamepadCreate();
|
|
310
|
+
|
|
295
311
|
return ontouchstart(e);
|
|
296
312
|
}
|
|
297
313
|
}
|
|
@@ -305,76 +321,69 @@ let touchGamepadTimer = new Timer, touchGamepadButtons, touchGamepadStick;
|
|
|
305
321
|
// create the touch gamepad, called automatically by the engine
|
|
306
322
|
function touchGamepadCreate()
|
|
307
323
|
{
|
|
308
|
-
if (!touchGamepadEnable || !isTouchDevice)
|
|
309
|
-
return;
|
|
310
|
-
|
|
311
324
|
// touch input internal variables
|
|
312
325
|
touchGamepadButtons = [];
|
|
313
326
|
touchGamepadStick = vec2();
|
|
314
327
|
|
|
315
|
-
|
|
316
|
-
ontouchstart = (e)=>
|
|
328
|
+
let touchHandler = ontouchstart;
|
|
329
|
+
ontouchstart = ontouchmove = ontouchend = (e)=>
|
|
317
330
|
{
|
|
318
|
-
//
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
331
|
+
// clear touch gamepad input
|
|
332
|
+
touchGamepadStick = vec2();
|
|
333
|
+
touchGamepadButtons = [];
|
|
334
|
+
|
|
335
|
+
const touching = e.touches.length;
|
|
336
|
+
if (touching)
|
|
322
337
|
{
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
touchGamepadButtons = [];
|
|
326
|
-
|
|
327
|
-
const touching = e.touches.length;
|
|
328
|
-
if (touching)
|
|
338
|
+
touchGamepadTimer.set();
|
|
339
|
+
if (paused)
|
|
329
340
|
{
|
|
330
|
-
//
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
if (paused)
|
|
335
|
-
{
|
|
336
|
-
// touch anywhere to press start when paused
|
|
337
|
-
touchGamepadButtons[9] = 1;
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
341
|
+
// touch anywhere to press start when paused
|
|
342
|
+
touchGamepadButtons[9] = 1;
|
|
343
|
+
return;
|
|
340
344
|
}
|
|
345
|
+
}
|
|
341
346
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
347
|
+
// get center of left and right sides
|
|
348
|
+
const stickCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
349
|
+
const buttonCenter = mainCanvasSize.subtract(vec2(touchGamepadSize, touchGamepadSize));
|
|
350
|
+
const startCenter = mainCanvasSize.scale(.5);
|
|
346
351
|
|
|
347
|
-
|
|
348
|
-
|
|
352
|
+
// check each touch point
|
|
353
|
+
for (const touch of e.touches)
|
|
354
|
+
{
|
|
355
|
+
const touchPos = mouseToScreen(vec2(touch.clientX, touch.clientY));
|
|
356
|
+
if (touchPos.distance(stickCenter) < touchGamepadSize)
|
|
349
357
|
{
|
|
350
|
-
|
|
351
|
-
if (
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
if (touchGamepadAnalog)
|
|
355
|
-
touchGamepadStick = touchPos.subtract(stickCenter).scale(2/touchGamepadSize).clampLength();
|
|
356
|
-
else
|
|
357
|
-
{
|
|
358
|
-
// 8 way dpad
|
|
359
|
-
const angle = touchPos.subtract(stickCenter).angle();
|
|
360
|
-
touchGamepadStick.setAngle((angle * 4 / PI + 8.5 | 0) * PI / 4);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
else if (touchPos.distance(buttonCenter) < touchGamepadSize)
|
|
358
|
+
// virtual analog stick
|
|
359
|
+
if (touchGamepadAnalog)
|
|
360
|
+
touchGamepadStick = touchPos.subtract(stickCenter).scale(2/touchGamepadSize).clampLength();
|
|
361
|
+
else
|
|
364
362
|
{
|
|
365
|
-
//
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
}
|
|
369
|
-
else if (touchPos.distance(startCenter) < touchGamepadSize)
|
|
370
|
-
{
|
|
371
|
-
// virtual start button in center
|
|
372
|
-
touchGamepadButtons[9] = 1;
|
|
363
|
+
// 8 way dpad
|
|
364
|
+
const angle = touchPos.subtract(stickCenter).angle();
|
|
365
|
+
touchGamepadStick.setAngle((angle * 4 / PI + 8.5 | 0) * PI / 4);
|
|
373
366
|
}
|
|
374
367
|
}
|
|
368
|
+
else if (touchPos.distance(buttonCenter) < touchGamepadSize)
|
|
369
|
+
{
|
|
370
|
+
// virtual face buttons
|
|
371
|
+
const button = touchPos.subtract(buttonCenter).direction();
|
|
372
|
+
touchGamepadButtons[button] = 1;
|
|
373
|
+
}
|
|
374
|
+
else if (touchPos.distance(startCenter) < touchGamepadSize)
|
|
375
|
+
{
|
|
376
|
+
// virtual start button in center
|
|
377
|
+
touchGamepadButtons[9] = 1;
|
|
378
|
+
}
|
|
375
379
|
}
|
|
376
380
|
|
|
377
|
-
|
|
381
|
+
// call default touch handler and set to using gamepad
|
|
382
|
+
touchHandler(e);
|
|
383
|
+
isUsingGamepad = 1;
|
|
384
|
+
|
|
385
|
+
// must return true so the document will get focus
|
|
386
|
+
return true;
|
|
378
387
|
}
|
|
379
388
|
}
|
|
380
389
|
|
|
@@ -400,7 +409,7 @@ function touchGamepadRender()
|
|
|
400
409
|
overlayContext.beginPath();
|
|
401
410
|
|
|
402
411
|
const leftCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
403
|
-
if (touchGamepadAnalog)
|
|
412
|
+
if (touchGamepadAnalog) // draw circle shaped gamepad
|
|
404
413
|
{
|
|
405
414
|
overlayContext.arc(leftCenter.x, leftCenter.y, touchGamepadSize/2, 0, 9);
|
|
406
415
|
overlayContext.fill();
|
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);
|
|
@@ -112,6 +112,7 @@ class EngineObject
|
|
|
112
112
|
this.velocity.y += gravity * this.gravityScale;
|
|
113
113
|
this.pos.x += this.velocity.x *= this.damping;
|
|
114
114
|
this.pos.y += this.velocity.y *= this.damping;
|
|
115
|
+
this.angle += this.angleVelocity *= this.angleDamping;
|
|
115
116
|
|
|
116
117
|
// physics sanity checks
|
|
117
118
|
ASSERT(this.angleDamping >= 0 && this.angleDamping <= 1);
|
|
@@ -168,6 +169,7 @@ class EngineObject
|
|
|
168
169
|
const smallStepUp = (oldPos.y - o.pos.y)*2 > sizeBoth.y + gravity; // prefer to push up if small delta
|
|
169
170
|
const isBlockedX = abs(oldPos.y - o.pos.y)*2 < sizeBoth.y;
|
|
170
171
|
const isBlockedY = abs(oldPos.x - o.pos.x)*2 < sizeBoth.x;
|
|
172
|
+
const elasticity = max(this.elasticity, o.elasticity);
|
|
171
173
|
|
|
172
174
|
if (smallStepUp | isBlockedY | !isBlockedX) // resolve y collision
|
|
173
175
|
{
|
|
@@ -180,7 +182,7 @@ class EngineObject
|
|
|
180
182
|
this.groundObject = o;
|
|
181
183
|
|
|
182
184
|
// bounce if other object is fixed or grounded
|
|
183
|
-
this.velocity.y *= -
|
|
185
|
+
this.velocity.y *= -elasticity;
|
|
184
186
|
}
|
|
185
187
|
else if (o.mass)
|
|
186
188
|
{
|
|
@@ -194,7 +196,6 @@ class EngineObject
|
|
|
194
196
|
+ this.velocity.y * 2 * this.mass / (this.mass + o.mass);
|
|
195
197
|
|
|
196
198
|
// lerp betwen elastic or inelastic based on elasticity
|
|
197
|
-
const elasticity = max(this.elasticity, o.elasticity);
|
|
198
199
|
this.velocity.y = lerp(elasticity, inelastic, elastic0);
|
|
199
200
|
o.velocity.y = lerp(elasticity, inelastic, elastic1);
|
|
200
201
|
}
|
|
@@ -215,12 +216,11 @@ class EngineObject
|
|
|
215
216
|
+ this.velocity.x * 2 * this.mass / (this.mass + o.mass);
|
|
216
217
|
|
|
217
218
|
// lerp betwen elastic or inelastic based on elasticity
|
|
218
|
-
const elasticity = max(this.elasticity, o.elasticity);
|
|
219
219
|
this.velocity.x = lerp(elasticity, inelastic, elastic0);
|
|
220
220
|
o.velocity.x = lerp(elasticity, inelastic, elastic1);
|
|
221
221
|
}
|
|
222
222
|
else // bounce if other object is fixed
|
|
223
|
-
this.velocity.x *= -
|
|
223
|
+
this.velocity.x *= -elasticity;
|
|
224
224
|
}
|
|
225
225
|
debugOverlay && debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f0f');
|
|
226
226
|
}
|
package/src/engineParticles.js
CHANGED
package/src/engineRelease.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
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
11
|
let godMode = 0;
|
|
12
|
+
let debugKeyCode = 0;
|
|
13
13
|
const debug = 0;
|
|
14
14
|
const debugOverlay = 0;
|
|
15
15
|
const debugPhysics = 0;
|
|
@@ -19,15 +19,15 @@ const debugGamepads = 0;
|
|
|
19
19
|
const debugMedals = 0;
|
|
20
20
|
|
|
21
21
|
// debug commands are automatically removed from the final build
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
22
|
+
function ASSERT (){}
|
|
23
|
+
function debugInit (){}
|
|
24
|
+
function debugUpdate (){}
|
|
25
|
+
function debugRender (){}
|
|
26
|
+
function debugRect (){}
|
|
27
|
+
function debugCircle (){}
|
|
28
|
+
function debugPoint (){}
|
|
29
|
+
function debugLine (){}
|
|
30
|
+
function debugAABB (){}
|
|
31
|
+
function debugText (){}
|
|
32
|
+
function debugClear (){}
|
|
33
|
+
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
|
|
@@ -139,10 +143,10 @@ class TileLayerData
|
|
|
139
143
|
|
|
140
144
|
/**
|
|
141
145
|
* Tile layer object - cached rendering system for tile layers
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
+
* - Each Tile layer is rendered to an off screen canvas
|
|
147
|
+
* - To allow dynamic modifications, layers are rendered using canvas 2d
|
|
148
|
+
* - Some devices like mobile phones are limited to 4k texture resolution
|
|
149
|
+
* - So with 16x16 tiles this limits layers to 256x256 on mobile devices
|
|
146
150
|
* @extends EngineObject
|
|
147
151
|
* @example
|
|
148
152
|
* // create tile collision and visible tile layer
|