littlejsengine 1.14.10 → 1.14.11
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 +12 -11
- package/dist/littlejs.esm.js +54 -46
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +53 -46
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +45 -32
- package/examples/index.html +52 -47
- package/examples/platformer/gameCharacter.js +6 -2
- package/examples/platformer/gameLevel.js +1 -1
- package/examples/platformer/gameObjects.js +7 -5
- package/examples/shorts/landerGame.js +26 -2
- package/examples/shorts/music.js +3 -2
- package/examples/shorts/particles.js +2 -2
- package/examples/shorts/raycasting.js +4 -1
- package/examples/shorts/slidingPuzzle.js +13 -5
- package/examples/shorts/starfield.js +1 -1
- package/examples/uiSystem/game.js +4 -4
- package/package.json +1 -1
- package/plugins/box2d.js +1 -1
- package/plugins/newgrounds.js +4 -4
- package/reference.md +0 -2
- package/src/engine.js +20 -12
- package/src/engineDebug.js +9 -14
- package/src/engineExport.js +1 -0
- package/src/engineRelease.js +1 -0
- package/src/engineTileLayer.js +7 -1
- package/src/engineUtilities.js +12 -14
package/dist/littlejs.release.js
CHANGED
|
@@ -33,7 +33,7 @@ const engineName = 'LittleJS';
|
|
|
33
33
|
* @type {string}
|
|
34
34
|
* @default
|
|
35
35
|
* @memberof Engine */
|
|
36
|
-
const engineVersion = '1.14.
|
|
36
|
+
const engineVersion = '1.14.11';
|
|
37
37
|
|
|
38
38
|
/** Frames per second to update
|
|
39
39
|
* @type {number}
|
|
@@ -122,12 +122,12 @@ function engineAddPlugin(updateFunction, renderFunction)
|
|
|
122
122
|
* @example
|
|
123
123
|
* // Basic engine startup
|
|
124
124
|
* engineInit(
|
|
125
|
-
* () => {
|
|
126
|
-
* () => { updateGameLogic(); },
|
|
127
|
-
* () => { updateUI(); },
|
|
128
|
-
* () => { drawBackground(); },
|
|
129
|
-
* () => { drawHUD(); },
|
|
130
|
-
* ['tiles.png', 'tilesLevel.png']
|
|
125
|
+
* () => { LOG('Game initialized!'); }, // gameInit
|
|
126
|
+
* () => { updateGameLogic(); }, // gameUpdate
|
|
127
|
+
* () => { updateUI(); }, // gameUpdatePost
|
|
128
|
+
* () => { drawBackground(); }, // gameRender
|
|
129
|
+
* () => { drawHUD(); }, // gameRenderPost
|
|
130
|
+
* ['tiles.png', 'tilesLevel.png'] // images to load
|
|
131
131
|
* );
|
|
132
132
|
* @memberof Engine */
|
|
133
133
|
async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=[], rootElement=document.body)
|
|
@@ -173,16 +173,20 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
173
173
|
if (!debugSpeedUp)
|
|
174
174
|
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp min framerate
|
|
175
175
|
|
|
176
|
+
let wasUpdated = false;
|
|
176
177
|
if (paused)
|
|
177
178
|
{
|
|
179
|
+
// update everything except the game and objects
|
|
180
|
+
wasUpdated = true;
|
|
178
181
|
updateCanvas();
|
|
182
|
+
inputUpdate();
|
|
183
|
+
pluginUpdateList.forEach(f=>f());
|
|
179
184
|
|
|
180
185
|
// update object transforms even when paused
|
|
181
186
|
for (const o of engineObjects)
|
|
182
187
|
o.parent || o.updateTransforms();
|
|
183
188
|
|
|
184
|
-
|
|
185
|
-
pluginUpdateList.forEach(f=>f());
|
|
189
|
+
// do post update
|
|
186
190
|
debugUpdate();
|
|
187
191
|
gameUpdatePost();
|
|
188
192
|
inputUpdatePost();
|
|
@@ -199,12 +203,13 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
199
203
|
}
|
|
200
204
|
|
|
201
205
|
// update multiple frames if necessary in case of slow framerate
|
|
202
|
-
for (;frameTimeBufferMS >= 0; frameTimeBufferMS -= 1e3 / frameRate)
|
|
206
|
+
for (; frameTimeBufferMS >= 0; frameTimeBufferMS -= 1e3 / frameRate)
|
|
203
207
|
{
|
|
204
208
|
// increment frame and update time
|
|
205
209
|
time = frame++ / frameRate;
|
|
206
210
|
|
|
207
211
|
// update game and objects
|
|
212
|
+
wasUpdated = true;
|
|
208
213
|
updateCanvas();
|
|
209
214
|
inputUpdate();
|
|
210
215
|
gameUpdate();
|
|
@@ -215,7 +220,6 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
215
220
|
debugUpdate();
|
|
216
221
|
gameUpdatePost();
|
|
217
222
|
inputUpdatePost();
|
|
218
|
-
|
|
219
223
|
if (debugVideoCaptureIsActive())
|
|
220
224
|
renderFrame();
|
|
221
225
|
}
|
|
@@ -232,6 +236,10 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
232
236
|
{
|
|
233
237
|
if (headlessMode) return;
|
|
234
238
|
|
|
239
|
+
// canvas must be updated before rendering
|
|
240
|
+
if (!wasUpdated)
|
|
241
|
+
updateCanvas();
|
|
242
|
+
|
|
235
243
|
// render sort then render while removing destroyed objects
|
|
236
244
|
enginePreRender();
|
|
237
245
|
gameRender();
|
|
@@ -391,7 +399,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
391
399
|
promises.push(new Promise(resolve =>
|
|
392
400
|
{
|
|
393
401
|
let t = 0;
|
|
394
|
-
|
|
402
|
+
LOG(`${engineName} Engine v${engineVersion}`);
|
|
395
403
|
updateSplash();
|
|
396
404
|
function updateSplash()
|
|
397
405
|
{
|
|
@@ -690,6 +698,7 @@ const debugMedals = 0;
|
|
|
690
698
|
|
|
691
699
|
// debug commands are automatically removed from the final build
|
|
692
700
|
function ASSERT (){}
|
|
701
|
+
function LOG (){}
|
|
693
702
|
function debugInit (){}
|
|
694
703
|
function debugUpdate (){}
|
|
695
704
|
function debugRender (){}
|
|
@@ -927,7 +936,12 @@ function wave(frequency=1, amplitude=1, t=time, offset=0)
|
|
|
927
936
|
* @param {number} t - time in seconds
|
|
928
937
|
* @return {string}
|
|
929
938
|
* @memberof Utilities */
|
|
930
|
-
function formatTime(t)
|
|
939
|
+
function formatTime(t)
|
|
940
|
+
{
|
|
941
|
+
const sign = t < 0 ? '-' : '';
|
|
942
|
+
t = abs(t)|0;
|
|
943
|
+
return sign + (t/60|0) + ':' + (t%60<10?'0':'') + t%60;
|
|
944
|
+
}
|
|
931
945
|
|
|
932
946
|
/** Fetches a JSON file from a URL and returns the parsed JSON object. Must be used with await!
|
|
933
947
|
* @param {string} url - URL of JSON file
|
|
@@ -1263,11 +1277,7 @@ class Vector2
|
|
|
1263
1277
|
direction()
|
|
1264
1278
|
{ return abs(this.x) > abs(this.y) ? this.x < 0 ? 3 : 1 : this.y < 0 ? 2 : 0; }
|
|
1265
1279
|
|
|
1266
|
-
/** Returns a copy of this vector
|
|
1267
|
-
* @return {Vector2} */
|
|
1268
|
-
invert() { return new Vector2(this.y, -this.x); }
|
|
1269
|
-
|
|
1270
|
-
/** Returns a copy of this vector absolute values
|
|
1280
|
+
/** Returns a copy of this vector with absolute values
|
|
1271
1281
|
* @return {Vector2} */
|
|
1272
1282
|
abs() { return new Vector2(abs(this.x), abs(this.y)); }
|
|
1273
1283
|
|
|
@@ -1309,13 +1319,10 @@ class Vector2
|
|
|
1309
1319
|
toString(digits=3)
|
|
1310
1320
|
{
|
|
1311
1321
|
ASSERT_NUMBER_VALID(digits);
|
|
1312
|
-
if (
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
else
|
|
1317
|
-
return `(${this.x}, ${this.y})`;
|
|
1318
|
-
}
|
|
1322
|
+
if (this.isValid())
|
|
1323
|
+
return `(${(this.x<0?'':' ') + this.x.toFixed(digits)},${(this.y<0?'':' ') + this.y.toFixed(digits)} )`;
|
|
1324
|
+
else
|
|
1325
|
+
return `(${this.x}, ${this.y})`;
|
|
1319
1326
|
}
|
|
1320
1327
|
|
|
1321
1328
|
/** Checks if this is a valid vector
|
|
@@ -1704,7 +1711,7 @@ class Timer
|
|
|
1704
1711
|
|
|
1705
1712
|
/** Returns this timer expressed as a string
|
|
1706
1713
|
* @return {string} */
|
|
1707
|
-
toString() {
|
|
1714
|
+
toString() { return this.isSet() ? Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ) : 'unset'; }
|
|
1708
1715
|
|
|
1709
1716
|
/** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
|
|
1710
1717
|
* @return {number} */
|
|
@@ -5071,6 +5078,12 @@ function tileCollisionLoad(tileMapData, tileInfo=tile(), renderOrder=0, collisio
|
|
|
5071
5078
|
const tileLayer = new TileCollisionLayer(vec2(), levelSize, tileInfo, layerRenderOrder);
|
|
5072
5079
|
tileLayers[layerIndex] = tileLayer;
|
|
5073
5080
|
|
|
5081
|
+
// apply layer color
|
|
5082
|
+
const layerColor = dataLayer.color || WHITE;
|
|
5083
|
+
if (dataLayer.tintcolor)
|
|
5084
|
+
layerColor.setHex(dataLayer.tintcolor);
|
|
5085
|
+
ASSERT(isColor(layerColor), 'layer color is not a color');
|
|
5086
|
+
|
|
5074
5087
|
for (let x=levelSize.x; x--;)
|
|
5075
5088
|
for (let y=levelSize.y; y--;)
|
|
5076
5089
|
{
|
|
@@ -5078,7 +5091,7 @@ function tileCollisionLoad(tileMapData, tileInfo=tile(), renderOrder=0, collisio
|
|
|
5078
5091
|
const data = dataLayer.data[x + y*levelSize.x];
|
|
5079
5092
|
if (data)
|
|
5080
5093
|
{
|
|
5081
|
-
const layerData = new TileLayerData(data-1);
|
|
5094
|
+
const layerData = new TileLayerData(data-1, 0, false, layerColor);
|
|
5082
5095
|
tileLayer.setData(pos, layerData);
|
|
5083
5096
|
|
|
5084
5097
|
// set collision for top layer
|
|
@@ -6972,7 +6985,7 @@ class NewgroundsPlugin
|
|
|
6972
6985
|
// get medals
|
|
6973
6986
|
const medalsResult = this.call('Medal.getList');
|
|
6974
6987
|
this.medals = medalsResult ? medalsResult.result.data['medals'] : [];
|
|
6975
|
-
debugMedals &&
|
|
6988
|
+
debugMedals && LOG(this.medals);
|
|
6976
6989
|
for (const newgroundsMedal of this.medals)
|
|
6977
6990
|
{
|
|
6978
6991
|
const medal = medals[newgroundsMedal['id']];
|
|
@@ -6995,7 +7008,7 @@ class NewgroundsPlugin
|
|
|
6995
7008
|
// get scoreboards
|
|
6996
7009
|
const scoreboardResult = this.call('ScoreBoard.getBoards');
|
|
6997
7010
|
this.scoreboards = scoreboardResult ? scoreboardResult.result.data.scoreboards : [];
|
|
6998
|
-
debugMedals &&
|
|
7011
|
+
debugMedals && LOG(this.scoreboards);
|
|
6999
7012
|
|
|
7000
7013
|
// keep the session alive with a ping every minute
|
|
7001
7014
|
const keepAliveMS = 60 * 1e3;
|
|
@@ -7064,10 +7077,10 @@ class NewgroundsPlugin
|
|
|
7064
7077
|
try { xmlHttp.send(formData); }
|
|
7065
7078
|
catch(e)
|
|
7066
7079
|
{
|
|
7067
|
-
debugMedals &&
|
|
7080
|
+
debugMedals && LOG('newgrounds call failed', e);
|
|
7068
7081
|
return;
|
|
7069
7082
|
}
|
|
7070
|
-
debugMedals &&
|
|
7083
|
+
debugMedals && LOG(xmlHttp.responseText);
|
|
7071
7084
|
return xmlHttp.responseText && JSON.parse(xmlHttp.responseText);
|
|
7072
7085
|
}
|
|
7073
7086
|
}
|
|
@@ -9664,7 +9677,7 @@ async function box2dInit()
|
|
|
9664
9677
|
}
|
|
9665
9678
|
function box2dRender()
|
|
9666
9679
|
{
|
|
9667
|
-
if (box2dDebug || debugPhysics
|
|
9680
|
+
if (box2dDebug || debugPhysics)
|
|
9668
9681
|
box2d.world.DrawDebugData();
|
|
9669
9682
|
}
|
|
9670
9683
|
|
package/examples/index.html
CHANGED
|
@@ -53,7 +53,7 @@ Theme:
|
|
|
53
53
|
|
|
54
54
|
class ExampleInfo
|
|
55
55
|
{
|
|
56
|
-
constructor(name, filename, description='', largeExample=false)
|
|
56
|
+
constructor(name, filename, description='', largeExample=false, tags='')
|
|
57
57
|
{
|
|
58
58
|
if (filename && !largeExample)
|
|
59
59
|
filename = 'shorts/' + filename;
|
|
@@ -61,62 +61,66 @@ class ExampleInfo
|
|
|
61
61
|
this.filename = filename;
|
|
62
62
|
this.description = description;
|
|
63
63
|
this.largeExample = largeExample;
|
|
64
|
+
this.tags = tags;
|
|
64
65
|
this.isHeading = !filename;
|
|
65
66
|
this.text = this.name;
|
|
66
67
|
if (this.description)
|
|
67
68
|
this.text += ' - ' + this.description;
|
|
69
|
+
this.selectText = this.text;
|
|
70
|
+
if (this.tags)
|
|
71
|
+
this.selectText += ' (' + this.tags + ')';
|
|
68
72
|
}
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
const exampleList =
|
|
72
76
|
[
|
|
73
77
|
new ExampleInfo('--- SHORT EXAMPLES ---'),
|
|
74
|
-
new ExampleInfo('Hello World', 'helloWorld.js', 'Minimal starter example'),
|
|
75
|
-
new ExampleInfo('Texture', 'texture.js', 'Texture display and manipulation'),
|
|
76
|
-
new ExampleInfo('Animation', 'animation.js', 'Sprite animation system'),
|
|
77
|
-
new ExampleInfo('Shapes', 'shapes.js', 'Draw geometric shapes and primitives'),
|
|
78
|
-
new ExampleInfo('Colors', 'colors.js', 'Color manipulation and HSL'),
|
|
79
|
-
new ExampleInfo('Starfield', 'starfield.js', 'Animated parallax starfield'),
|
|
80
|
-
new ExampleInfo('Sprite Atlas', 'spriteAtlas.js', 'Sprite atlas and tile rendering'),
|
|
81
|
-
new ExampleInfo('Blending', 'blending.js', 'Additive blending and transparency'),
|
|
82
|
-
new ExampleInfo('Tile Layer', 'tileLayer.js', 'Tile layer rendering system'),
|
|
83
|
-
new ExampleInfo('Particles', 'particles.js', 'Particle system'),
|
|
84
|
-
new ExampleInfo('Timers', 'timers.js', 'Timer objects and UI'),
|
|
85
|
-
new ExampleInfo('Sound Effects', 'sound.js', 'ZzFX sound effect generator'),
|
|
86
|
-
new ExampleInfo('Music', 'music.js', 'Music playback and controls'),
|
|
87
|
-
new ExampleInfo('Font Image', 'systemFont.js', 'Bitmap font system with built-in system font'),
|
|
88
|
-
new ExampleInfo('Parallax', 'parallax.js', 'Parallax scrolling mountains'),
|
|
89
|
-
new ExampleInfo('Maze Generator', 'maze.js', 'Procedural maze generation'),
|
|
90
|
-
new ExampleInfo('Medals', 'medals.js', 'Achievement system'),
|
|
91
|
-
new ExampleInfo('Piano', 'piano.js', 'Interactive piano keyboard'),
|
|
92
|
-
new ExampleInfo('Clock', 'clock.js', 'Animated analog clock'),
|
|
78
|
+
new ExampleInfo('Hello World', 'helloWorld.js', 'Minimal starter example', false, 'beginner, gradient, text, tiles'),
|
|
79
|
+
new ExampleInfo('Texture', 'texture.js', 'Texture display and manipulation', false, 'sprites, loading, tiles'),
|
|
80
|
+
new ExampleInfo('Animation', 'animation.js', 'Sprite animation system', false, 'frames, loop, tiles, sprites'),
|
|
81
|
+
new ExampleInfo('Shapes', 'shapes.js', 'Draw geometric shapes and primitives', false, 'circle, ellipses, rectangles, polygon, lines'),
|
|
82
|
+
new ExampleInfo('Colors', 'colors.js', 'Color manipulation and HSL', false, 'hue, saturation, blending, rectangles'),
|
|
83
|
+
new ExampleInfo('Starfield', 'starfield.js', 'Animated parallax starfield', false, 'space, movement, depth, rectangles'),
|
|
84
|
+
new ExampleInfo('Sprite Atlas', 'spriteAtlas.js', 'Sprite atlas and tile rendering', false, 'sheet, frames, tiles'),
|
|
85
|
+
new ExampleInfo('Blending', 'blending.js', 'Additive blending and transparency', false, 'alpha, color, tiles, smooth'),
|
|
86
|
+
new ExampleInfo('Tile Layer', 'tileLayer.js', 'Tile layer rendering system', false, 'level, map, grid, particles'),
|
|
87
|
+
new ExampleInfo('Particles', 'particles.js', 'Particle system', false, 'effects, emitter, physics, fire, smoke'),
|
|
88
|
+
new ExampleInfo('Timers', 'timers.js', 'Timer objects and UI', false, 'delay, interval, slider'),
|
|
89
|
+
new ExampleInfo('Sound Effects', 'sound.js', 'ZzFX sound effect generator', false, 'audio, volume, ui'),
|
|
90
|
+
new ExampleInfo('Music', 'music.js', 'Music playback and controls', false, 'audio, streaming, volume, ui'),
|
|
91
|
+
new ExampleInfo('Font Image', 'systemFont.js', 'Bitmap font system with built-in system font', false, 'text, characters'),
|
|
92
|
+
new ExampleInfo('Parallax', 'parallax.js', 'Parallax scrolling mountains', false, 'generative, canvas, background'),
|
|
93
|
+
new ExampleInfo('Maze Generator', 'maze.js', 'Procedural maze generation', false, 'generative, level, tiles, map, grid'),
|
|
94
|
+
new ExampleInfo('Medals', 'medals.js', 'Achievement system', false, 'unlock, progress, newgrounds'),
|
|
95
|
+
new ExampleInfo('Piano', 'piano.js', 'Interactive piano keyboard', false, 'music, notes, ui, instrument'),
|
|
96
|
+
new ExampleInfo('Clock', 'clock.js', 'Animated analog clock', false, 'time, rotation, lines, rectangles'),
|
|
93
97
|
new ExampleInfo('--- MINI GAMES ---'),
|
|
94
|
-
new ExampleInfo('Pong Game', 'pongGame.js', 'Classic paddle ball bouncing'),
|
|
95
|
-
new ExampleInfo('Platformer Game', 'platformer.js', 'Jump and run side view'),
|
|
96
|
-
new ExampleInfo('Top Down Game', 'topDown.js', 'Top-down style camera'),
|
|
97
|
-
new ExampleInfo('Tilted View Game', 'tiltedView.js', 'Pseudo-3D oblique view'),
|
|
98
|
-
new ExampleInfo('Flappy Game', 'flappyGame.js', 'Flappy bird style game'),
|
|
99
|
-
new ExampleInfo('Lander Game', 'landerGame.js', 'Lunar lander style game'),
|
|
100
|
-
new ExampleInfo('Hill Glide Game', 'hillGlideGame.js', 'Tiny wings style sliding game'),
|
|
101
|
-
new ExampleInfo('Sliding Puzzle', 'slidingPuzzle.js', '15 tile sliding puzzle'),
|
|
102
|
-
new ExampleInfo('Space Game', 'spaceGame.js', 'Spaceship shooter with parallax'),
|
|
103
|
-
new ExampleInfo('Raycasting 3D Game', 'raycasting.js', '
|
|
98
|
+
new ExampleInfo('Pong Game', 'pongGame.js', 'Classic paddle ball bouncing', false, 'objects, collision'),
|
|
99
|
+
new ExampleInfo('Platformer Game', 'platformer.js', 'Jump and run side view', false, 'objects, gravity, level, tiles, camera'),
|
|
100
|
+
new ExampleInfo('Top Down Game', 'topDown.js', 'Top-down style camera', false, 'objects, movement, exploration'),
|
|
101
|
+
new ExampleInfo('Tilted View Game', 'tiltedView.js', 'Pseudo-3D oblique view', false, 'isometric, depth'),
|
|
102
|
+
new ExampleInfo('Flappy Game', 'flappyGame.js', 'Flappy bird style game', false, 'objects, obstacles'),
|
|
103
|
+
new ExampleInfo('Lander Game', 'landerGame.js', 'Lunar lander style game', false, 'objects, physics'),
|
|
104
|
+
new ExampleInfo('Hill Glide Game', 'hillGlideGame.js', 'Tiny wings style sliding game', false, 'objects, physics, speed'),
|
|
105
|
+
new ExampleInfo('Sliding Puzzle', 'slidingPuzzle.js', '15 tile sliding puzzle', false, 'objects, numbers, ui'),
|
|
106
|
+
new ExampleInfo('Space Game', 'spaceGame.js', 'Spaceship shooter with parallax', false, 'objects, weapons, stars, camera, rotation'),
|
|
107
|
+
new ExampleInfo('Raycasting 3D Game', 'raycasting.js', 'Pseudo 3D raycasting demo', false, '3D, maze, camera'),
|
|
104
108
|
new ExampleInfo('--- PLUGINS ---'),
|
|
105
|
-
new ExampleInfo('Box2d Demo', 'box2d.js', 'Box2D physics plugin'),
|
|
106
|
-
new ExampleInfo('Box2d Car', 'box2dCar.js', 'Drivable car with Box2D physics'),
|
|
107
|
-
new ExampleInfo('Post Processing', 'postProcess.js', 'Shader effects and filters'),
|
|
108
|
-
new ExampleInfo('UI System Plugin', 'uiSystem.js', 'Buttons, sliders, and checkboxes'),
|
|
109
|
-
new ExampleInfo('Nine Slice', 'nineSlice.js', 'Scalable UI panels'),
|
|
109
|
+
new ExampleInfo('Box2d Demo', 'box2d.js', 'Box2D physics plugin', false, 'objects, mouse'),
|
|
110
|
+
new ExampleInfo('Box2d Car', 'box2dCar.js', 'Drivable car with Box2D physics', false, 'objects, vehicle, suspension, wheels'),
|
|
111
|
+
new ExampleInfo('Post Processing', 'postProcess.js', 'Shader effects and filters', false, 'webgl, visual, effect'),
|
|
112
|
+
new ExampleInfo('UI System Plugin', 'uiSystem.js', 'Buttons, sliders, and checkboxes', false, 'objects, widgets, interactive'),
|
|
113
|
+
new ExampleInfo('Nine Slice', 'nineSlice.js', 'Scalable UI panels', false, 'three slice, stretch, corners, text, tiles'),
|
|
110
114
|
new ExampleInfo('--- FULL EXAMPLES ---'),
|
|
111
|
-
new ExampleInfo('Starter', 'starter', 'Clean project template', true),
|
|
112
|
-
new ExampleInfo('Breakout Tutorial', 'breakoutTutorial', 'Step-by-step breakout tutorial', true),
|
|
113
|
-
new ExampleInfo('Breakout Game', 'breakout', 'Complete breakout game', true),
|
|
114
|
-
new ExampleInfo('Platforming Game', 'platformer', '
|
|
115
|
-
new ExampleInfo('Puzzle Game', 'puzzle', 'Match
|
|
116
|
-
new ExampleInfo('Stress Test', 'stress', 'Performance and music test', true),
|
|
117
|
-
new ExampleInfo('Box2D Plugin', 'box2d', 'Full Box2D physics demo', true),
|
|
118
|
-
new ExampleInfo('HTML Menus', 'htmlMenu', 'HTML UI integration', true),
|
|
119
|
-
new ExampleInfo('UI System Plugin', 'uiSystem', 'Complete UI system demo', true),
|
|
115
|
+
new ExampleInfo('Starter', 'starter', 'Clean project template', true, 'base, empty, particles'),
|
|
116
|
+
new ExampleInfo('Breakout Tutorial', 'breakoutTutorial', 'Step-by-step breakout game tutorial', true, 'objects, physics, score'),
|
|
117
|
+
new ExampleInfo('Breakout Game', 'breakout', 'Complete breakout game', true, 'objects, physics, score'),
|
|
118
|
+
new ExampleInfo('Platforming Game', 'platformer', 'Platformer with level loading', true, 'jump, world, tiles, pixel art, sprites'),
|
|
119
|
+
new ExampleInfo('Puzzle Game', 'puzzle', 'Match 3 style puzzle game', true, 'match, swap, sprites'),
|
|
120
|
+
new ExampleInfo('Stress Test', 'stress', 'Performance and music test', true, 'optimization, tiles, sprites'),
|
|
121
|
+
new ExampleInfo('Box2D Plugin', 'box2d', 'Full Box2D physics demo', true, 'objects, bodies, joints'),
|
|
122
|
+
new ExampleInfo('HTML Menus', 'htmlMenu', 'HTML UI integration', true, 'web, browser, overlay, button, slider, textbox'),
|
|
123
|
+
new ExampleInfo('UI System Plugin', 'uiSystem', 'Complete UI system demo', true, 'menu, overlay, button, slider, checkbox'),
|
|
120
124
|
];
|
|
121
125
|
|
|
122
126
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -313,9 +317,10 @@ function filterExamples(reset=0)
|
|
|
313
317
|
if (!example.filename)
|
|
314
318
|
continue;
|
|
315
319
|
|
|
316
|
-
// Check if search term matches name or
|
|
320
|
+
// Check if search term matches name, description, or tags
|
|
317
321
|
if (example.name.toLowerCase().includes(searchTerm) ||
|
|
318
|
-
example.description.toLowerCase().includes(searchTerm)
|
|
322
|
+
example.description.toLowerCase().includes(searchTerm) ||
|
|
323
|
+
example.tags.toLowerCase().includes(searchTerm))
|
|
319
324
|
matchingIndices.push(i);
|
|
320
325
|
}
|
|
321
326
|
|
|
@@ -345,7 +350,7 @@ function filterExamples(reset=0)
|
|
|
345
350
|
else if (matchingIndices.includes(i))
|
|
346
351
|
{
|
|
347
352
|
// add matching example
|
|
348
|
-
const o = new Option(example.
|
|
353
|
+
const o = new Option(example.selectText);
|
|
349
354
|
o.originalIndex = i;
|
|
350
355
|
selectExample.add(o);
|
|
351
356
|
}
|
|
@@ -22,10 +22,9 @@ const {vec2, hsl, Timer} = LJS;
|
|
|
22
22
|
export class Character extends GameObjects.GameObject
|
|
23
23
|
{
|
|
24
24
|
constructor(pos)
|
|
25
|
-
{
|
|
25
|
+
{
|
|
26
26
|
super(pos, vec2(.6,.95));
|
|
27
27
|
|
|
28
|
-
this.weapon = new GameObjects.Weapon(pos, this);
|
|
29
28
|
this.lastPos = pos;
|
|
30
29
|
this.groundTimer = new Timer;
|
|
31
30
|
this.jumpTimer = new Timer;
|
|
@@ -41,6 +40,11 @@ export class Character extends GameObjects.GameObject
|
|
|
41
40
|
this.health = 1;
|
|
42
41
|
this.climbingLadder = false;
|
|
43
42
|
this.setCollision(true,false);
|
|
43
|
+
|
|
44
|
+
// attach weapon
|
|
45
|
+
this.weapon = new GameObjects.Weapon(pos);
|
|
46
|
+
this.weapon.renderOrder = this.renderOrder + 1;
|
|
47
|
+
this.addChild(this.weapon, vec2(this.size.x,0));
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
update()
|
|
@@ -50,7 +50,7 @@ function loadLevelData()
|
|
|
50
50
|
{
|
|
51
51
|
// load the level data
|
|
52
52
|
const tileMapData = Game.gameLevelData;
|
|
53
|
-
tileLayers = LJS.tileCollisionLoad(tileMapData, tile(0,16,1));
|
|
53
|
+
tileLayers = LJS.tileCollisionLoad(tileMapData, tile(0,16,1), 0, 1);
|
|
54
54
|
levelSize = tileLayers[0].size;
|
|
55
55
|
playerStartPos = vec2(0, levelSize.y); // default player start
|
|
56
56
|
foregroundTileLayer = tileLayers[0];
|
|
@@ -101,10 +101,14 @@ export class Coin extends LJS.EngineObject
|
|
|
101
101
|
|
|
102
102
|
render()
|
|
103
103
|
{
|
|
104
|
+
// side of coin
|
|
105
|
+
LJS.drawTile(this.pos, vec2(.1, .6), 0, this.color);
|
|
106
|
+
|
|
104
107
|
// make it appear to spin
|
|
105
108
|
const t = LJS.time+this.pos.x/4+this.pos.y/4;
|
|
106
|
-
|
|
107
|
-
|
|
109
|
+
const spinSize = vec2(.5+.5*Math.sin(t*2*LJS.PI), 1);
|
|
110
|
+
if (spinSize.x > .1)
|
|
111
|
+
LJS.drawTile(this.pos, spinSize, this.tileInfo, this.color);
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
update()
|
|
@@ -227,7 +231,7 @@ export class Grenade extends GameObject
|
|
|
227
231
|
|
|
228
232
|
export class Weapon extends LJS.EngineObject
|
|
229
233
|
{
|
|
230
|
-
constructor(pos
|
|
234
|
+
constructor(pos)
|
|
231
235
|
{
|
|
232
236
|
super(pos, vec2(.6), Game.spriteAtlas.gun);
|
|
233
237
|
|
|
@@ -238,10 +242,8 @@ export class Weapon extends LJS.EngineObject
|
|
|
238
242
|
this.damage = 1;
|
|
239
243
|
|
|
240
244
|
// prepare to fire
|
|
241
|
-
this.renderOrder = parent.renderOrder + 1;
|
|
242
245
|
this.fireTimeBuffer = this.localAngle = 0;
|
|
243
246
|
this.recoilTimer = new Timer;
|
|
244
|
-
parent.addChild(this, vec2(.6,0));
|
|
245
247
|
|
|
246
248
|
// shell effect
|
|
247
249
|
this.addChild(this.shellEmitter = new LJS.ParticleEmitter(
|
|
@@ -4,14 +4,38 @@ class Player extends EngineObject
|
|
|
4
4
|
{
|
|
5
5
|
super(pos, vec2(1,2), tile(8), 0, RED);
|
|
6
6
|
this.setCollision(); // make object collide
|
|
7
|
+
this.angleDamping = .95;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
update()
|
|
10
11
|
{
|
|
11
12
|
super.update();
|
|
13
|
+
|
|
14
|
+
// space ship controls
|
|
15
|
+
const moveInput = keyDirection();
|
|
16
|
+
this.applyAngularAcceleration(moveInput.x * .002);
|
|
17
|
+
this.applyAcceleration(vec2().setAngle(this.angle, moveInput.y*.002));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// explode when it collides
|
|
21
|
+
collideWithObject()
|
|
22
|
+
{
|
|
23
|
+
// don't explode if player is almost still and not tilted
|
|
24
|
+
if (abs(this.angle) < .2)
|
|
25
|
+
if (this.velocity.length() < .05)
|
|
26
|
+
return true;
|
|
12
27
|
|
|
13
|
-
|
|
14
|
-
|
|
28
|
+
this.destroy();
|
|
29
|
+
new ParticleEmitter(
|
|
30
|
+
this.pos, 0, // pos, angle
|
|
31
|
+
1, .1, 300, 3.14, // emitSize, emitTime, emitRate, emitCone
|
|
32
|
+
0, // tileInfo
|
|
33
|
+
rgb(1,.5,.1), rgb(1,.1,.1), // colorStartA, colorStartB
|
|
34
|
+
rgb(1,.5,.1,0), rgb(1,.1,.1,0), // colorEndA, colorEndB
|
|
35
|
+
.7, .8, .2, .2, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
|
|
36
|
+
.9, 1, -.2, 3.14, .05, // damp, angleDamp, gravity, particleCone, fade
|
|
37
|
+
1, 0, 1 // randomness, collide, additive
|
|
38
|
+
);
|
|
15
39
|
}
|
|
16
40
|
}
|
|
17
41
|
|
package/examples/shorts/music.js
CHANGED
|
@@ -48,7 +48,6 @@ function gameInit()
|
|
|
48
48
|
|
|
49
49
|
// stop button
|
|
50
50
|
stopButton = new UIButton(vec2(90, 30), vec2(140, 50), 'Stop');
|
|
51
|
-
musicPlayer.addChild(stopButton);
|
|
52
51
|
stopButton.onClick = ()=>
|
|
53
52
|
{
|
|
54
53
|
if (!musicInstance)
|
|
@@ -57,10 +56,11 @@ function gameInit()
|
|
|
57
56
|
// stop sound
|
|
58
57
|
musicInstance.stop();
|
|
59
58
|
};
|
|
59
|
+
musicPlayer.addChild(stopButton);
|
|
60
60
|
|
|
61
61
|
// progress bar and scrollbar for seeking
|
|
62
62
|
progressBar = new UIScrollbar(vec2(0, 100), vec2(400, 30), 0, 'Progress');
|
|
63
|
-
|
|
63
|
+
progressBar.disabledColor = RED;
|
|
64
64
|
progressBar.onChange = ()=>
|
|
65
65
|
{
|
|
66
66
|
// control music seek position
|
|
@@ -73,6 +73,7 @@ function gameInit()
|
|
|
73
73
|
if (!wasPlaying)
|
|
74
74
|
musicInstance.pause();
|
|
75
75
|
};
|
|
76
|
+
musicPlayer.addChild(progressBar);
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
function gameUpdate()
|
|
@@ -4,7 +4,7 @@ function gameInit()
|
|
|
4
4
|
|
|
5
5
|
// fire
|
|
6
6
|
new ParticleEmitter(
|
|
7
|
-
vec2(-5,-2), 0,
|
|
7
|
+
vec2(-5,-2), 0, // pos, angle
|
|
8
8
|
2, 0, 200, PI, // emitSize, emitTime, emitRate, emitCone
|
|
9
9
|
tile(0), // tileInfo
|
|
10
10
|
rgb(1,.5,.1), rgb(1,.1,.1), // colorStartA, colorStartB
|
|
@@ -16,7 +16,7 @@ function gameInit()
|
|
|
16
16
|
|
|
17
17
|
// smoke
|
|
18
18
|
new ParticleEmitter(
|
|
19
|
-
vec2(
|
|
19
|
+
vec2(5,-2), 0, // pos, angle
|
|
20
20
|
3, 0, 100, PI, // emitSize, emitTime, emitRate, emitCone
|
|
21
21
|
tile(0), // tileInfo
|
|
22
22
|
hsl(0,0,0,.5), hsl(0,0,1,.5), // colorStartA, colorStartB
|
|
@@ -31,7 +31,10 @@ function gameUpdate()
|
|
|
31
31
|
playerAngle += mouseDelta.x * .003;
|
|
32
32
|
|
|
33
33
|
// update player movement, prevent walking through walls
|
|
34
|
-
|
|
34
|
+
let velocity = keyDirection();
|
|
35
|
+
if (velocity.y && mouseIsDown(0))
|
|
36
|
+
velocity.y = 1; // forward movement with mouse
|
|
37
|
+
velocity = velocity.rotate(playerAngle).scale(.1);
|
|
35
38
|
const newPos = playerPos.add(velocity);
|
|
36
39
|
if (!levelTest(newPos.x, newPos.y))
|
|
37
40
|
playerPos = newPos;
|
|
@@ -6,27 +6,35 @@ class PuzzlePiece extends EngineObject
|
|
|
6
6
|
{
|
|
7
7
|
constructor(gridPos, size)
|
|
8
8
|
{
|
|
9
|
-
const
|
|
9
|
+
const x = gridPos.x, y = gridPos.y;
|
|
10
|
+
const color = rgb(x/(gridSize.x-1), y/(gridSize.y-1), 1);
|
|
10
11
|
super(gridPos.multiply(size), size, 0, 0, color);
|
|
11
12
|
this.gridPos = gridPos;
|
|
12
|
-
this.text =
|
|
13
|
+
this.text = x + y*gridSize.x;
|
|
14
|
+
this.moveTimer = new Timer;
|
|
15
|
+
this.lastPos = this.pos;
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
update()
|
|
16
19
|
{
|
|
20
|
+
const deltaX = emptyGridPos.x - this.gridPos.x;
|
|
21
|
+
const deltaY = emptyGridPos.y - this.gridPos.y;
|
|
17
22
|
if (mouseWasPressed(0) && isOverlapping(this.pos, this.size, mousePos))
|
|
18
|
-
if (abs(
|
|
23
|
+
if (abs(deltaX) + abs(deltaY) === 1)
|
|
19
24
|
{
|
|
20
25
|
// swap with empty space when clicked on
|
|
26
|
+
this.lastPos = this.pos;
|
|
21
27
|
this.pos = emptyGridPos.multiply(this.size);
|
|
22
28
|
[emptyGridPos, this.gridPos] = [this.gridPos, emptyGridPos];
|
|
29
|
+
this.moveTimer.set(.2);
|
|
23
30
|
}
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
render()
|
|
27
34
|
{
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
const pos = this.lastPos.lerp(this.pos, this.moveTimer.getPercent());
|
|
36
|
+
drawRect(pos, this.size, this.color);
|
|
37
|
+
drawTextOverlay(this.text, pos, 2.5, BLACK);
|
|
30
38
|
}
|
|
31
39
|
}
|
|
32
40
|
|
|
@@ -41,14 +41,14 @@ function createUI()
|
|
|
41
41
|
uiMenu.addChild(uiBackground);
|
|
42
42
|
|
|
43
43
|
// example large text
|
|
44
|
-
const textTitle = new LJS.UIText(vec2(0,-220), vec2(500,
|
|
44
|
+
const textTitle = new LJS.UIText(vec2(0,-220), vec2(500, 120), 'Test Title');
|
|
45
45
|
uiMenu.addChild(textTitle);
|
|
46
46
|
textTitle.textColor = LJS.RED;
|
|
47
47
|
textTitle.lineWidth = 4;
|
|
48
48
|
textTitle.lineColor = LJS.BLUE;
|
|
49
49
|
|
|
50
50
|
// example multiline text
|
|
51
|
-
const textTest = new LJS.UIText(vec2(-60,-120), vec2(
|
|
51
|
+
const textTest = new LJS.UIText(vec2(-60,-120), vec2(350, 60), 'Test Text\nSecond text line.')
|
|
52
52
|
uiMenu.addChild(textTest);
|
|
53
53
|
|
|
54
54
|
// example tile image
|
|
@@ -63,7 +63,7 @@ function createUI()
|
|
|
63
63
|
// example button
|
|
64
64
|
const button1 = new LJS.UIButton(vec2(0,140), vec2(350, 50), 'Test Button');
|
|
65
65
|
uiMenu.addChild(button1);
|
|
66
|
-
button1.onClick = ()=>
|
|
66
|
+
button1.onClick = ()=> LOG('Button 1 clicked');
|
|
67
67
|
|
|
68
68
|
// example checkbox
|
|
69
69
|
const checkbox = new LJS.UICheckbox(vec2(-140,-20), vec2(40));
|
|
@@ -71,7 +71,7 @@ function createUI()
|
|
|
71
71
|
checkbox.onChange = ()=> button1.disabled = checkbox.checked;
|
|
72
72
|
|
|
73
73
|
// text attached to checkbox
|
|
74
|
-
const checkboxText = new LJS.UIText(vec2(170,0), vec2(300,
|
|
74
|
+
const checkboxText = new LJS.UIText(vec2(170,0), vec2(300, 60), 'Test Checkbox');
|
|
75
75
|
checkbox.addChild(checkboxText);
|
|
76
76
|
|
|
77
77
|
// exit button
|
package/package.json
CHANGED