littlejsengine 1.17.1 → 1.17.5
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/dist/littlejs.d.ts +94 -83
- package/dist/littlejs.esm.js +302 -198
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +302 -197
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +298 -193
- package/examples/box2d/gameObjects.js +3 -3
- package/examples/electron/index.html +2 -2
- package/examples/index.html +8 -7
- package/examples/module/build.bat +7 -0
- package/examples/module/build.js +121 -0
- package/examples/platformer/game.js +1 -1
- package/examples/platformer/gameEffects.js +2 -7
- package/examples/platformer/gameLevel.js +3 -3
- package/examples/puzzle/game.js +2 -2
- package/examples/shorts/base.html +4 -1
- package/examples/shorts/box2dPool.js +2 -2
- package/examples/shorts/box2dTileLayer.js +48 -0
- package/examples/shorts/music.js +2 -2
- package/examples/shorts/musicPlayer.js +2 -2
- package/examples/starter/index.html +2 -2
- package/package.json +5 -5
- package/plugins/box2d.js +167 -63
- package/plugins/uiSystem.js +3 -3
- package/plugins/zzfxm.js +2 -2
- package/reference.md +3 -2
- package/src/engine.js +10 -9
- package/src/engineAudio.js +44 -58
- package/src/engineDebug.js +4 -4
- package/src/engineDraw.js +5 -2
- package/src/engineExport.js +0 -1
- package/src/engineInput.js +4 -4
- package/src/engineMath.js +9 -9
- package/src/engineObject.js +1 -1
- package/src/engineTileLayer.js +51 -40
- package/src/engineWebGL.js +2 -2
package/dist/littlejs.esm.js
CHANGED
|
@@ -33,7 +33,7 @@ const engineName = 'LittleJS';
|
|
|
33
33
|
* @type {string}
|
|
34
34
|
* @default
|
|
35
35
|
* @memberof Engine */
|
|
36
|
-
const engineVersion = '1.17.
|
|
36
|
+
const engineVersion = '1.17.5';
|
|
37
37
|
|
|
38
38
|
/** Frames per second to update
|
|
39
39
|
* @type {number}
|
|
@@ -88,8 +88,9 @@ function getPaused() { return paused; }
|
|
|
88
88
|
* @memberof Engine */
|
|
89
89
|
function setPaused(isPaused=true) { paused = isPaused; }
|
|
90
90
|
|
|
91
|
-
//
|
|
91
|
+
// Engine internal variables
|
|
92
92
|
let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
|
|
93
|
+
let showEngineVersion = true;
|
|
93
94
|
|
|
94
95
|
///////////////////////////////////////////////////////////////////////////////
|
|
95
96
|
// plugin hooks
|
|
@@ -153,16 +154,17 @@ function engineAddPlugin(update, render, glContextLost, glContextRestored)
|
|
|
153
154
|
* @example
|
|
154
155
|
* // Basic engine startup
|
|
155
156
|
* engineInit(
|
|
156
|
-
* ()
|
|
157
|
-
* ()
|
|
158
|
-
* ()
|
|
159
|
-
* ()
|
|
160
|
-
* ()
|
|
157
|
+
* ()=> { LOG('Game initialized!'); }, // gameInit
|
|
158
|
+
* ()=> { updateGameLogic(); }, // gameUpdate
|
|
159
|
+
* ()=> { updateUI(); }, // gameUpdatePost
|
|
160
|
+
* ()=> { drawBackground(); }, // gameRender
|
|
161
|
+
* ()=> { drawHUD(); }, // gameRenderPost
|
|
161
162
|
* ['tiles.png', 'tilesLevel.png'] // images to load
|
|
162
163
|
* );
|
|
163
164
|
* @memberof Engine */
|
|
164
165
|
async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=[], rootElement=document.body)
|
|
165
166
|
{
|
|
167
|
+
showEngineVersion && console.log(`${engineName} Engine v${engineVersion}`);
|
|
166
168
|
ASSERT(!mainContext, 'engine already initialized');
|
|
167
169
|
ASSERT(isArray(imageSources), 'pass in images as array');
|
|
168
170
|
|
|
@@ -431,7 +433,6 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
431
433
|
promises.push(new Promise(resolve =>
|
|
432
434
|
{
|
|
433
435
|
let t = 0;
|
|
434
|
-
console.log(`${engineName} Engine v${engineVersion}`);
|
|
435
436
|
updateSplash();
|
|
436
437
|
function updateSplash()
|
|
437
438
|
{
|
|
@@ -608,7 +609,7 @@ function drawEngineLogo(t)
|
|
|
608
609
|
x.fillStyle = C;
|
|
609
610
|
C ? x.fill() : x.stroke();
|
|
610
611
|
};
|
|
611
|
-
const color = (c=0, l=0)
|
|
612
|
+
const color = (c=0, l=0)=>
|
|
612
613
|
hsl([.98,.3,.57,.14][c%4],.9,[0,.3,.5,.8,.9][l]).toString();
|
|
613
614
|
const alpha = wave(1,1,t);
|
|
614
615
|
const p = percent(alpha, .1, .5);
|
|
@@ -777,7 +778,7 @@ let debugPrimitives = [], debugPhysics = false, debugRaycast = false, debugParti
|
|
|
777
778
|
/** Asserts if the expression is false, does nothing in release builds
|
|
778
779
|
* Halts execution if the assert fails and throws an error
|
|
779
780
|
* @param {boolean} assert
|
|
780
|
-
* @param {...Object}
|
|
781
|
+
* @param {...Object} output - error message output
|
|
781
782
|
* @memberof Debug */
|
|
782
783
|
function ASSERT(assert, ...output)
|
|
783
784
|
{
|
|
@@ -787,7 +788,7 @@ function ASSERT(assert, ...output)
|
|
|
787
788
|
}
|
|
788
789
|
|
|
789
790
|
/** Log to console if debug is enabled, does nothing in release builds
|
|
790
|
-
* @param {...Object}
|
|
791
|
+
* @param {...Object} output - message output
|
|
791
792
|
* @memberof Debug */
|
|
792
793
|
function LOG(...output) { console.log(...output); }
|
|
793
794
|
|
|
@@ -1434,8 +1435,8 @@ function debugProtectConstant(obj)
|
|
|
1434
1435
|
props.forEach(prop =>
|
|
1435
1436
|
{
|
|
1436
1437
|
Object.defineProperty(obj, prop, {
|
|
1437
|
-
get: ()
|
|
1438
|
-
set: (value)
|
|
1438
|
+
get: ()=> values[prop],
|
|
1439
|
+
set: (value)=>
|
|
1439
1440
|
{
|
|
1440
1441
|
ASSERT(false, `Cannot modify engine constant. Attempted to set constant (${obj}) property '${prop}' to '${value}'.`);
|
|
1441
1442
|
},
|
|
@@ -1463,25 +1464,25 @@ function debugProtectConstant(obj)
|
|
|
1463
1464
|
const PI = Math.PI;
|
|
1464
1465
|
|
|
1465
1466
|
/** Returns absolute value of value passed in
|
|
1466
|
-
* @param {number}
|
|
1467
|
+
* @param {number} x
|
|
1467
1468
|
* @return {number}
|
|
1468
1469
|
* @memberof Math */
|
|
1469
1470
|
const abs = Math.abs;
|
|
1470
1471
|
|
|
1471
1472
|
/** Returns floored value of value passed in
|
|
1472
|
-
* @param {number}
|
|
1473
|
+
* @param {number} x
|
|
1473
1474
|
* @return {number}
|
|
1474
1475
|
* @memberof Math */
|
|
1475
1476
|
const floor = Math.floor;
|
|
1476
1477
|
|
|
1477
1478
|
/** Returns ceiled value of value passed in
|
|
1478
|
-
* @param {number}
|
|
1479
|
+
* @param {number} x
|
|
1479
1480
|
* @return {number}
|
|
1480
1481
|
* @memberof Math */
|
|
1481
1482
|
const ceil = Math.ceil;
|
|
1482
1483
|
|
|
1483
1484
|
/** Returns rounded value passed in
|
|
1484
|
-
* @param {number}
|
|
1485
|
+
* @param {number} x
|
|
1485
1486
|
* @return {number}
|
|
1486
1487
|
* @memberof Math */
|
|
1487
1488
|
const round = Math.round;
|
|
@@ -1499,7 +1500,7 @@ const min = Math.min;
|
|
|
1499
1500
|
const max = Math.max;
|
|
1500
1501
|
|
|
1501
1502
|
/** Returns the sign of value passed in
|
|
1502
|
-
* @param {number}
|
|
1503
|
+
* @param {number} x
|
|
1503
1504
|
* @return {number}
|
|
1504
1505
|
* @memberof Math */
|
|
1505
1506
|
const sign = Math.sign;
|
|
@@ -1511,25 +1512,25 @@ const sign = Math.sign;
|
|
|
1511
1512
|
const hypot = Math.hypot;
|
|
1512
1513
|
|
|
1513
1514
|
/** Returns log2 of value passed in
|
|
1514
|
-
* @param {number}
|
|
1515
|
+
* @param {number} x
|
|
1515
1516
|
* @return {number}
|
|
1516
1517
|
* @memberof Math */
|
|
1517
1518
|
const log2 = Math.log2;
|
|
1518
1519
|
|
|
1519
1520
|
/** Returns sin of value passed in
|
|
1520
|
-
* @param {number}
|
|
1521
|
+
* @param {number} x
|
|
1521
1522
|
* @return {number}
|
|
1522
1523
|
* @memberof Math */
|
|
1523
1524
|
const sin = Math.sin;
|
|
1524
1525
|
|
|
1525
1526
|
/** Returns cos of value passed in
|
|
1526
|
-
* @param {number}
|
|
1527
|
+
* @param {number} x
|
|
1527
1528
|
* @return {number}
|
|
1528
1529
|
* @memberof Math */
|
|
1529
1530
|
const cos = Math.cos;
|
|
1530
1531
|
|
|
1531
1532
|
/** Returns tan of value passed in
|
|
1532
|
-
* @param {number}
|
|
1533
|
+
* @param {number} x
|
|
1533
1534
|
* @return {number}
|
|
1534
1535
|
* @memberof Math */
|
|
1535
1536
|
const tan = Math.tan;
|
|
@@ -3601,7 +3602,7 @@ class EngineObject
|
|
|
3601
3602
|
if (this.collideTiles)
|
|
3602
3603
|
{
|
|
3603
3604
|
// check collision against tiles
|
|
3604
|
-
const hitLayer = tileCollisionTest(this.pos, this.size, this)
|
|
3605
|
+
const hitLayer = tileCollisionTest(this.pos, this.size, this);
|
|
3605
3606
|
if (hitLayer)
|
|
3606
3607
|
{
|
|
3607
3608
|
// if already was stuck in collision, don't do anything
|
|
@@ -4105,7 +4106,7 @@ function drawTile(pos, size=vec2(1), tileInfo, color=WHITE,
|
|
|
4105
4106
|
ASSERT(!additiveColor || isColor(additiveColor), 'additiveColor must be a color');
|
|
4106
4107
|
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
4107
4108
|
|
|
4108
|
-
const textureInfo = tileInfo
|
|
4109
|
+
const textureInfo = tileInfo?.textureInfo;
|
|
4109
4110
|
const bleed = tileInfo?.bleed ?? 0;
|
|
4110
4111
|
if (useWebGL && glEnable)
|
|
4111
4112
|
{
|
|
@@ -4411,9 +4412,12 @@ function drawEllipse(pos, size=vec2(1), color=WHITE, angle=0, lineWidth=0, lineC
|
|
|
4411
4412
|
ASSERT(isColor(color) && isColor(lineColor), 'color is invalid');
|
|
4412
4413
|
ASSERT(isNumber(angle), 'angle must be a number');
|
|
4413
4414
|
ASSERT(isNumber(lineWidth), 'lineWidth must be a number');
|
|
4414
|
-
ASSERT(lineWidth >= 0
|
|
4415
|
+
ASSERT(lineWidth >= 0, 'lineWidth must be a positive value or 0');
|
|
4415
4416
|
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
4416
4417
|
|
|
4418
|
+
// clamp line width to prevent artifacts
|
|
4419
|
+
lineWidth = clamp(lineWidth, 0, Math.min(size.x, size.y));
|
|
4420
|
+
|
|
4417
4421
|
if (useWebGL && glEnable)
|
|
4418
4422
|
{
|
|
4419
4423
|
// draw as a regular polygon
|
|
@@ -5379,9 +5383,9 @@ function inputInit()
|
|
|
5379
5383
|
function touchInputInit()
|
|
5380
5384
|
{
|
|
5381
5385
|
// add non passive touch event listeners
|
|
5382
|
-
document.addEventListener('touchstart', (e)
|
|
5383
|
-
document.addEventListener('touchmove', (e)
|
|
5384
|
-
document.addEventListener('touchend', (e)
|
|
5386
|
+
document.addEventListener('touchstart', (e)=> handleTouch(e), { passive: false });
|
|
5387
|
+
document.addEventListener('touchmove', (e)=> handleTouch(e), { passive: false });
|
|
5388
|
+
document.addEventListener('touchend', (e)=> handleTouch(e), { passive: false });
|
|
5385
5389
|
|
|
5386
5390
|
// handle all touch events the same way
|
|
5387
5391
|
let wasTouching;
|
|
@@ -5587,7 +5591,7 @@ function inputUpdate()
|
|
|
5587
5591
|
// poll gamepads
|
|
5588
5592
|
const maxGamepads = 8;
|
|
5589
5593
|
const gamepads = navigator.getGamepads();
|
|
5590
|
-
const gamepadCount = min(maxGamepads, gamepads.length)
|
|
5594
|
+
const gamepadCount = min(maxGamepads, gamepads.length);
|
|
5591
5595
|
for (let i=0; i<gamepadCount; ++i)
|
|
5592
5596
|
{
|
|
5593
5597
|
// get or create gamepad data
|
|
@@ -5792,29 +5796,46 @@ function audioInit()
|
|
|
5792
5796
|
///////////////////////////////////////////////////////////////////////////////
|
|
5793
5797
|
|
|
5794
5798
|
/**
|
|
5795
|
-
* Sound Object - Stores a sound for later
|
|
5799
|
+
* Sound Object - Stores a sound for later
|
|
5800
|
+
* - this can be used to load and play wave, mp3, and ogg files
|
|
5801
|
+
* - it can also create sounds using the ZzFX sound generator
|
|
5802
|
+
* - can attenuate and apply stereo panning to sounds
|
|
5803
|
+
* - sound instance control with pause/resume capability
|
|
5796
5804
|
*
|
|
5797
5805
|
* <a href=https://killedbyapixel.github.io/ZzFX/>Create sounds using the ZzFX Sound Designer.</a>
|
|
5798
5806
|
* @memberof Audio
|
|
5799
5807
|
* @example
|
|
5800
|
-
* //
|
|
5808
|
+
* // load an audio asset file
|
|
5809
|
+
* const sound_example = new Sound('sound.mp3');
|
|
5810
|
+
*
|
|
5811
|
+
* // create a zzfx sound
|
|
5801
5812
|
* const sound_example = new Sound([.5,.5]);
|
|
5802
5813
|
*
|
|
5803
|
-
* // play
|
|
5814
|
+
* // play a sound
|
|
5804
5815
|
* sound_example.play();
|
|
5805
5816
|
*/
|
|
5806
5817
|
class Sound
|
|
5807
5818
|
{
|
|
5808
|
-
/**
|
|
5809
|
-
*
|
|
5819
|
+
/**
|
|
5820
|
+
* @callback SoundLoadCallback - Function called when sound is loaded
|
|
5821
|
+
* @param {Sound} sound
|
|
5822
|
+
* @memberof Audio
|
|
5823
|
+
*/
|
|
5824
|
+
|
|
5825
|
+
/** Create a sound object and cache the audio for later use
|
|
5826
|
+
* @param {string|Array} [asset] - Filename of audio file or zzfx array
|
|
5827
|
+
* @param {number} [randomness] - How much to randomize frequency each time sound plays, for zzfx sounds the zzfx default is used if undefined
|
|
5810
5828
|
* @param {number} [range=soundDefaultRange] - World space max range of sound
|
|
5811
5829
|
* @param {number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering
|
|
5830
|
+
* @param {SoundLoadCallback} [onloadCallback] - callback function to call when sound is loaded
|
|
5812
5831
|
*/
|
|
5813
|
-
constructor(
|
|
5832
|
+
constructor(asset, randomness, range=soundDefaultRange, taper=soundDefaultTaper, onloadCallback)
|
|
5814
5833
|
{
|
|
5815
5834
|
if (!soundEnable || headlessMode) return;
|
|
5816
5835
|
|
|
5817
|
-
ASSERT(!
|
|
5836
|
+
ASSERT(!asset || isArray(asset) || isString(asset), 'asset must be a file name or zzfx array');
|
|
5837
|
+
ASSERT(randomness === undefined || isNumber(randomness), 'randomness must be a number');
|
|
5838
|
+
ASSERT(randomness === undefined || randomness >= 0 && randomness <=1, 'randomness must be between 0 and 1');
|
|
5818
5839
|
ASSERT(isNumber(range), 'range must be a number');
|
|
5819
5840
|
ASSERT(isNumber(taper), 'taper must be a number');
|
|
5820
5841
|
|
|
@@ -5823,23 +5844,35 @@ class Sound
|
|
|
5823
5844
|
/** @property {number} - At what percentage of range should it start tapering */
|
|
5824
5845
|
this.taper = taper;
|
|
5825
5846
|
/** @property {number} - How much to randomize frequency each time sound plays */
|
|
5826
|
-
this.randomness = 0;
|
|
5847
|
+
this.randomness = randomness ?? 0;
|
|
5827
5848
|
/** @property {number} - Sample rate for this sound */
|
|
5828
5849
|
this.sampleRate = audioDefaultSampleRate;
|
|
5829
5850
|
/** @property {number} - Percentage of this sound currently loaded */
|
|
5830
5851
|
this.loadedPercent = 0;
|
|
5852
|
+
/** @property {SoundLoadCallback} - function to call when sound is loaded */
|
|
5853
|
+
this.onloadCallback = onloadCallback;
|
|
5831
5854
|
|
|
5832
|
-
|
|
5833
|
-
if (zzfxSound)
|
|
5855
|
+
if (Array.isArray(asset))
|
|
5834
5856
|
{
|
|
5857
|
+
// generate zzfx sound
|
|
5858
|
+
const zzfxSound = asset;
|
|
5859
|
+
|
|
5835
5860
|
// remove randomness so it can be applied on playback
|
|
5836
|
-
const
|
|
5861
|
+
const defaultRandomness = randomness ?? .05;
|
|
5862
|
+
const randomnessIndex = 1;
|
|
5837
5863
|
this.randomness = zzfxSound[randomnessIndex] ?? defaultRandomness;
|
|
5838
5864
|
zzfxSound[randomnessIndex] = 0;
|
|
5839
5865
|
|
|
5840
5866
|
// generate the zzfx samples
|
|
5841
5867
|
this.sampleChannels = [zzfxG(...zzfxSound)];
|
|
5842
5868
|
this.loadedPercent = 1;
|
|
5869
|
+
onloadCallback?.(this);
|
|
5870
|
+
}
|
|
5871
|
+
else if (typeof asset === 'string')
|
|
5872
|
+
{
|
|
5873
|
+
// load the audio file
|
|
5874
|
+
const filename = asset;
|
|
5875
|
+
this.loadSound(filename);
|
|
5843
5876
|
}
|
|
5844
5877
|
}
|
|
5845
5878
|
|
|
@@ -5891,7 +5924,7 @@ class Sound
|
|
|
5891
5924
|
* @param {number} [volume] - Volume to play the music at
|
|
5892
5925
|
* @param {boolean} [loop] - Should the music loop?
|
|
5893
5926
|
* @param {boolean} [paused] - Should the music start paused
|
|
5894
|
-
* @return {SoundInstance} - The
|
|
5927
|
+
* @return {SoundInstance} - The sound instance
|
|
5895
5928
|
*/
|
|
5896
5929
|
playMusic(volume=1, loop=true, paused=false)
|
|
5897
5930
|
{ return this.play(undefined, volume, 1, 0, loop, paused); }
|
|
@@ -5901,7 +5934,7 @@ class Sound
|
|
|
5901
5934
|
* @param {number} [semitoneOffset=0] - How many semitones to offset pitch
|
|
5902
5935
|
* @param {Vector2} [pos] - World space position to play the sound if any
|
|
5903
5936
|
* @param {number} [volume=1] - How much to scale volume by
|
|
5904
|
-
* @return {SoundInstance} - The
|
|
5937
|
+
* @return {SoundInstance} - The sound instance
|
|
5905
5938
|
*/
|
|
5906
5939
|
playNote(semitoneOffset=0, pos, volume)
|
|
5907
5940
|
{
|
|
@@ -5914,57 +5947,14 @@ class Sound
|
|
|
5914
5947
|
* @return {number} - How long the sound is in seconds (undefined if loading)
|
|
5915
5948
|
*/
|
|
5916
5949
|
getDuration()
|
|
5917
|
-
{ return this.sampleChannels?.[0]
|
|
5950
|
+
{ return this.sampleChannels?.[0]?.length / this.sampleRate || 0; }
|
|
5918
5951
|
|
|
5919
5952
|
/** Check if sound is loaded, for sounds fetched from a url
|
|
5920
5953
|
* @return {boolean} - True if sound is loaded and ready to play
|
|
5921
5954
|
*/
|
|
5922
5955
|
isLoaded() { return this.loadedPercent === 1; }
|
|
5923
|
-
}
|
|
5924
|
-
|
|
5925
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
5926
|
-
|
|
5927
|
-
/**
|
|
5928
|
-
* Sound Wave Object - Loads and stores an audio file for later use
|
|
5929
|
-
* - this can be used to load and play wave, mp3, and ogg files
|
|
5930
|
-
* @extends Sound
|
|
5931
|
-
* @memberof Audio
|
|
5932
|
-
* @example
|
|
5933
|
-
* // load an audio asset file
|
|
5934
|
-
* const sound_example = new SoundWave('sound.mp3');
|
|
5935
|
-
*
|
|
5936
|
-
* // play the sound
|
|
5937
|
-
* sound_example.play();
|
|
5938
|
-
*/
|
|
5939
|
-
class SoundWave extends Sound
|
|
5940
|
-
{
|
|
5941
|
-
/**
|
|
5942
|
-
* @callback SoundLoadCallback - Function called when sound is loaded
|
|
5943
|
-
* @param {SoundWave} sound
|
|
5944
|
-
* @memberof Audio
|
|
5945
|
-
*/
|
|
5946
5956
|
|
|
5947
|
-
/**
|
|
5948
|
-
* @param {string} filename - Filename of audio file to load
|
|
5949
|
-
* @param {number} [randomness] - How much to randomize frequency each time sound plays
|
|
5950
|
-
* @param {number} [range=soundDefaultRange] - World space max range of sound
|
|
5951
|
-
* @param {number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering
|
|
5952
|
-
* @param {SoundLoadCallback} [onloadCallback] - callback function to call when sound is loaded
|
|
5953
|
-
*/
|
|
5954
|
-
constructor(filename, randomness=0, range, taper, onloadCallback)
|
|
5955
|
-
{
|
|
5956
|
-
super(undefined, range, taper);
|
|
5957
|
-
if (!soundEnable || headlessMode) return;
|
|
5958
|
-
ASSERT(!filename || isString(filename), 'filename must be a string');
|
|
5959
|
-
ASSERT(isNumber(randomness), 'randomness must be a number');
|
|
5960
|
-
|
|
5961
|
-
/** @property {SoundLoadCallback} - callback function to call when sound is loaded */
|
|
5962
|
-
this.onloadCallback = onloadCallback;
|
|
5963
|
-
this.randomness = randomness;
|
|
5964
|
-
filename && this.loadSound(filename);
|
|
5965
|
-
}
|
|
5966
|
-
|
|
5967
|
-
/** Loads a sound from a URL and decodes it into sample data. Must be used with await!
|
|
5957
|
+
/** Loads a sound from a URL and decodes it into sample data.
|
|
5968
5958
|
* @param {string} filename
|
|
5969
5959
|
* @return {Promise<void>} */
|
|
5970
5960
|
async loadSound(filename)
|
|
@@ -6619,17 +6609,17 @@ class TileLayerData
|
|
|
6619
6609
|
class CanvasLayer extends EngineObject
|
|
6620
6610
|
{
|
|
6621
6611
|
/** Create a canvas layer object
|
|
6622
|
-
* @param {Vector2} [
|
|
6612
|
+
* @param {Vector2} [pos] - World space position of the layer
|
|
6623
6613
|
* @param {Vector2} [size] - World space size of the layer
|
|
6624
6614
|
* @param {number} [angle] - Angle the layer is rotated by
|
|
6625
6615
|
* @param {number} [renderOrder] - Objects sorted by renderOrder
|
|
6626
6616
|
* @param {Vector2} [canvasSize] - Default size of canvas, can be changed later
|
|
6627
6617
|
* @param {boolean} [useWebGL] - Should this layer use WebGL for rendering
|
|
6628
6618
|
*/
|
|
6629
|
-
constructor(
|
|
6619
|
+
constructor(pos, size, angle=0, renderOrder=0, canvasSize=vec2(512), useWebGL=true)
|
|
6630
6620
|
{
|
|
6631
6621
|
ASSERT(isVector2(canvasSize), 'canvasSize must be a Vector2');
|
|
6632
|
-
super(
|
|
6622
|
+
super(pos, size, undefined, angle, WHITE, renderOrder);
|
|
6633
6623
|
|
|
6634
6624
|
/** @property {HTMLCanvasElement} - The canvas used by this layer */
|
|
6635
6625
|
this.canvas = headlessMode ? undefined : new OffscreenCanvas(canvasSize.x, canvasSize.y);
|
|
@@ -6733,16 +6723,16 @@ class CanvasLayer extends EngineObject
|
|
|
6733
6723
|
class TileLayer extends CanvasLayer
|
|
6734
6724
|
{
|
|
6735
6725
|
/** Create a tile layer object
|
|
6736
|
-
* @param {Vector2}
|
|
6726
|
+
* @param {Vector2} pos - World space position
|
|
6737
6727
|
* @param {Vector2} size - World space size
|
|
6738
6728
|
* @param {TileInfo} [tileInfo] - Default tile info for layer (used for size and texture)
|
|
6739
6729
|
* @param {number} [renderOrder] - Objects are sorted by renderOrder
|
|
6730
|
+
* @param {boolean} [useWebGL] - Should this layer use WebGL for rendering
|
|
6740
6731
|
*/
|
|
6741
|
-
constructor(
|
|
6732
|
+
constructor(pos, size, tileInfo=tile(), renderOrder=0, useWebGL=true)
|
|
6742
6733
|
{
|
|
6743
6734
|
const canvasSize = tileInfo ? size.multiply(tileInfo.size) : size;
|
|
6744
|
-
|
|
6745
|
-
super(position, size, 0, renderOrder, canvasSize, useWebGL);
|
|
6735
|
+
super(pos, size, 0, renderOrder, canvasSize, useWebGL);
|
|
6746
6736
|
|
|
6747
6737
|
/** @property {TileInfo} - Default tile info for layer */
|
|
6748
6738
|
this.tileInfo = undefined;
|
|
@@ -6754,15 +6744,15 @@ class TileLayer extends CanvasLayer
|
|
|
6754
6744
|
if (headlessMode)
|
|
6755
6745
|
{
|
|
6756
6746
|
// disable rendering in headless mode
|
|
6757
|
-
this.render = ()
|
|
6758
|
-
this.redraw = ()
|
|
6759
|
-
this.redrawStart = ()
|
|
6760
|
-
this.redrawEnd = ()
|
|
6761
|
-
this.drawTileData = ()
|
|
6762
|
-
this.redrawTileData = ()
|
|
6763
|
-
this.drawLayerTile = ()
|
|
6764
|
-
this.drawLayerRect = ()
|
|
6765
|
-
this.clearLayerRect = ()
|
|
6747
|
+
this.render = ()=> {};
|
|
6748
|
+
this.redraw = ()=> {};
|
|
6749
|
+
this.redrawStart = ()=> {};
|
|
6750
|
+
this.redrawEnd = ()=> {};
|
|
6751
|
+
this.drawTileData = ()=> {};
|
|
6752
|
+
this.redrawTileData = ()=> {};
|
|
6753
|
+
this.drawLayerTile = ()=> {};
|
|
6754
|
+
this.drawLayerRect = ()=> {};
|
|
6755
|
+
this.clearLayerRect = ()=> {};
|
|
6766
6756
|
return;
|
|
6767
6757
|
}
|
|
6768
6758
|
|
|
@@ -6796,6 +6786,12 @@ class TileLayer extends CanvasLayer
|
|
|
6796
6786
|
isRedraw ? this.drawTileData(layerPos) : this.redrawTileData(layerPos);
|
|
6797
6787
|
}
|
|
6798
6788
|
|
|
6789
|
+
/** Clear data at a given position in the array
|
|
6790
|
+
* @param {Vector2} layerPos - Local position in array
|
|
6791
|
+
* @param {boolean} [redraw] - Force the tile to redraw if true */
|
|
6792
|
+
clearData(layerPos, redraw=false)
|
|
6793
|
+
{ this.setData(layerPos, new TileLayerData, redraw) }
|
|
6794
|
+
|
|
6799
6795
|
/** Get data at a given position in the array
|
|
6800
6796
|
* @param {Vector2} layerPos - Local position in array
|
|
6801
6797
|
* @return {TileLayerData} */
|
|
@@ -6837,7 +6833,7 @@ class TileLayer extends CanvasLayer
|
|
|
6837
6833
|
for (let x = this.size.x; x--;)
|
|
6838
6834
|
for (let y = this.size.y; y--;)
|
|
6839
6835
|
this.drawTileData(vec2(x,y), false);
|
|
6840
|
-
this.
|
|
6836
|
+
this.isUsingWebGL && glFlush();
|
|
6841
6837
|
this.onRedraw();
|
|
6842
6838
|
this.redrawEnd();
|
|
6843
6839
|
}
|
|
@@ -6886,14 +6882,13 @@ class TileLayer extends CanvasLayer
|
|
|
6886
6882
|
if (!this.context) return;
|
|
6887
6883
|
ASSERT(drawContext === this.context);
|
|
6888
6884
|
|
|
6889
|
-
if (glEnable && this.textureInfo.glTexture)
|
|
6890
|
-
glSetRenderTarget();
|
|
6891
|
-
|
|
6892
6885
|
// set stuff back to normal
|
|
6886
|
+
if (this.isUsingWebGL)
|
|
6887
|
+
glSetRenderTarget();
|
|
6893
6888
|
[drawContext, mainCanvasSize, cameraPos, cameraScale, canvasClearColor] = this.savedRenderSettings;
|
|
6894
6889
|
}
|
|
6895
6890
|
|
|
6896
|
-
/** Draw the tile at a given position in the tile
|
|
6891
|
+
/** Draw the tile at a given position in the tile layer
|
|
6897
6892
|
* This can be used to clear out tiles when they are destroyed
|
|
6898
6893
|
* Tiles can also be redrawn if inside a redrawStart/End block
|
|
6899
6894
|
* @param {Vector2} layerPos
|
|
@@ -6917,7 +6912,7 @@ class TileLayer extends CanvasLayer
|
|
|
6917
6912
|
this.drawLayerTile(drawPos, drawSize, tileInfo, d.color, d.direction*PI/2, d.mirror);
|
|
6918
6913
|
}
|
|
6919
6914
|
|
|
6920
|
-
/** Draw the tile at a given position in the tile
|
|
6915
|
+
/** Draw the tile at a given position in the tile layer
|
|
6921
6916
|
* This can be used to clear tiles when they are destroyed
|
|
6922
6917
|
* For better performance use drawTileData inside a redrawStart/End block
|
|
6923
6918
|
* @param {Vector2} layerPos
|
|
@@ -6945,7 +6940,7 @@ class TileLayer extends CanvasLayer
|
|
|
6945
6940
|
angle=0, mirror, additiveColor)
|
|
6946
6941
|
{
|
|
6947
6942
|
const drawPos = pos.add(size.scale(.5));
|
|
6948
|
-
drawTile(drawPos, size, tileInfo, color, angle, mirror, additiveColor);
|
|
6943
|
+
drawTile(drawPos, size, tileInfo, color, angle, mirror, additiveColor, this.isUsingWebGL);
|
|
6949
6944
|
}
|
|
6950
6945
|
|
|
6951
6946
|
/** Clear a rectangle in layer space
|
|
@@ -6985,14 +6980,15 @@ class TileLayer extends CanvasLayer
|
|
|
6985
6980
|
class TileCollisionLayer extends TileLayer
|
|
6986
6981
|
{
|
|
6987
6982
|
/** Create a tile layer object
|
|
6988
|
-
* @param {Vector2}
|
|
6989
|
-
* @param {Vector2} size
|
|
6990
|
-
* @param {TileInfo} [tileInfo]
|
|
6983
|
+
* @param {Vector2} pos - World space position
|
|
6984
|
+
* @param {Vector2} size - World space size
|
|
6985
|
+
* @param {TileInfo} [tileInfo] - Tile info for layer
|
|
6991
6986
|
* @param {number} [renderOrder] - Objects are sorted by renderOrder
|
|
6987
|
+
* @param {boolean} [useWebGL] - Should this layer use WebGL for rendering
|
|
6992
6988
|
*/
|
|
6993
|
-
constructor(
|
|
6989
|
+
constructor(pos, size, tileInfo=tile(), renderOrder=0, useWebGL=true)
|
|
6994
6990
|
{
|
|
6995
|
-
super(
|
|
6991
|
+
super(pos, size.floor(), tileInfo, renderOrder, useWebGL);
|
|
6996
6992
|
|
|
6997
6993
|
/** @property {Array<number>} - The tile collision grid */
|
|
6998
6994
|
this.collisionData = [];
|
|
@@ -7028,24 +7024,29 @@ class TileCollisionLayer extends TileLayer
|
|
|
7028
7024
|
this.collisionData.fill(0);
|
|
7029
7025
|
}
|
|
7030
7026
|
|
|
7031
|
-
/** Set tile collision data for a given cell in the
|
|
7032
|
-
* @param {Vector2}
|
|
7027
|
+
/** Set tile collision data for a given cell in the layer
|
|
7028
|
+
* @param {Vector2} layerPos
|
|
7033
7029
|
* @param {number} [data] */
|
|
7034
|
-
setCollisionData(
|
|
7030
|
+
setCollisionData(layerPos, data=1)
|
|
7035
7031
|
{
|
|
7036
|
-
ASSERT(isVector2(
|
|
7037
|
-
const i = (
|
|
7038
|
-
|
|
7032
|
+
ASSERT(isVector2(layerPos), 'layerPos must be a Vector2');
|
|
7033
|
+
const i = (layerPos.y|0)*this.size.x + layerPos.x|0;
|
|
7034
|
+
layerPos.arrayCheck(this.size) && (this.collisionData[i] = data);
|
|
7039
7035
|
}
|
|
7040
7036
|
|
|
7041
|
-
/**
|
|
7042
|
-
* @param {Vector2}
|
|
7037
|
+
/** Clear tile collision data for a given cell in the layer
|
|
7038
|
+
* @param {Vector2} layerPos */
|
|
7039
|
+
clearCollisionData(layerPos)
|
|
7040
|
+
{ this.setCollisionData(layerPos, 0); }
|
|
7041
|
+
|
|
7042
|
+
/** Get tile collision data for a given cell in the layer
|
|
7043
|
+
* @param {Vector2} layerPos
|
|
7043
7044
|
* @return {number} */
|
|
7044
|
-
getCollisionData(
|
|
7045
|
+
getCollisionData(layerPos)
|
|
7045
7046
|
{
|
|
7046
|
-
ASSERT(isVector2(
|
|
7047
|
-
const i = (
|
|
7048
|
-
return
|
|
7047
|
+
ASSERT(isVector2(layerPos), 'layerPos must be a Vector2');
|
|
7048
|
+
const i = (layerPos.y|0)*this.size.x + layerPos.x|0;
|
|
7049
|
+
return layerPos.arrayCheck(this.size) ? this.collisionData[i] : 0;
|
|
7049
7050
|
}
|
|
7050
7051
|
|
|
7051
7052
|
/** Check if collision with another object should occur
|
|
@@ -7963,7 +7964,7 @@ function glPreRender(clear=true)
|
|
|
7963
7964
|
p.x, p.y, 0, 1];
|
|
7964
7965
|
|
|
7965
7966
|
// set the same transform matrix for both shaders
|
|
7966
|
-
const initUniform = (program, uniform, value)
|
|
7967
|
+
const initUniform = (program, uniform, value)=>
|
|
7967
7968
|
{
|
|
7968
7969
|
glContext.useProgram(program);
|
|
7969
7970
|
const location = glContext.getUniformLocation(program, uniform);
|
|
@@ -8357,7 +8358,7 @@ function glSetRenderTarget(texture, clear=false)
|
|
|
8357
8358
|
glContext.bindFramebuffer(glContext.FRAMEBUFFER, glFramebuffer);
|
|
8358
8359
|
glContext.framebufferTexture2D(glContext.FRAMEBUFFER,
|
|
8359
8360
|
glContext.COLOR_ATTACHMENT0, glContext.TEXTURE_2D, texture, 0);
|
|
8360
|
-
|
|
8361
|
+
glPreRender(clear);
|
|
8361
8362
|
}
|
|
8362
8363
|
else
|
|
8363
8364
|
{
|
|
@@ -8976,7 +8977,7 @@ class ZzFXMusic extends Sound
|
|
|
8976
8977
|
/** Play the music that loops by default
|
|
8977
8978
|
* @param {number} [volume] - Volume to play the music at
|
|
8978
8979
|
* @param {boolean} [loop] - Should the music loop?
|
|
8979
|
-
* @return {
|
|
8980
|
+
* @return {SoundInstance} - The sound instance
|
|
8980
8981
|
*/
|
|
8981
8982
|
playMusic(volume=1, loop=true)
|
|
8982
8983
|
{ return super.play(undefined, volume, 1, 0, loop); }
|
|
@@ -9023,7 +9024,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
|
|
|
9023
9024
|
sampleBuffer = [hasMore = notFirstBeat = outSampleOffset = 0];
|
|
9024
9025
|
|
|
9025
9026
|
// for each pattern in sequence
|
|
9026
|
-
sequence.forEach((patternIndex, sequenceIndex)
|
|
9027
|
+
sequence.forEach((patternIndex, sequenceIndex)=> {
|
|
9027
9028
|
// get pattern for current channel, use empty 1 note pattern if none found
|
|
9028
9029
|
patternChannel = patterns[patternIndex][channelIndex] || [0, 0, 0];
|
|
9029
9030
|
|
|
@@ -9116,7 +9117,7 @@ let uiDebug = 0;
|
|
|
9116
9117
|
|
|
9117
9118
|
/** Enable UI system debug drawing
|
|
9118
9119
|
* 0=off, 1=normal, 2=show invisible
|
|
9119
|
-
* @param {number|boolean}
|
|
9120
|
+
* @param {number|boolean} debugMode
|
|
9120
9121
|
* @memberof UISystem */
|
|
9121
9122
|
function uiSetDebug(debugMode)
|
|
9122
9123
|
{ uiDebug = typeof debugMode === 'boolean' ? (debugMode ? 1 : 0) : debugMode; }
|
|
@@ -10317,8 +10318,8 @@ class UIScrollbar extends UIObject
|
|
|
10317
10318
|
class UIVideo extends UIObject
|
|
10318
10319
|
{
|
|
10319
10320
|
/** Create a video player UI object
|
|
10320
|
-
* @param {Vector2}
|
|
10321
|
-
* @param {Vector2}
|
|
10321
|
+
* @param {Vector2} pos
|
|
10322
|
+
* @param {Vector2} size
|
|
10322
10323
|
* @param {string} src - Video file path or URL
|
|
10323
10324
|
* @param {boolean} [autoplay=false] - Start playing immediately?
|
|
10324
10325
|
* @param {boolean} [loop=false] - Loop the video?
|
|
@@ -10458,6 +10459,7 @@ class UIVideo extends UIObject
|
|
|
10458
10459
|
* - Contact begin and end callbacks
|
|
10459
10460
|
* - Wraps b2Vec2 type to/from Vector2
|
|
10460
10461
|
* - Raycasting and querying
|
|
10462
|
+
* - Box2dTileLayer for grid based collision
|
|
10461
10463
|
* - Every type of joint
|
|
10462
10464
|
* - Debug physics drawing
|
|
10463
10465
|
* @namespace Box2D
|
|
@@ -10507,21 +10509,24 @@ class Box2dObject extends EngineObject
|
|
|
10507
10509
|
bodyDef.set_type(bodyType);
|
|
10508
10510
|
bodyDef.set_position(box2d.vec2dTo(pos));
|
|
10509
10511
|
bodyDef.set_angle(-angle);
|
|
10512
|
+
|
|
10513
|
+
/** @property {Object} - The Box2d body */
|
|
10510
10514
|
this.body = box2d.world.CreateBody(bodyDef);
|
|
10511
|
-
|
|
10515
|
+
/** @property {Color} - Line color used for default box2d drawing */
|
|
10512
10516
|
this.lineColor = BLACK;
|
|
10513
|
-
box2d
|
|
10514
|
-
|
|
10515
|
-
// edge lists and loops for drawing
|
|
10517
|
+
/** @property {Array<Object>} - List of all edges for default box2d drawing */
|
|
10516
10518
|
this.edgeLists = [];
|
|
10519
|
+
/** @property {Array<Object>} - List of all edge loops for default box2d drawing */
|
|
10517
10520
|
this.edgeLoops = [];
|
|
10521
|
+
|
|
10522
|
+
this.body.object = this; // link body to this object
|
|
10523
|
+
box2d.objects.push(this); // keep track of all box2d objects
|
|
10518
10524
|
}
|
|
10519
10525
|
|
|
10520
10526
|
/** Destroy this object and its physics body */
|
|
10521
10527
|
destroy()
|
|
10522
10528
|
{
|
|
10523
|
-
if (this.destroyed)
|
|
10524
|
-
return;
|
|
10529
|
+
if (this.destroyed) return;
|
|
10525
10530
|
|
|
10526
10531
|
// destroy physics body, fixtures, and joints
|
|
10527
10532
|
ASSERT(this.body, 'Box2dObject has no body to destroy');
|
|
@@ -10552,11 +10557,12 @@ class Box2dObject extends EngineObject
|
|
|
10552
10557
|
}
|
|
10553
10558
|
|
|
10554
10559
|
/** Draws all this object's fixtures
|
|
10555
|
-
* @param {Color}
|
|
10556
|
-
* @param {Color}
|
|
10557
|
-
* @param {number}
|
|
10560
|
+
* @param {Color} [color]
|
|
10561
|
+
* @param {Color} [lineColor]
|
|
10562
|
+
* @param {number} [lineWidth]
|
|
10563
|
+
* @param {boolean} [useWebGL=glEnable]
|
|
10558
10564
|
* @param {CanvasRenderingContext2D} [context] */
|
|
10559
|
-
drawFixtures(color=WHITE, lineColor=BLACK, lineWidth=.1, context)
|
|
10565
|
+
drawFixtures(color=WHITE, lineColor=BLACK, lineWidth=.1, useWebGL, context)
|
|
10560
10566
|
{
|
|
10561
10567
|
// draw non-edge fixtures
|
|
10562
10568
|
this.getFixtureList().forEach((fixture)=>
|
|
@@ -10564,7 +10570,7 @@ class Box2dObject extends EngineObject
|
|
|
10564
10570
|
const shape = box2d.castObjectType(fixture.GetShape());
|
|
10565
10571
|
if (shape.GetType() !== box2d.instance.b2Shape.e_edge)
|
|
10566
10572
|
{
|
|
10567
|
-
box2d.drawFixture(fixture, this.pos, this.angle, color, lineColor, lineWidth, context);
|
|
10573
|
+
box2d.drawFixture(fixture, this.pos, this.angle, color, lineColor, lineWidth, useWebGL, context);
|
|
10568
10574
|
}
|
|
10569
10575
|
});
|
|
10570
10576
|
|
|
@@ -10790,6 +10796,14 @@ class Box2dObject extends EngineObject
|
|
|
10790
10796
|
return fixtures;
|
|
10791
10797
|
}
|
|
10792
10798
|
|
|
10799
|
+
/** Destroy a fixture from the body
|
|
10800
|
+
* @param {Object} [fixture] */
|
|
10801
|
+
destroyFixture(fixture) { this.body.DestroyFixture(fixture); }
|
|
10802
|
+
|
|
10803
|
+
/** Destroy all fixture from the body */
|
|
10804
|
+
destroyAllFixtures()
|
|
10805
|
+
{ this.getFixtureList().forEach(fixture=>this.destroyFixture(fixture)); }
|
|
10806
|
+
|
|
10793
10807
|
///////////////////////////////////////////////////////////////////////////////
|
|
10794
10808
|
// physics get functions
|
|
10795
10809
|
|
|
@@ -11022,6 +11036,136 @@ class Box2dObject extends EngineObject
|
|
|
11022
11036
|
}
|
|
11023
11037
|
}
|
|
11024
11038
|
|
|
11039
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
11040
|
+
/**
|
|
11041
|
+
* Box2D Static Object - Box2d with a static physics body
|
|
11042
|
+
* @extends Box2dObject
|
|
11043
|
+
* @memberof Box2D
|
|
11044
|
+
*/
|
|
11045
|
+
class Box2dStaticObject extends Box2dObject
|
|
11046
|
+
{
|
|
11047
|
+
/** Create a LittleJS object with Box2d physics
|
|
11048
|
+
* @param {Vector2} [pos]
|
|
11049
|
+
* @param {Vector2} [size]
|
|
11050
|
+
* @param {TileInfo} [tileInfo]
|
|
11051
|
+
* @param {number} [angle]
|
|
11052
|
+
* @param {Color} [color]
|
|
11053
|
+
* @param {number} [renderOrder] */
|
|
11054
|
+
constructor(pos, size, tileInfo, angle=0, color, renderOrder=0)
|
|
11055
|
+
{
|
|
11056
|
+
const bodyType = box2d.bodyTypeStatic;
|
|
11057
|
+
super(pos, size, tileInfo, angle, color, bodyType, renderOrder);
|
|
11058
|
+
}
|
|
11059
|
+
}
|
|
11060
|
+
|
|
11061
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
11062
|
+
/**
|
|
11063
|
+
* Box2D Kiematic Object - Box2d with a kinematic physics body
|
|
11064
|
+
* @extends Box2dObject
|
|
11065
|
+
* @memberof Box2D
|
|
11066
|
+
*/
|
|
11067
|
+
class Box2dKiematicObject extends Box2dObject
|
|
11068
|
+
{
|
|
11069
|
+
/** Create a LittleJS object with Box2d physics
|
|
11070
|
+
* @param {Vector2} [pos]
|
|
11071
|
+
* @param {Vector2} [size]
|
|
11072
|
+
* @param {TileInfo} [tileInfo]
|
|
11073
|
+
* @param {number} [angle]
|
|
11074
|
+
* @param {Color} [color]
|
|
11075
|
+
* @param {number} [renderOrder] */
|
|
11076
|
+
constructor(pos, size, tileInfo, angle=0, color, renderOrder=0)
|
|
11077
|
+
{
|
|
11078
|
+
const bodyType = box2d.bodyTypeKinematic;
|
|
11079
|
+
super(pos, size, tileInfo, angle, color, bodyType, renderOrder);
|
|
11080
|
+
}
|
|
11081
|
+
}
|
|
11082
|
+
|
|
11083
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
11084
|
+
/**
|
|
11085
|
+
* Box2d Tile Layer
|
|
11086
|
+
* - adds Box2d support to tile layers
|
|
11087
|
+
* - creates static box2d fixtures for solid tiles
|
|
11088
|
+
* @extends Box2dObject
|
|
11089
|
+
* @memberof Box2D
|
|
11090
|
+
*/
|
|
11091
|
+
class Box2dTileLayer extends Box2dStaticObject
|
|
11092
|
+
{
|
|
11093
|
+
/** Create a Box2d tile layer object
|
|
11094
|
+
* @param {TileCollisionLayer} tileLayer - Tile layer for this object */
|
|
11095
|
+
constructor(tileLayer)
|
|
11096
|
+
{
|
|
11097
|
+
ASSERT(tileLayer instanceof TileCollisionLayer, 'tileLayer must be a TileCollisionLayer');
|
|
11098
|
+
super(tileLayer.pos, tileLayer.size);
|
|
11099
|
+
|
|
11100
|
+
/** @property {TileLayer} - The tile layer */
|
|
11101
|
+
this.tileLayer = tileLayer;
|
|
11102
|
+
this.addChild(tileLayer);
|
|
11103
|
+
}
|
|
11104
|
+
|
|
11105
|
+
render()
|
|
11106
|
+
{
|
|
11107
|
+
// do not render fixtures, tile layer handles rendering
|
|
11108
|
+
}
|
|
11109
|
+
|
|
11110
|
+
/** Create box2d collision fixtures for solid tiles
|
|
11111
|
+
* @param {number} [friction]
|
|
11112
|
+
* @param {number} [restitution] */
|
|
11113
|
+
buildCollision(friction=.2, restitution=0)
|
|
11114
|
+
{
|
|
11115
|
+
// destroy all fixtures and create new ones
|
|
11116
|
+
this.destroyAllFixtures();
|
|
11117
|
+
|
|
11118
|
+
// create box2d object for this layer
|
|
11119
|
+
const size = this.tileLayer.size;
|
|
11120
|
+
this.pos = this.tileLayer.pos.copy();
|
|
11121
|
+
this.size = size.copy();
|
|
11122
|
+
|
|
11123
|
+
// track which tiles have been processed
|
|
11124
|
+
const processed = [];
|
|
11125
|
+
const getIndex = (x, y)=> x + y * size.x;
|
|
11126
|
+
const isSolidUnprocessed = (x, y)=>
|
|
11127
|
+
!processed[getIndex(x, y)] &&
|
|
11128
|
+
this.tileLayer.getCollisionData(vec2(x, y)) > 0;
|
|
11129
|
+
|
|
11130
|
+
// combine tiles into larger boxes
|
|
11131
|
+
for (let x = 0; x < size.x; ++x)
|
|
11132
|
+
for (let y = 0; y < size.y; ++y)
|
|
11133
|
+
{
|
|
11134
|
+
if (!isSolidUnprocessed(x, y)) continue;
|
|
11135
|
+
|
|
11136
|
+
// find max width by scanning right
|
|
11137
|
+
let width = 1, height = 1, canExpand = true;
|
|
11138
|
+
while (isSolidUnprocessed(x + width, y))
|
|
11139
|
+
++width;
|
|
11140
|
+
|
|
11141
|
+
// find max height by scanning up, ensuring all rows have the same width
|
|
11142
|
+
while (canExpand)
|
|
11143
|
+
{
|
|
11144
|
+
for (let checkX = 0; checkX < width; ++checkX)
|
|
11145
|
+
{
|
|
11146
|
+
if (!isSolidUnprocessed(x + checkX, y + height))
|
|
11147
|
+
{
|
|
11148
|
+
canExpand = false;
|
|
11149
|
+
break;
|
|
11150
|
+
}
|
|
11151
|
+
}
|
|
11152
|
+
if (canExpand)
|
|
11153
|
+
++height;
|
|
11154
|
+
}
|
|
11155
|
+
|
|
11156
|
+
// mark all tiles in this rectangle as processed
|
|
11157
|
+
for (let rectX = width; rectX--;)
|
|
11158
|
+
for (let rectY = height; rectY--;)
|
|
11159
|
+
processed[getIndex(x + rectX, y + rectY)] = true;
|
|
11160
|
+
|
|
11161
|
+
// create a single fixture for the entire rectangle
|
|
11162
|
+
const shapeSize = vec2(width, height);
|
|
11163
|
+
const offset = vec2(x + width/2, y + height/2);
|
|
11164
|
+
this.addBox(shapeSize, offset, 0, 0, friction, restitution);
|
|
11165
|
+
}
|
|
11166
|
+
}
|
|
11167
|
+
}
|
|
11168
|
+
|
|
11025
11169
|
///////////////////////////////////////////////////////////////////////////////
|
|
11026
11170
|
/**
|
|
11027
11171
|
* Box2D Raycast Result
|
|
@@ -11063,6 +11207,7 @@ class Box2dJoint
|
|
|
11063
11207
|
* @param {Object} jointDef */
|
|
11064
11208
|
constructor(jointDef)
|
|
11065
11209
|
{
|
|
11210
|
+
/** @property {Object} - The Box2d joint */
|
|
11066
11211
|
this.box2dJoint = box2d.castObjectType(box2d.world.CreateJoint(jointDef));
|
|
11067
11212
|
}
|
|
11068
11213
|
|
|
@@ -11409,7 +11554,7 @@ class Box2dGearJoint extends Box2dJoint
|
|
|
11409
11554
|
* @param {Box2dObject} objectB
|
|
11410
11555
|
* @param {Box2dJoint} joint1
|
|
11411
11556
|
* @param {Box2dJoint} joint2
|
|
11412
|
-
* @param {
|
|
11557
|
+
* @param {number} [ratio] */
|
|
11413
11558
|
constructor(objectA, objectB, joint1, joint2, ratio=1)
|
|
11414
11559
|
{
|
|
11415
11560
|
const jointDef = new box2d.instance.b2GearJointDef();
|
|
@@ -11551,50 +11696,6 @@ class Box2dPrismaticJoint extends Box2dJoint
|
|
|
11551
11696
|
getMotorForce(time) { return this.box2dJoint.GetMotorForce(1/time); }
|
|
11552
11697
|
}
|
|
11553
11698
|
|
|
11554
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
11555
|
-
/**
|
|
11556
|
-
* Box2D Static Object - Box2d with a static physics body
|
|
11557
|
-
* @extends Box2dObject
|
|
11558
|
-
* @memberof Box2D
|
|
11559
|
-
*/
|
|
11560
|
-
class Box2dStaticObject extends Box2dObject
|
|
11561
|
-
{
|
|
11562
|
-
/** Create a LittleJS object with Box2d physics
|
|
11563
|
-
* @param {Vector2} [pos]
|
|
11564
|
-
* @param {Vector2} [size]
|
|
11565
|
-
* @param {TileInfo} [tileInfo]
|
|
11566
|
-
* @param {number} [angle]
|
|
11567
|
-
* @param {Color} [color]
|
|
11568
|
-
* @param {number} [renderOrder] */
|
|
11569
|
-
constructor(pos, size, tileInfo, angle=0, color, renderOrder=0)
|
|
11570
|
-
{
|
|
11571
|
-
const bodyType = box2d.bodyTypeStatic;
|
|
11572
|
-
super(pos, size, tileInfo, angle, color, bodyType, renderOrder);
|
|
11573
|
-
}
|
|
11574
|
-
}
|
|
11575
|
-
|
|
11576
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
11577
|
-
/**
|
|
11578
|
-
* Box2D Kiematic Object - Box2d with a kinematic physics body
|
|
11579
|
-
* @extends Box2dObject
|
|
11580
|
-
* @memberof Box2D
|
|
11581
|
-
*/
|
|
11582
|
-
class Box2dKiematicObject extends Box2dObject
|
|
11583
|
-
{
|
|
11584
|
-
/** Create a LittleJS object with Box2d physics
|
|
11585
|
-
* @param {Vector2} [pos]
|
|
11586
|
-
* @param {Vector2} [size]
|
|
11587
|
-
* @param {TileInfo} [tileInfo]
|
|
11588
|
-
* @param {number} [angle]
|
|
11589
|
-
* @param {Color} [color]
|
|
11590
|
-
* @param {number} [renderOrder] */
|
|
11591
|
-
constructor(pos, size, tileInfo, angle=0, color, renderOrder=0)
|
|
11592
|
-
{
|
|
11593
|
-
const bodyType = box2d.bodyTypeKinematic;
|
|
11594
|
-
super(pos, size, tileInfo, angle, color, bodyType, renderOrder);
|
|
11595
|
-
}
|
|
11596
|
-
}
|
|
11597
|
-
|
|
11598
11699
|
///////////////////////////////////////////////////////////////////////////////
|
|
11599
11700
|
/**
|
|
11600
11701
|
* Box2D Wheel Joint
|
|
@@ -11955,10 +12056,13 @@ class Box2dPlugin
|
|
|
11955
12056
|
{
|
|
11956
12057
|
ASSERT(!box2d, 'Box2D already initialized');
|
|
11957
12058
|
box2d = this;
|
|
12059
|
+
|
|
12060
|
+
/** @property {Object} - The Box2d instance */
|
|
11958
12061
|
this.instance = instance;
|
|
12062
|
+
/** @property {Object} - The Box2d world */
|
|
11959
12063
|
this.world = new box2d.instance.b2World();
|
|
12064
|
+
/** @property {Array<Box2dObject>} - List of all Box2d objects */
|
|
11960
12065
|
this.objects = [];
|
|
11961
|
-
|
|
11962
12066
|
/** @property {number} - Velocity iterations per update*/
|
|
11963
12067
|
this.velocityIterations = 8;
|
|
11964
12068
|
/** @property {number} - Position iterations per update*/
|
|
@@ -12157,8 +12261,9 @@ class Box2dPlugin
|
|
|
12157
12261
|
* @param {Color} [color]
|
|
12158
12262
|
* @param {Color} [lineColor]
|
|
12159
12263
|
* @param {number} [lineWidth]
|
|
12264
|
+
* @param {boolean} [useWebGL=glEnable]
|
|
12160
12265
|
* @param {CanvasRenderingContext2D} [context] */
|
|
12161
|
-
drawFixture(fixture, pos, angle, color=WHITE, lineColor=BLACK, lineWidth=.1, context)
|
|
12266
|
+
drawFixture(fixture, pos, angle, color=WHITE, lineColor=BLACK, lineWidth=.1, useWebgl, context)
|
|
12162
12267
|
{
|
|
12163
12268
|
const shape = box2d.castObjectType(fixture.GetShape());
|
|
12164
12269
|
switch (shape.GetType())
|
|
@@ -12168,20 +12273,20 @@ class Box2dPlugin
|
|
|
12168
12273
|
let points = [];
|
|
12169
12274
|
for (let i=shape.GetVertexCount(); i--;)
|
|
12170
12275
|
points.push(box2d.vec2From(shape.GetVertex(i)));
|
|
12171
|
-
drawPoly(points, color, lineWidth, lineColor, pos, angle);
|
|
12276
|
+
drawPoly(points, color, lineWidth, lineColor, pos, angle, useWebgl, false, context);
|
|
12172
12277
|
break;
|
|
12173
12278
|
}
|
|
12174
12279
|
case box2d.instance.b2Shape.e_circle:
|
|
12175
12280
|
{
|
|
12176
12281
|
const radius = shape.get_m_radius();
|
|
12177
|
-
drawCircle(pos, radius*2, color, lineWidth, lineColor);
|
|
12282
|
+
drawCircle(pos, radius*2, color, lineWidth, lineColor, useWebgl, false, context);
|
|
12178
12283
|
break;
|
|
12179
12284
|
}
|
|
12180
12285
|
case box2d.instance.b2Shape.e_edge:
|
|
12181
12286
|
{
|
|
12182
12287
|
const v1 = box2d.vec2From(shape.get_m_vertex1());
|
|
12183
12288
|
const v2 = box2d.vec2From(shape.get_m_vertex2());
|
|
12184
|
-
drawLine(v1, v2, lineWidth, lineColor, pos, angle);
|
|
12289
|
+
drawLine(v1, v2, lineWidth, lineColor, pos, angle, useWebgl, false, context);
|
|
12185
12290
|
break;
|
|
12186
12291
|
}
|
|
12187
12292
|
}
|
|
@@ -12199,7 +12304,7 @@ class Box2dPlugin
|
|
|
12199
12304
|
}
|
|
12200
12305
|
|
|
12201
12306
|
/** converts a box2d vec2 pointer to a Vector2
|
|
12202
|
-
* @param {Object}
|
|
12307
|
+
* @param {Object} vp */
|
|
12203
12308
|
vec2FromPointer(vp)
|
|
12204
12309
|
{
|
|
12205
12310
|
const v = box2d.instance.wrapPointer(vp, box2d.instance.b2Vec2);
|
|
@@ -12311,7 +12416,7 @@ async function box2dInit()
|
|
|
12311
12416
|
const box2dColorPointer = (c)=>
|
|
12312
12417
|
box2dColor(box2d.instance.wrapPointer(c, box2d.instance.b2Color));
|
|
12313
12418
|
const getDebugColor = (color)=>box2dColorPointer(color).scale(1,.8);
|
|
12314
|
-
const getPointsList = (vertices, vertexCount)
|
|
12419
|
+
const getPointsList = (vertices, vertexCount)=>
|
|
12315
12420
|
{
|
|
12316
12421
|
const points = [];
|
|
12317
12422
|
for (let i=vertexCount; i--;)
|
|
@@ -12818,7 +12923,6 @@ export
|
|
|
12818
12923
|
audioMasterGain,
|
|
12819
12924
|
audioDefaultSampleRate,
|
|
12820
12925
|
Sound,
|
|
12821
|
-
SoundWave,
|
|
12822
12926
|
SoundInstance,
|
|
12823
12927
|
speak,
|
|
12824
12928
|
speakStop,
|