littlejsengine 1.7.21 → 1.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -55
- package/build/littlejs.d.ts +595 -552
- package/build/littlejs.esm.js +626 -535
- package/build/littlejs.esm.min.js +1 -1
- package/build/littlejs.js +542 -264
- package/build/littlejs.min.js +1 -1
- package/build/littlejs.release.js +542 -264
- package/examples/breakout/game.js +17 -14
- package/examples/breakout/gameObjects.js +29 -8
- package/examples/breakout/index.html +3 -3
- package/examples/breakoutTutorial/README.md +3 -3
- package/examples/breakoutTutorial/game.js +4 -4
- package/examples/breakoutTutorial/index.html +2 -2
- package/examples/electron/game.js +3 -2
- package/examples/electron/index.html +2 -2
- package/examples/empty/game.js +1 -1
- package/examples/favicon.png +0 -0
- package/examples/js13k/game.js +20 -15
- package/examples/js13k/index.html +14 -14
- package/examples/module/game.js +5 -4
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +19 -22
- package/examples/platformer/game.js +3 -3
- package/examples/platformer/gameEffects.js +21 -19
- package/examples/platformer/gameLevel.js +6 -6
- package/examples/platformer/gameObjects.js +18 -18
- package/examples/platformer/gamePlayer.js +4 -3
- package/examples/platformer/index.html +6 -6
- package/examples/platformer/tiles.png +0 -0
- package/examples/platformer/tilesLevel.png +0 -0
- package/examples/puzzle/game.js +10 -8
- package/examples/puzzle/index.html +2 -2
- package/examples/screenshot.jpg +0 -0
- package/examples/starter/game.js +32 -21
- package/examples/starter/index.html +13 -13
- package/examples/starter/tiles.png +0 -0
- package/examples/stress/index.html +4 -4
- package/examples/typescript/game.js +4 -3
- package/examples/typescript/game.ts +5 -4
- package/examples/typescript/index.html +1 -1
- package/package.json +2 -1
- package/src/engine.js +59 -52
- package/src/engineAudio.js +2 -1
- package/src/engineDraw.js +171 -55
- package/src/engineExport.js +84 -271
- package/src/engineMedals.js +13 -45
- package/src/engineObject.js +13 -13
- package/src/engineParticles.js +17 -17
- package/src/engineSettings.js +195 -2
- package/src/engineTileLayer.js +23 -22
- package/src/engineUtilities.js +6 -6
- package/src/engineWebGL.js +43 -50
package/src/engineDraw.js
CHANGED
|
@@ -47,13 +47,109 @@ let overlayContext;
|
|
|
47
47
|
* @memberof Draw */
|
|
48
48
|
let mainCanvasSize = vec2();
|
|
49
49
|
|
|
50
|
-
/**
|
|
51
|
-
* @type {
|
|
50
|
+
/** Array containing texture info for batch rendering system
|
|
51
|
+
* @type {Array}
|
|
52
52
|
* @memberof Draw */
|
|
53
|
-
|
|
53
|
+
let textureInfos = [];
|
|
54
54
|
|
|
55
55
|
// Engine internal variables not exposed to documentation
|
|
56
|
-
let
|
|
56
|
+
let drawCount;
|
|
57
|
+
|
|
58
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Create a tile info object
|
|
62
|
+
* - This can take vecs or floats for easier use and conversion
|
|
63
|
+
* - If an index is passed in, the tile size and index will determine the position
|
|
64
|
+
* @param {(Number|Vector2)} [pos=Vector2()] - Top left corner of tile in pixels or index
|
|
65
|
+
* @param {(Number|Vector2)} [size=tileSizeDefault] - Size of tile in pixels
|
|
66
|
+
* @param {Number} [textureIndex=0] - Texture index to use
|
|
67
|
+
* @return {TileInfo}
|
|
68
|
+
* @example
|
|
69
|
+
* tile(2) // a tile at index 2 using the default tile size of 16
|
|
70
|
+
* tile(5, 8) // a tile at index 5 using a tile size of 8
|
|
71
|
+
* tile(1, 16, 3) // a tile at index 1 of size 16 on texture 3
|
|
72
|
+
* tile(vec2(4,8), vec2(30,10)) // a tile at pixel location (4,8) with a size of (30,10)
|
|
73
|
+
* @memberof Draw
|
|
74
|
+
*/
|
|
75
|
+
function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0)
|
|
76
|
+
{
|
|
77
|
+
// if size is a number, make it a vector
|
|
78
|
+
if (size.x == undefined)
|
|
79
|
+
{
|
|
80
|
+
ASSERT(size > 0);
|
|
81
|
+
size = vec2(size);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// if pos is a number, use it as a tile index
|
|
85
|
+
if (pos.x == undefined)
|
|
86
|
+
{
|
|
87
|
+
const textureInfo = textureInfos[textureIndex];
|
|
88
|
+
if (textureInfo)
|
|
89
|
+
{
|
|
90
|
+
const cols = textureInfo.size.x / size.x |0;
|
|
91
|
+
pos = vec2((pos%cols)*size.x, (pos/cols|0)*size.y);
|
|
92
|
+
}
|
|
93
|
+
else
|
|
94
|
+
pos = vec2();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// return a tile info object
|
|
98
|
+
return new TileInfo(pos, size, textureIndex);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Tile Info - Stores info about how to draw a tile
|
|
103
|
+
*/
|
|
104
|
+
class TileInfo
|
|
105
|
+
{
|
|
106
|
+
/** Create a tile info object
|
|
107
|
+
* @param {Vector2} [pos=Vector2()] - Top left corner of tile in pixels
|
|
108
|
+
* @param {Vector2} [size=tileSizeDefault] - Size of tile in pixels
|
|
109
|
+
* @param {Number} [textureIndex=0] - Texture index to use
|
|
110
|
+
*/
|
|
111
|
+
constructor(pos=vec2(), size=tileSizeDefault, textureIndex=0)
|
|
112
|
+
{
|
|
113
|
+
/** @property {Vector2} - Top left corner of tile in pixels */
|
|
114
|
+
this.pos = pos;
|
|
115
|
+
/** @property {Vector2} - Size of tile in pixels */
|
|
116
|
+
this.size = size;
|
|
117
|
+
/** @property {Number} - Texture index to use */
|
|
118
|
+
this.textureIndex = textureIndex;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Returns an offset copy of this tile, useful for animation
|
|
122
|
+
* @param {Vector2} offset - Offset to apply in pixels
|
|
123
|
+
* @return {TileInfo}
|
|
124
|
+
*/
|
|
125
|
+
offset(offset)
|
|
126
|
+
{ return new TileInfo(this.pos.add(offset), this.size, this.textureIndex); }
|
|
127
|
+
|
|
128
|
+
/** Returns the texture info for this tile
|
|
129
|
+
* @return {TextureInfo}
|
|
130
|
+
*/
|
|
131
|
+
getTextureInfo()
|
|
132
|
+
{ return textureInfos[this.textureIndex]; }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Texture Info - Stores info about each texture */
|
|
136
|
+
class TextureInfo
|
|
137
|
+
{
|
|
138
|
+
// create a TextureInfo, called automatically by the engine
|
|
139
|
+
constructor(image)
|
|
140
|
+
{
|
|
141
|
+
/** @property {CanvasImageSource} - image source */
|
|
142
|
+
this.image = image;
|
|
143
|
+
/** @property {Vector2} - size of the image */
|
|
144
|
+
this.size = vec2(image.width, image.height);
|
|
145
|
+
/** @property {WebGLTexture} - webgl texture */
|
|
146
|
+
this.glTexture = glEnable && glCreateTexture(image);
|
|
147
|
+
/** @property {Vector2} - size to adjust tile to fix bleeding */
|
|
148
|
+
this.fixBleedSize = vec2(tileFixBleedScale).divide(this.size);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
57
153
|
|
|
58
154
|
/** Convert from screen to world space coordinates
|
|
59
155
|
* @param {Vector2} screenPos
|
|
@@ -84,7 +180,7 @@ function worldToScreen(worldPos)
|
|
|
84
180
|
/** Draw textured tile centered in world space, with color applied if using WebGL
|
|
85
181
|
* @param {Vector2} pos - Center of the tile in world space
|
|
86
182
|
* @param {Vector2} [size=Vector2(1,1)] - Size of the tile in world space
|
|
87
|
-
* @param {
|
|
183
|
+
* @param {TileInfo}[tileInfo] - Tile info to use, untextured if undefined
|
|
88
184
|
* @param {Vector2} [tileSize=tileSizeDefault] - Tile size in source pixels
|
|
89
185
|
* @param {Color} [color=Color()] - Color to modulate with
|
|
90
186
|
* @param {Number} [angle=0] - Angle to rotate by
|
|
@@ -92,13 +188,18 @@ function worldToScreen(worldPos)
|
|
|
92
188
|
* @param {Color} [additiveColor=Color(0,0,0,0)] - Additive color to be applied
|
|
93
189
|
* @param {Boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
|
|
94
190
|
* @param {Boolean} [screenSpace=0] - If true the pos and size are in screen space
|
|
191
|
+
* @param {CanvasRenderingContext2D} [context] - Canvas 2D context to draw to
|
|
95
192
|
* @memberof Draw */
|
|
96
|
-
function drawTile(pos, size=vec2(1),
|
|
97
|
-
angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable, screenSpace)
|
|
193
|
+
function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
|
|
194
|
+
angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable, screenSpace, context)
|
|
98
195
|
{
|
|
196
|
+
ASSERT(!context || !useWebGL); // context only supported in canvas 2D mode
|
|
197
|
+
ASSERT(typeof tileInfo !== 'number' || !tileInfo); // prevent old style calls
|
|
198
|
+
// to fix old calls, replace with tile(tileIndex, tileSize)
|
|
199
|
+
|
|
99
200
|
showWatermark && ++drawCount;
|
|
100
|
-
|
|
101
|
-
if (
|
|
201
|
+
const textureInfo = tileInfo && tileInfo.getTextureInfo();
|
|
202
|
+
if (useWebGL)
|
|
102
203
|
{
|
|
103
204
|
if (screenSpace)
|
|
104
205
|
{
|
|
@@ -106,48 +207,50 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
|
|
|
106
207
|
pos = screenToWorld(pos);
|
|
107
208
|
size = size.scale(1/cameraScale);
|
|
108
209
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// if negative tile index or image not found, force untextured
|
|
112
|
-
glDraw(pos.x, pos.y, size.x, size.y, angle, 0, 0, 0, 0, 0, color.rgbaInt());
|
|
113
|
-
}
|
|
114
|
-
else
|
|
210
|
+
|
|
211
|
+
if (textureInfo)
|
|
115
212
|
{
|
|
116
213
|
// calculate uvs and render
|
|
117
|
-
const
|
|
118
|
-
const
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
|
|
214
|
+
const x = tileInfo.pos.x / textureInfo.size.x;
|
|
215
|
+
const y = tileInfo.pos.y / textureInfo.size.y;
|
|
216
|
+
const w = tileInfo.size.x / textureInfo.size.x;
|
|
217
|
+
const h = tileInfo.size.y / textureInfo.size.y;
|
|
218
|
+
const tileImageFixBleed = textureInfo.fixBleedSize;
|
|
219
|
+
glSetTexture(textureInfo.glTexture);
|
|
122
220
|
glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
|
|
123
|
-
|
|
124
|
-
|
|
221
|
+
x + tileImageFixBleed.x, y + tileImageFixBleed.y,
|
|
222
|
+
x - tileImageFixBleed.x + w, y - tileImageFixBleed.y + h,
|
|
125
223
|
color.rgbaInt(), additiveColor.rgbaInt());
|
|
126
224
|
}
|
|
225
|
+
else
|
|
226
|
+
{
|
|
227
|
+
// if no tile info, force untextured
|
|
228
|
+
glDraw(pos.x, pos.y, size.x, size.y, angle, 0, 0, 0, 0, 0, color.rgbaInt());
|
|
229
|
+
}
|
|
127
230
|
}
|
|
128
231
|
else
|
|
129
232
|
{
|
|
130
233
|
// normal canvas 2D rendering method (slower)
|
|
131
234
|
drawCanvas2D(pos, size, angle, mirror, (context)=>
|
|
132
235
|
{
|
|
133
|
-
if (
|
|
236
|
+
if (textureInfo)
|
|
134
237
|
{
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
238
|
+
// calculate uvs and render
|
|
239
|
+
const x = tileInfo.pos.x + tileFixBleedScale;
|
|
240
|
+
const y = tileInfo.pos.y + tileFixBleedScale;
|
|
241
|
+
const w = tileInfo.size.x - 2*tileFixBleedScale;
|
|
242
|
+
const h = tileInfo.size.y - 2*tileFixBleedScale;
|
|
243
|
+
context.globalAlpha = color.a; // only alpha is supported
|
|
244
|
+
context.drawImage(textureInfo.image, x, y, w, h, -.5, -.5, 1, 1);
|
|
245
|
+
context.globalAlpha = 1; // set back to full alpha
|
|
138
246
|
}
|
|
139
247
|
else
|
|
140
248
|
{
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const sY = (tileIndex/cols|0)*tileSize.y + tileFixBleedScale;
|
|
145
|
-
const sWidth = tileSize.x - 2*tileFixBleedScale;
|
|
146
|
-
const sHeight = tileSize.y - 2*tileFixBleedScale;
|
|
147
|
-
context.globalAlpha = color.a; // only alpha is supported
|
|
148
|
-
context.drawImage(tileImage, sX, sY, sWidth, sHeight, -.5, -.5, 1, 1);
|
|
249
|
+
// if no tile info, force untextured
|
|
250
|
+
context.fillStyle = color;
|
|
251
|
+
context.fillRect(-.5, -.5, 1, 1);
|
|
149
252
|
}
|
|
150
|
-
},
|
|
253
|
+
}, screenSpace, context);
|
|
151
254
|
}
|
|
152
255
|
}
|
|
153
256
|
|
|
@@ -158,28 +261,36 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
|
|
|
158
261
|
* @param {Number} [angle=0]
|
|
159
262
|
* @param {Boolean} [useWebGL=glEnable]
|
|
160
263
|
* @param {Boolean} [screenSpace=0]
|
|
264
|
+
* @param {CanvasRenderingContext2D} [context]
|
|
161
265
|
* @memberof Draw */
|
|
162
|
-
function drawRect(pos, size, color, angle, useWebGL, screenSpace)
|
|
163
|
-
{
|
|
266
|
+
function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
|
|
267
|
+
{
|
|
268
|
+
drawTile(pos, size, undefined, color, angle, 0, undefined, useWebGL, screenSpace, context);
|
|
269
|
+
}
|
|
164
270
|
|
|
165
271
|
/** Draw colored polygon using passed in points
|
|
166
272
|
* @param {Array} points - Array of Vector2 points
|
|
167
273
|
* @param {Color} [color=Color()]
|
|
168
274
|
* @param {Boolean} [useWebGL=glEnable]
|
|
169
275
|
* @param {Boolean} [screenSpace=0]
|
|
276
|
+
* @param {CanvasRenderingContext2D} [context]
|
|
170
277
|
* @memberof Draw */
|
|
171
|
-
function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace)
|
|
278
|
+
function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace, context)
|
|
172
279
|
{
|
|
280
|
+
ASSERT(!context || !useWebGL); // context only supported in canvas 2D mode
|
|
281
|
+
|
|
173
282
|
if (useWebGL)
|
|
174
283
|
glDrawPoints(screenSpace ? points.map(screenToWorld) : points, color.rgbaInt());
|
|
175
284
|
else
|
|
176
285
|
{
|
|
177
286
|
// draw using canvas
|
|
178
|
-
|
|
179
|
-
|
|
287
|
+
if (!context)
|
|
288
|
+
context = mainContext;
|
|
289
|
+
context.fillStyle = color;
|
|
290
|
+
context.beginPath();
|
|
180
291
|
for (const point of screenSpace ? points : points.map(worldToScreen))
|
|
181
|
-
|
|
182
|
-
|
|
292
|
+
context.lineTo(point.x, point.y);
|
|
293
|
+
context.fill();
|
|
183
294
|
}
|
|
184
295
|
}
|
|
185
296
|
|
|
@@ -190,12 +301,13 @@ function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace)
|
|
|
190
301
|
* @param {Color} [color=Color()]
|
|
191
302
|
* @param {Boolean} [useWebGL=glEnable]
|
|
192
303
|
* @param {Boolean} [screenSpace=0]
|
|
304
|
+
* @param {CanvasRenderingContext2D} [context]
|
|
193
305
|
* @memberof Draw */
|
|
194
|
-
function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace)
|
|
306
|
+
function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace, context)
|
|
195
307
|
{
|
|
196
308
|
const halfDelta = vec2((posB.x - posA.x)/2, (posB.y - posA.y)/2);
|
|
197
309
|
const size = vec2(thickness, halfDelta.length()*2);
|
|
198
|
-
drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL, screenSpace);
|
|
310
|
+
drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL, screenSpace, context);
|
|
199
311
|
}
|
|
200
312
|
|
|
201
313
|
/** Draw directly to a 2d canvas context in world space
|
|
@@ -204,10 +316,10 @@ function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace)
|
|
|
204
316
|
* @param {Number} angle
|
|
205
317
|
* @param {Boolean} mirror
|
|
206
318
|
* @param {Function} drawFunction
|
|
207
|
-
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
208
319
|
* @param {Boolean} [screenSpace=0]
|
|
320
|
+
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
209
321
|
* @memberof Draw */
|
|
210
|
-
function drawCanvas2D(pos, size, angle, mirror, drawFunction, context
|
|
322
|
+
function drawCanvas2D(pos, size, angle, mirror, drawFunction, screenSpace, context=mainContext)
|
|
211
323
|
{
|
|
212
324
|
if (!screenSpace)
|
|
213
325
|
{
|
|
@@ -226,13 +338,19 @@ function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainCont
|
|
|
226
338
|
/** Enable normal or additive blend mode
|
|
227
339
|
* @param {Boolean} [additive=0]
|
|
228
340
|
* @param {Boolean} [useWebGL=glEnable]
|
|
341
|
+
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
229
342
|
* @memberof Draw */
|
|
230
|
-
function setBlendMode(additive, useWebGL=glEnable)
|
|
343
|
+
function setBlendMode(additive, useWebGL=glEnable, context)
|
|
231
344
|
{
|
|
232
|
-
|
|
233
|
-
|
|
345
|
+
ASSERT(!context || !useWebGL); // context only supported in canvas 2D mode
|
|
346
|
+
if (useWebGL)
|
|
347
|
+
glAdditive = additive;
|
|
234
348
|
else
|
|
235
|
-
|
|
349
|
+
{
|
|
350
|
+
if (!context)
|
|
351
|
+
context = mainContext;
|
|
352
|
+
context.globalCompositeOperation = additive ? 'lighter' : 'source-over';
|
|
353
|
+
}
|
|
236
354
|
}
|
|
237
355
|
|
|
238
356
|
/** Draw text on overlay canvas in world space
|
|
@@ -305,10 +423,9 @@ class FontImage
|
|
|
305
423
|
* @param {HTMLImageElement} [image] - Image for the font, if undefined default font is used
|
|
306
424
|
* @param {Vector2} [tileSize=vec2(8)] - Size of the font source tiles
|
|
307
425
|
* @param {Vector2} [paddingSize=vec2(0,1)] - How much extra space to add between characters
|
|
308
|
-
* @param {Number} [startTileIndex=0] - Tile index in image where font starts
|
|
309
426
|
* @param {CanvasRenderingContext2D} [context=overlayContext] - context to draw to
|
|
310
427
|
*/
|
|
311
|
-
constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1),
|
|
428
|
+
constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1), context=overlayContext)
|
|
312
429
|
{
|
|
313
430
|
// load default font image
|
|
314
431
|
if (!engineFontImage)
|
|
@@ -317,7 +434,6 @@ class FontImage
|
|
|
317
434
|
this.image = image || engineFontImage;
|
|
318
435
|
this.tileSize = tileSize;
|
|
319
436
|
this.paddingSize = paddingSize;
|
|
320
|
-
this.startTileIndex = startTileIndex;
|
|
321
437
|
this.context = context;
|
|
322
438
|
}
|
|
323
439
|
|
|
@@ -358,7 +474,7 @@ class FontImage
|
|
|
358
474
|
charCode = 127; // unknown character
|
|
359
475
|
|
|
360
476
|
// get the character source location and draw it
|
|
361
|
-
const tile =
|
|
477
|
+
const tile = charCode - 32;
|
|
362
478
|
const x = tile % cols;
|
|
363
479
|
const y = tile / cols |0;
|
|
364
480
|
const drawPos = pos.add(vec2(j,i).multiply(drawSize));
|
|
@@ -390,4 +506,4 @@ function toggleFullscreen()
|
|
|
390
506
|
}
|
|
391
507
|
else if (document.body.requestFullscreen)
|
|
392
508
|
document.body.requestFullscreen();
|
|
393
|
-
}
|
|
509
|
+
}
|