littlejsengine 1.12.4 → 1.12.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/dist/box2d.wasm.js +630 -0
- package/dist/box2d.wasm.wasm +0 -0
- package/dist/littlejs.d.ts +52 -44
- package/dist/littlejs.esm.js +100 -97
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +98 -96
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +98 -96
- package/examples/box2d/game.js +36 -41
- package/examples/box2d/gameObjects.js +38 -35
- package/examples/box2d/index.html +1 -1
- package/examples/box2d/scenes.js +17 -13
- package/examples/box2d/tiles.png +0 -0
- package/examples/index.html +22 -14
- package/examples/platformer/game.js +6 -15
- package/examples/shorts/base.html +1 -0
- package/examples/shorts/box2d.js +46 -0
- package/examples/shorts/box2dCar.js +49 -0
- package/examples/shorts/postProcess.js +45 -0
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/uiSystem.js +39 -0
- package/examples/starter/game.js +2 -0
- package/examples/uiSystem/game.js +1 -1
- package/package.json +1 -1
- package/plugins/box2d.js +23 -29
- package/plugins/pluginExport.js +1 -1
- package/plugins/uiSystem.js +9 -3
- package/src/engine.js +10 -11
- package/src/engineAudio.js +24 -15
- package/src/engineBuild.js +12 -2
- package/src/engineExport.js +1 -0
- package/src/engineInput.js +3 -3
- package/src/engineUtilities.js +16 -0
- package/src/engineWebGL.js +13 -1
package/plugins/uiSystem.js
CHANGED
|
@@ -177,6 +177,8 @@ class UIObject
|
|
|
177
177
|
this.lineWidth = uiSystem.defaultLineWidth;
|
|
178
178
|
/** @property {string} */
|
|
179
179
|
this.font = uiSystem.defaultFont;
|
|
180
|
+
/** @property {number} - override for text height */
|
|
181
|
+
this.textHeight = undefined;
|
|
180
182
|
/** @property {boolean} */
|
|
181
183
|
this.visible = true;
|
|
182
184
|
/** @property {Array<UIObject>} */
|
|
@@ -287,7 +289,8 @@ class UIText extends UIObject
|
|
|
287
289
|
}
|
|
288
290
|
render()
|
|
289
291
|
{
|
|
290
|
-
|
|
292
|
+
const textSize = vec2(this.size.x, this.textHeight || this.size.y);
|
|
293
|
+
uiSystem.drawText(this.text, this.pos, textSize, this.textColor, this.lineWidth, this.lineColor, this.align, this.font);
|
|
291
294
|
}
|
|
292
295
|
}
|
|
293
296
|
|
|
@@ -350,7 +353,9 @@ class UIButton extends UIObject
|
|
|
350
353
|
const lineColor = this.mouseIsHeld ? this.color : this.lineColor;
|
|
351
354
|
const color = this.mouseIsOver? this.hoverColor : this.color;
|
|
352
355
|
uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor);
|
|
353
|
-
|
|
356
|
+
|
|
357
|
+
const textScale = .8; // scale text to fit in button
|
|
358
|
+
const textSize = vec2(this.size.x, this.textHeight || this.size.y*textScale);
|
|
354
359
|
uiSystem.drawText(this.text, this.pos, textSize,
|
|
355
360
|
this.textColor, 0, undefined, this.align, this.font);
|
|
356
361
|
}
|
|
@@ -447,7 +452,8 @@ class UIScrollbar extends UIObject
|
|
|
447
452
|
const barColor = this.mouseIsHeld ? this.color : this.handleColor;
|
|
448
453
|
uiSystem.drawRect(handlePos, handleSize, barColor, this.lineWidth, this.lineColor);
|
|
449
454
|
|
|
450
|
-
const
|
|
455
|
+
const textScale = .8; // scale text to fit in scrollbar
|
|
456
|
+
const textSize = vec2(this.size.x, this.textHeight || this.size.y*textScale);
|
|
451
457
|
uiSystem.drawText(this.text, this.pos, textSize,
|
|
452
458
|
this.textColor, 0, undefined, this.align, this.font);
|
|
453
459
|
}
|
package/src/engine.js
CHANGED
|
@@ -30,7 +30,7 @@ const engineName = 'LittleJS';
|
|
|
30
30
|
* @type {string}
|
|
31
31
|
* @default
|
|
32
32
|
* @memberof Engine */
|
|
33
|
-
const engineVersion = '1.12.
|
|
33
|
+
const engineVersion = '1.12.6';
|
|
34
34
|
|
|
35
35
|
/** Frames per second to update
|
|
36
36
|
* @type {number}
|
|
@@ -112,7 +112,7 @@ function engineAddPlugin(updateFunction, renderFunction)
|
|
|
112
112
|
* @param {Array<string>} [imageSources=[]] - List of images to load
|
|
113
113
|
* @param {HTMLElement} [rootElement] - Root element to attach to, the document body by default
|
|
114
114
|
* @memberof Engine */
|
|
115
|
-
function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=[], rootElement=document.body)
|
|
115
|
+
async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=[], rootElement=document.body)
|
|
116
116
|
{
|
|
117
117
|
ASSERT(!mainContext, 'engine already initialized');
|
|
118
118
|
ASSERT(Array.isArray(imageSources), 'pass in images as array');
|
|
@@ -269,16 +269,14 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
269
269
|
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
-
|
|
272
|
+
// wait for gameInit to load
|
|
273
|
+
async function startEngine()
|
|
273
274
|
{
|
|
274
|
-
|
|
275
|
+
await gameInit();
|
|
276
|
+
engineUpdate();
|
|
275
277
|
}
|
|
276
|
-
|
|
277
278
|
if (headlessMode)
|
|
278
|
-
|
|
279
|
-
startEngine();
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
279
|
+
return startEngine();
|
|
282
280
|
|
|
283
281
|
// setup html
|
|
284
282
|
const styleRoot =
|
|
@@ -354,8 +352,9 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
354
352
|
}));
|
|
355
353
|
}
|
|
356
354
|
|
|
357
|
-
//
|
|
358
|
-
Promise.all(promises)
|
|
355
|
+
// wait for all the promises to finish
|
|
356
|
+
await Promise.all(promises);
|
|
357
|
+
return startEngine();
|
|
359
358
|
}
|
|
360
359
|
|
|
361
360
|
/** Update each engine object, remove destroyed objects, and update time
|
package/src/engineAudio.js
CHANGED
|
@@ -47,17 +47,17 @@ class Sound
|
|
|
47
47
|
{
|
|
48
48
|
/** Create a sound object and cache the zzfx samples for later use
|
|
49
49
|
* @param {Array} zzfxSound - Array of zzfx parameters, ex. [.5,.5]
|
|
50
|
-
* @param {number} [range=soundDefaultRange] - World space max range of sound
|
|
50
|
+
* @param {number} [range=soundDefaultRange] - World space max range of sound
|
|
51
51
|
* @param {number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering
|
|
52
52
|
*/
|
|
53
53
|
constructor(zzfxSound, range=soundDefaultRange, taper=soundDefaultTaper)
|
|
54
54
|
{
|
|
55
55
|
if (!soundEnable || headlessMode) return;
|
|
56
56
|
|
|
57
|
-
/** @property {number} - World space max range of sound
|
|
57
|
+
/** @property {number} - World space max range of sound */
|
|
58
58
|
this.range = range;
|
|
59
59
|
|
|
60
|
-
/** @property {number} - At what percentage of range should it start tapering
|
|
60
|
+
/** @property {number} - At what percentage of range should it start tapering */
|
|
61
61
|
this.taper = taper;
|
|
62
62
|
|
|
63
63
|
/** @property {number} - How much to randomize frequency each time sound plays */
|
|
@@ -173,8 +173,8 @@ class SoundWave extends Sound
|
|
|
173
173
|
/** Create a sound object and cache the wave file for later use
|
|
174
174
|
* @param {string} filename - Filename of audio file to load
|
|
175
175
|
* @param {number} [randomness] - How much to randomize frequency each time sound plays
|
|
176
|
-
* @param {number} [range=soundDefaultRange] - World space max range of sound
|
|
177
|
-
* @param {number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering
|
|
176
|
+
* @param {number} [range=soundDefaultRange] - World space max range of sound
|
|
177
|
+
* @param {number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering
|
|
178
178
|
* @param {Function} [onloadCallback] - callback function to call when sound is loaded
|
|
179
179
|
*/
|
|
180
180
|
constructor(filename, randomness=0, range, taper, onloadCallback)
|
|
@@ -182,17 +182,26 @@ class SoundWave extends Sound
|
|
|
182
182
|
super(undefined, range, taper);
|
|
183
183
|
if (!soundEnable || headlessMode) return;
|
|
184
184
|
|
|
185
|
+
/** @property {Function} - callback function to call when sound is loaded */
|
|
186
|
+
this.onloadCallback = onloadCallback;
|
|
185
187
|
this.randomness = randomness;
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
188
|
+
this.loadSound(filename);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Loads a sound from a URL and decodes it into sample data. Must be used with await!
|
|
192
|
+
* @param {string} filename
|
|
193
|
+
* @return {Promise<void>} */
|
|
194
|
+
async loadSound(filename)
|
|
195
|
+
{
|
|
196
|
+
const response = await fetch(filename);
|
|
197
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
198
|
+
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
|
|
199
|
+
this.sampleChannels = [];
|
|
200
|
+
for (let i = audioBuffer.numberOfChannels; i--;)
|
|
201
|
+
this.sampleChannels[i] = Array.from(audioBuffer.getChannelData(i));
|
|
202
|
+
this.sampleRate = audioBuffer.sampleRate;
|
|
203
|
+
if (this.onloadCallback)
|
|
204
|
+
this.onloadCallback();
|
|
196
205
|
}
|
|
197
206
|
}
|
|
198
207
|
|
package/src/engineBuild.js
CHANGED
|
@@ -36,6 +36,11 @@ const enginePluginFiles =
|
|
|
36
36
|
`${PLUGIN_FOLDER}/uiSystem.js`,
|
|
37
37
|
`${PLUGIN_FOLDER}/box2d.js`,
|
|
38
38
|
];
|
|
39
|
+
const engineExtraFiles =
|
|
40
|
+
[
|
|
41
|
+
`${PLUGIN_FOLDER}/box2d.wasm.js`,
|
|
42
|
+
`${PLUGIN_FOLDER}/box2d.wasm.wasm`,
|
|
43
|
+
];
|
|
39
44
|
const asciiArt =`
|
|
40
45
|
~~~~°°°°ooo°oOo°ooOooOooOo.
|
|
41
46
|
__________ ________ ____'°oO.
|
|
@@ -57,6 +62,11 @@ try
|
|
|
57
62
|
// Setup build folder
|
|
58
63
|
fs.rmSync(BUILD_FOLDER, { recursive: true, force: true });
|
|
59
64
|
fs.mkdirSync(BUILD_FOLDER);
|
|
65
|
+
|
|
66
|
+
// copy extra files to build folder
|
|
67
|
+
for (const file of engineExtraFiles)
|
|
68
|
+
fs.copyFileSync(file, `${BUILD_FOLDER}/${file.substring(file.lastIndexOf('/')+1)}`);
|
|
69
|
+
|
|
60
70
|
}
|
|
61
71
|
catch (e) { handleError(e, 'Failed to create build folder!'); }
|
|
62
72
|
|
|
@@ -140,9 +150,9 @@ function Build(message, outputFile, files=[], buildSteps=[], isPrimaryBuild)
|
|
|
140
150
|
// get file content
|
|
141
151
|
let fileContent = fs.readFileSync(file) + '\n';
|
|
142
152
|
|
|
143
|
-
// remove first 'use strict'
|
|
153
|
+
// remove first 'use strict' and surrounding new lines
|
|
144
154
|
if (isPrimaryBuild)
|
|
145
|
-
fileContent = fileContent.replace(
|
|
155
|
+
fileContent = fileContent.replace(/'use strict';\s*\n/g, '');
|
|
146
156
|
|
|
147
157
|
// add it to the buffer
|
|
148
158
|
buffer += fileContent;
|
package/src/engineExport.js
CHANGED
package/src/engineInput.js
CHANGED
|
@@ -61,21 +61,21 @@ function clearInput() { inputData = [[]]; touchGamepadButtons = []; }
|
|
|
61
61
|
* @param {number} button
|
|
62
62
|
* @return {boolean}
|
|
63
63
|
* @memberof Input */
|
|
64
|
-
|
|
64
|
+
function mouseIsDown(button) { return keyIsDown(button); }
|
|
65
65
|
|
|
66
66
|
/** Returns true if mouse button was pressed
|
|
67
67
|
* @function
|
|
68
68
|
* @param {number} button
|
|
69
69
|
* @return {boolean}
|
|
70
70
|
* @memberof Input */
|
|
71
|
-
|
|
71
|
+
function mouseWasPressed(button) { return keyWasPressed(button); }
|
|
72
72
|
|
|
73
73
|
/** Returns true if mouse button was released
|
|
74
74
|
* @function
|
|
75
75
|
* @param {number} button
|
|
76
76
|
* @return {boolean}
|
|
77
77
|
* @memberof Input */
|
|
78
|
-
|
|
78
|
+
function mouseWasReleased(button) { return keyWasReleased(button); }
|
|
79
79
|
|
|
80
80
|
/** Mouse pos in world space
|
|
81
81
|
* @type {Vector2}
|
package/src/engineUtilities.js
CHANGED
|
@@ -189,6 +189,16 @@ function wave(frequency=1, amplitude=1, t=time)
|
|
|
189
189
|
* @memberof Utilities */
|
|
190
190
|
function formatTime(t) { return (t/60|0) + ':' + (t%60<10?'0':'') + (t%60|0); }
|
|
191
191
|
|
|
192
|
+
/** Fetches a JSON file from a URL and returns the parsed JSON object. Must be used with await!
|
|
193
|
+
* @param {string} url - URL of JSON file
|
|
194
|
+
* @return {Promise<object>}
|
|
195
|
+
* @memberof Utilities */
|
|
196
|
+
async function fetchJSON(url)
|
|
197
|
+
{
|
|
198
|
+
const response = await fetch(url);
|
|
199
|
+
return response.json();
|
|
200
|
+
}
|
|
201
|
+
|
|
192
202
|
///////////////////////////////////////////////////////////////////////////////
|
|
193
203
|
|
|
194
204
|
/** Random global functions
|
|
@@ -284,6 +294,12 @@ class RandomGenerator
|
|
|
284
294
|
/** Randomly returns either -1 or 1 deterministically
|
|
285
295
|
* @return {number} */
|
|
286
296
|
sign() { return this.float() > .5 ? 1 : -1; }
|
|
297
|
+
|
|
298
|
+
/** Returns a seeded random value between the two values passed in with a random sign
|
|
299
|
+
* @param {number} [valueA]
|
|
300
|
+
* @param {number} [valueB]
|
|
301
|
+
* @return {number} */
|
|
302
|
+
floatSign(valueA=1, valueB=0) { return this.float(valueA, valueB) * this.sign(); }
|
|
287
303
|
}
|
|
288
304
|
|
|
289
305
|
///////////////////////////////////////////////////////////////////////////////
|
package/src/engineWebGL.js
CHANGED
|
@@ -210,7 +210,19 @@ function glCreateTexture(image)
|
|
|
210
210
|
const texture = glContext.createTexture();
|
|
211
211
|
glContext.bindTexture(glContext.TEXTURE_2D, texture);
|
|
212
212
|
if (image && image.width)
|
|
213
|
+
{
|
|
213
214
|
glSetTextureData(texture, image);
|
|
215
|
+
|
|
216
|
+
const isPowerOfTwo = (value)=> !(value & (value - 1));
|
|
217
|
+
if (!tilesPixelated && isPowerOfTwo(image.width) && isPowerOfTwo(image.height))
|
|
218
|
+
{
|
|
219
|
+
// use mipmap filtering
|
|
220
|
+
glContext.generateMipmap(glContext.TEXTURE_2D);
|
|
221
|
+
glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, glContext.LINEAR_MIPMAP_LINEAR);
|
|
222
|
+
glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER, glContext.LINEAR);
|
|
223
|
+
return texture;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
214
226
|
else
|
|
215
227
|
{
|
|
216
228
|
// create a white texture
|
|
@@ -218,7 +230,7 @@ function glCreateTexture(image)
|
|
|
218
230
|
glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, 1, 1, 0, glContext.RGBA, glContext.UNSIGNED_BYTE, whitePixel);
|
|
219
231
|
}
|
|
220
232
|
|
|
221
|
-
//
|
|
233
|
+
// set texture filtering
|
|
222
234
|
const filter = tilesPixelated ? glContext.NEAREST : glContext.LINEAR;
|
|
223
235
|
glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, filter);
|
|
224
236
|
glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER, filter);
|