littlejsengine 1.16.2 → 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 +291 -246
- package/dist/littlejs.esm.js +1520 -1271
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +1178 -920
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +1170 -912
- package/examples/box2d/gameObjects.js +4 -4
- package/examples/breakout/game.js +5 -6
- package/examples/electron/index.html +2 -2
- package/examples/electron/tiles.png +0 -0
- package/examples/htmlMenu/tiles.png +0 -0
- package/examples/index.html +9 -8
- package/examples/logo.png +0 -0
- package/examples/module/build.bat +7 -0
- package/examples/module/build.js +121 -0
- package/examples/module/tiles.png +0 -0
- package/examples/platformer/game.js +1 -1
- package/examples/platformer/gameEffects.js +25 -29
- package/examples/platformer/gameLevel.js +27 -28
- 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/clock.js +3 -3
- package/examples/shorts/fontImage.js +4 -3
- package/examples/shorts/music.js +2 -2
- package/examples/shorts/musicPlayer.js +2 -2
- package/examples/shorts/parallax.js +1 -1
- package/examples/shorts/sequencer.js +1 -1
- package/examples/shorts/shapes.js +1 -1
- package/examples/shorts/texture.js +10 -6
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/tiltedView.js +2 -0
- package/examples/starter/index.html +2 -2
- package/examples/starter/tiles.png +0 -0
- package/examples/typescript/tiles.png +0 -0
- package/examples/uiSystem/game.js +1 -1
- package/examples/uiSystem/tiles.png +0 -0
- package/package.json +5 -5
- package/plugins/box2d.js +167 -63
- package/plugins/postProcess.js +47 -28
- package/plugins/uiSystem.js +18 -18
- package/plugins/zzfxm.js +2 -2
- package/reference.md +4 -3
- package/src/engine.js +182 -181
- package/src/engineAudio.js +47 -63
- package/src/engineDebug.js +8 -8
- package/src/engineDraw.js +184 -124
- package/src/engineExport.js +325 -334
- package/src/engineFont.png +0 -0
- package/src/engineInput.js +18 -24
- package/src/engineMath.js +24 -113
- package/src/engineObject.js +27 -26
- package/src/engineParticles.js +2 -2
- package/src/engineTileLayer.js +229 -192
- package/src/engineUtilities.js +100 -4
- package/src/engineWebGL.js +124 -73
package/src/engineTileLayer.js
CHANGED
|
@@ -32,7 +32,7 @@ function tileCollisionGetData(pos)
|
|
|
32
32
|
|
|
33
33
|
/** Check if a tile layer collides with another object
|
|
34
34
|
* @param {Vector2} pos
|
|
35
|
-
* @param {Vector2} [size=(
|
|
35
|
+
* @param {Vector2} [size=vec2()]
|
|
36
36
|
* @param {EngineObject} [object] - An object or undefined for generic test
|
|
37
37
|
* @param {boolean} [solidOnly] - Only check solid layers if true
|
|
38
38
|
* @return {TileCollisionLayer}
|
|
@@ -150,20 +150,20 @@ function tileLayersLoad(tileMapData, tileInfo=tile(), renderOrder=0, collisionLa
|
|
|
150
150
|
class TileLayerData
|
|
151
151
|
{
|
|
152
152
|
/** Create a tile layer data object, one for each tile in a TileLayer
|
|
153
|
-
* @param {number} [tile]
|
|
153
|
+
* @param {number} [tile] - The tile to use, untextured if undefined
|
|
154
154
|
* @param {number} [direction] - Integer direction of tile, in 90 degree increments
|
|
155
|
-
* @param {boolean} [mirror]
|
|
156
|
-
* @param {Color} [color]
|
|
155
|
+
* @param {boolean} [mirror] - If the tile should be mirrored along the x axis
|
|
156
|
+
* @param {Color} [color] - Color of the tile */
|
|
157
157
|
constructor(tile, direction=0, mirror=false, color=new Color)
|
|
158
158
|
{
|
|
159
|
-
/** @property {number}
|
|
160
|
-
this.tile
|
|
161
|
-
/** @property {number}
|
|
159
|
+
/** @property {number} - The tile to use, untextured if undefined */
|
|
160
|
+
this.tile = tile;
|
|
161
|
+
/** @property {number} - Integer direction of tile, in 90 degree increments */
|
|
162
162
|
this.direction = direction;
|
|
163
163
|
/** @property {boolean} - If the tile should be mirrored along the x axis */
|
|
164
|
-
this.mirror
|
|
165
|
-
/** @property {Color}
|
|
166
|
-
this.color
|
|
164
|
+
this.mirror = mirror;
|
|
165
|
+
/** @property {Color} - Color of the tile */
|
|
166
|
+
this.color = color.copy();
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
/** Set this tile to clear, it will not be rendered */
|
|
@@ -174,7 +174,7 @@ class TileLayerData
|
|
|
174
174
|
/**
|
|
175
175
|
* Canvas Layer - cached off screen rendering system
|
|
176
176
|
* - Contains an offscreen canvas that can be rendered to
|
|
177
|
-
* - WebGL rendering is optional, call
|
|
177
|
+
* - WebGL rendering is optional, call updateWebGL to enable/update
|
|
178
178
|
* @extends EngineObject
|
|
179
179
|
* @memberof TileLayers
|
|
180
180
|
* @example
|
|
@@ -183,29 +183,27 @@ class TileLayerData
|
|
|
183
183
|
class CanvasLayer extends EngineObject
|
|
184
184
|
{
|
|
185
185
|
/** Create a canvas layer object
|
|
186
|
-
* @param {Vector2} [
|
|
186
|
+
* @param {Vector2} [pos] - World space position of the layer
|
|
187
187
|
* @param {Vector2} [size] - World space size of the layer
|
|
188
188
|
* @param {number} [angle] - Angle the layer is rotated by
|
|
189
189
|
* @param {number} [renderOrder] - Objects sorted by renderOrder
|
|
190
190
|
* @param {Vector2} [canvasSize] - Default size of canvas, can be changed later
|
|
191
|
+
* @param {boolean} [useWebGL] - Should this layer use WebGL for rendering
|
|
191
192
|
*/
|
|
192
|
-
constructor(
|
|
193
|
+
constructor(pos, size, angle=0, renderOrder=0, canvasSize=vec2(512), useWebGL=true)
|
|
193
194
|
{
|
|
194
195
|
ASSERT(isVector2(canvasSize), 'canvasSize must be a Vector2');
|
|
195
|
-
super(
|
|
196
|
+
super(pos, size, undefined, angle, WHITE, renderOrder);
|
|
196
197
|
|
|
197
198
|
/** @property {HTMLCanvasElement} - The canvas used by this layer */
|
|
198
199
|
this.canvas = headlessMode ? undefined : new OffscreenCanvas(canvasSize.x, canvasSize.y);
|
|
199
200
|
/** @property {OffscreenCanvasRenderingContext2D} - The 2D canvas context used by this layer */
|
|
200
201
|
this.context = this.canvas?.getContext('2d');
|
|
201
202
|
/** @property {TextureInfo} - Texture info to use for this object rendering */
|
|
202
|
-
const useWebGL = false; // do not use webgl by default
|
|
203
203
|
this.textureInfo = new TextureInfo(this.canvas, useWebGL);
|
|
204
|
-
/** @property {boolean} - True if WebGL texture needs to be refreshed */
|
|
205
|
-
this.refreshWebGL = false;
|
|
206
204
|
|
|
207
205
|
// disable physics by default
|
|
208
|
-
this.mass =
|
|
206
|
+
this.mass = 0;
|
|
209
207
|
}
|
|
210
208
|
|
|
211
209
|
/** Destroy this canvas layer */
|
|
@@ -220,7 +218,7 @@ class CanvasLayer extends EngineObject
|
|
|
220
218
|
// Render the layer, called automatically by the engine
|
|
221
219
|
render()
|
|
222
220
|
{
|
|
223
|
-
this.draw(this.pos, this.size, this.
|
|
221
|
+
this.draw(this.pos, this.size, this.color, this.angle, this.mirror, this.additiveColor);
|
|
224
222
|
}
|
|
225
223
|
|
|
226
224
|
/** Draw this canvas layer centered in world space, with color applied if using WebGL
|
|
@@ -233,103 +231,54 @@ class CanvasLayer extends EngineObject
|
|
|
233
231
|
* @param {boolean} [screenSpace] - If true the pos and size are in screen space
|
|
234
232
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context] - Canvas 2D context to draw to
|
|
235
233
|
* @memberof Draw */
|
|
236
|
-
draw(pos, size,
|
|
234
|
+
draw(pos, size, color=WHITE, angle=0, mirror=false, additiveColor, screenSpace=false, context)
|
|
237
235
|
{
|
|
238
|
-
const useWebGL = glEnable && this.textureInfo.hasWebGL();
|
|
239
|
-
if (useWebGL && this.refreshWebGL)
|
|
240
|
-
{
|
|
241
|
-
// update the WebGL texture
|
|
242
|
-
this.textureInfo.createWebGLTexture();
|
|
243
|
-
this.refreshWebGL = false;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
236
|
// draw the canvas layer as a single tile that uses the whole texture
|
|
247
237
|
const tileInfo = new TileInfo().setFullImage(this.textureInfo);
|
|
238
|
+
const useWebGL = this.hasWebGL();
|
|
248
239
|
drawTile(pos, size, tileInfo, color, angle, mirror, additiveColor, useWebGL, screenSpace, context);
|
|
249
240
|
}
|
|
250
241
|
|
|
251
|
-
/**
|
|
252
|
-
* @callback Canvas2DDrawCallback - Function that draws to a canvas 2D context
|
|
253
|
-
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} context
|
|
254
|
-
* @memberof TileLayers
|
|
255
|
-
*/
|
|
256
|
-
|
|
257
|
-
/** Draw onto the layer canvas in world space (bypass WebGL)
|
|
258
|
-
* @param {Vector2} pos
|
|
259
|
-
* @param {Vector2} size
|
|
260
|
-
* @param {number} angle
|
|
261
|
-
* @param {boolean} mirror
|
|
262
|
-
* @param {Canvas2DDrawCallback} drawFunction */
|
|
263
|
-
drawCanvas2D(pos, size, angle, mirror, drawFunction)
|
|
264
|
-
{
|
|
265
|
-
if (!this.context) return;
|
|
266
|
-
|
|
267
|
-
const context = this.context;
|
|
268
|
-
context.save();
|
|
269
|
-
pos = pos.subtract(this.pos).multiply(this.tileInfo.size);
|
|
270
|
-
size = size.multiply(this.tileInfo.size);
|
|
271
|
-
context.translate(pos.x, this.canvas.height - pos.y);
|
|
272
|
-
context.rotate(angle);
|
|
273
|
-
context.scale(mirror ? -size.x : size.x, size.y);
|
|
274
|
-
drawFunction(context);
|
|
275
|
-
context.restore();
|
|
276
|
-
}
|
|
277
|
-
|
|
278
242
|
/** Draw a tile onto the layer canvas in world space
|
|
279
243
|
* @param {Vector2} pos
|
|
280
|
-
* @param {Vector2} [size=(1
|
|
244
|
+
* @param {Vector2} [size=vec2(1)]
|
|
281
245
|
* @param {TileInfo} [tileInfo]
|
|
282
|
-
* @param {Color} [color=
|
|
283
|
-
* @param {number} [angle
|
|
284
|
-
* @param {boolean} [mirror
|
|
285
|
-
drawTile(pos, size=vec2(1), tileInfo, color=new Color, angle, mirror)
|
|
246
|
+
* @param {Color} [color=WHITE]
|
|
247
|
+
* @param {number} [angle]
|
|
248
|
+
* @param {boolean} [mirror] */
|
|
249
|
+
drawTile(pos, size=vec2(1), tileInfo, color=new Color, angle=0, mirror=false)
|
|
286
250
|
{
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
// untextured
|
|
301
|
-
context.fillStyle = color.toString();
|
|
302
|
-
context.fillRect(-.5, -.5, 1, 1);
|
|
303
|
-
}
|
|
304
|
-
});
|
|
251
|
+
pos = pos.subtract(this.pos).multiply(this.tileInfo.size);
|
|
252
|
+
size = size.multiply(this.tileInfo.size);
|
|
253
|
+
pos.y = this.canvas.height - pos.y;
|
|
254
|
+
|
|
255
|
+
// draw the tile onto the layer canvas
|
|
256
|
+
const oldMainCanvasSize = mainCanvasSize;
|
|
257
|
+
mainCanvasSize = vec2(this.canvas.width, this.canvas.height);
|
|
258
|
+
const useWebGL = this.hasWebGL();
|
|
259
|
+
useWebGL && glSetRenderTarget(this.textureInfo.glTexture);
|
|
260
|
+
const drawContext = useWebGL ? undefined : this.context;
|
|
261
|
+
drawTile(pos, size, tileInfo, color, angle, mirror, undefined, useWebGL, true, drawContext);
|
|
262
|
+
useWebGL && glSetRenderTarget();
|
|
263
|
+
mainCanvasSize = oldMainCanvasSize;
|
|
305
264
|
}
|
|
306
265
|
|
|
307
266
|
/** Draw a rectangle onto the layer canvas in world space
|
|
308
267
|
* @param {Vector2} pos
|
|
309
|
-
* @param {Vector2} [size=(1
|
|
310
|
-
* @param {Color} [color=
|
|
311
|
-
* @param {number} [angle
|
|
268
|
+
* @param {Vector2} [size=vec2(1)]
|
|
269
|
+
* @param {Color} [color=WHITE]
|
|
270
|
+
* @param {number} [angle] */
|
|
312
271
|
drawRect(pos, size, color, angle)
|
|
313
272
|
{ this.drawTile(pos, size, undefined, color, angle); }
|
|
314
273
|
|
|
315
|
-
/** Create
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
*/
|
|
319
|
-
useWebGL(enable=true, immediate=false)
|
|
320
|
-
{
|
|
321
|
-
if (!immediate && enable && this.textureInfo.hasWebGL())
|
|
322
|
-
{
|
|
323
|
-
// refresh the texture when needed
|
|
324
|
-
this.refreshWebGL = true;
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
274
|
+
/** Create WebGL texture if necessary and copy layer canvas to it */
|
|
275
|
+
updateWebGL()
|
|
276
|
+
{ this.textureInfo.createWebGLTexture(); }
|
|
327
277
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
278
|
+
/** Check if this layer is using WebGL
|
|
279
|
+
* @return {boolean} */
|
|
280
|
+
hasWebGL()
|
|
281
|
+
{ return glEnable && this.textureInfo.hasWebGL(); }
|
|
333
282
|
}
|
|
334
283
|
|
|
335
284
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -348,59 +297,93 @@ class CanvasLayer extends EngineObject
|
|
|
348
297
|
class TileLayer extends CanvasLayer
|
|
349
298
|
{
|
|
350
299
|
/** Create a tile layer object
|
|
351
|
-
* @param {Vector2}
|
|
352
|
-
* @param {Vector2} size
|
|
353
|
-
* @param {TileInfo} [tileInfo]
|
|
300
|
+
* @param {Vector2} pos - World space position
|
|
301
|
+
* @param {Vector2} size - World space size
|
|
302
|
+
* @param {TileInfo} [tileInfo] - Default tile info for layer (used for size and texture)
|
|
354
303
|
* @param {number} [renderOrder] - Objects are sorted by renderOrder
|
|
304
|
+
* @param {boolean} [useWebGL] - Should this layer use WebGL for rendering
|
|
355
305
|
*/
|
|
356
|
-
constructor(
|
|
306
|
+
constructor(pos, size, tileInfo=tile(), renderOrder=0, useWebGL=true)
|
|
357
307
|
{
|
|
358
308
|
const canvasSize = tileInfo ? size.multiply(tileInfo.size) : size;
|
|
359
|
-
super(
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
this.tileInfo =
|
|
363
|
-
|
|
364
|
-
// init tile data
|
|
309
|
+
super(pos, size, 0, renderOrder, canvasSize, useWebGL);
|
|
310
|
+
|
|
311
|
+
/** @property {TileInfo} - Default tile info for layer */
|
|
312
|
+
this.tileInfo = undefined;
|
|
313
|
+
/** @property {Array<TileLayerData>} - Default tile info for layer */
|
|
365
314
|
this.data = [];
|
|
366
|
-
|
|
367
|
-
|
|
315
|
+
/** @property {boolean} - Is this layer using a webgl texture? */
|
|
316
|
+
this.isUsingWebGL = false;
|
|
368
317
|
|
|
369
318
|
if (headlessMode)
|
|
370
319
|
{
|
|
371
|
-
// disable rendering
|
|
372
|
-
this.
|
|
373
|
-
this.
|
|
374
|
-
this.redrawStart
|
|
375
|
-
this.redrawEnd
|
|
376
|
-
this.drawTileData
|
|
377
|
-
this.
|
|
378
|
-
this.
|
|
320
|
+
// disable rendering in headless mode
|
|
321
|
+
this.render = ()=> {};
|
|
322
|
+
this.redraw = ()=> {};
|
|
323
|
+
this.redrawStart = ()=> {};
|
|
324
|
+
this.redrawEnd = ()=> {};
|
|
325
|
+
this.drawTileData = ()=> {};
|
|
326
|
+
this.redrawTileData = ()=> {};
|
|
327
|
+
this.drawLayerTile = ()=> {};
|
|
328
|
+
this.drawLayerRect = ()=> {};
|
|
329
|
+
this.clearLayerRect = ()=> {};
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (tileInfo)
|
|
334
|
+
{
|
|
335
|
+
// set tile info
|
|
336
|
+
this.tileInfo = tileInfo.frame(0);
|
|
337
|
+
this.tileInfo.bleed = 0; // disable bleed for tile layers
|
|
379
338
|
}
|
|
339
|
+
|
|
340
|
+
// init tile data
|
|
341
|
+
for (let j = this.size.area(); j--;)
|
|
342
|
+
this.data.push(new TileLayerData);
|
|
380
343
|
}
|
|
381
344
|
|
|
382
345
|
/** Set data at a given position in the array
|
|
383
346
|
* @param {Vector2} layerPos - Local position in array
|
|
384
|
-
* @param {TileLayerData} data
|
|
347
|
+
* @param {TileLayerData} data - Data to set
|
|
385
348
|
* @param {boolean} [redraw] - Force the tile to redraw if true */
|
|
386
349
|
setData(layerPos, data, redraw=false)
|
|
387
350
|
{
|
|
351
|
+
layerPos = layerPos.floor();
|
|
388
352
|
ASSERT(isVector2(layerPos), 'layerPos must be a Vector2');
|
|
389
353
|
ASSERT(data instanceof TileLayerData, 'data must be a TileLayerData');
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
354
|
+
|
|
355
|
+
if (!layerPos.arrayCheck(this.size)) return;
|
|
356
|
+
this.data[(layerPos.y|0)*this.size.x+layerPos.x|0] = data;
|
|
357
|
+
|
|
358
|
+
if (!redraw) return;
|
|
359
|
+
const isRedraw = drawContext === this.context;
|
|
360
|
+
isRedraw ? this.drawTileData(layerPos) : this.redrawTileData(layerPos);
|
|
395
361
|
}
|
|
396
362
|
|
|
363
|
+
/** Clear data at a given position in the array
|
|
364
|
+
* @param {Vector2} layerPos - Local position in array
|
|
365
|
+
* @param {boolean} [redraw] - Force the tile to redraw if true */
|
|
366
|
+
clearData(layerPos, redraw=false)
|
|
367
|
+
{ this.setData(layerPos, new TileLayerData, redraw) }
|
|
368
|
+
|
|
397
369
|
/** Get data at a given position in the array
|
|
398
370
|
* @param {Vector2} layerPos - Local position in array
|
|
399
371
|
* @return {TileLayerData} */
|
|
400
372
|
getData(layerPos)
|
|
401
373
|
{
|
|
402
374
|
ASSERT(isVector2(layerPos), 'layerPos must be a Vector2');
|
|
403
|
-
return layerPos.arrayCheck(this.size) && this.data[(layerPos.y|0)*this.size.x+layerPos.x|0];
|
|
375
|
+
return layerPos.arrayCheck(this.size) && this.data[(layerPos.y|0)*this.size.x+layerPos.x|0];
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Update the tile layer, refresh texture if needed
|
|
379
|
+
update()
|
|
380
|
+
{
|
|
381
|
+
if (!glEnable && this.isUsingWebGL)
|
|
382
|
+
{
|
|
383
|
+
// redraw the layer if webgl was disabled or context lost
|
|
384
|
+
this.isUsingWebGL = false;
|
|
385
|
+
this.redraw();
|
|
386
|
+
}
|
|
404
387
|
}
|
|
405
388
|
|
|
406
389
|
// Render the tile layer, called automatically by the engine
|
|
@@ -408,40 +391,35 @@ class TileLayer extends CanvasLayer
|
|
|
408
391
|
{
|
|
409
392
|
ASSERT(drawContext !== this.context, 'must call redrawEnd() after drawing tiles!');
|
|
410
393
|
|
|
411
|
-
if (this.refreshWebGL)
|
|
412
|
-
{
|
|
413
|
-
// update the WebGL texture
|
|
414
|
-
this.textureInfo.createWebGLTexture();
|
|
415
|
-
this.refreshWebGL = false;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// draw the tile layer as a single tile
|
|
419
|
-
const tileInfo = new TileInfo().setFullImage(this.textureInfo);
|
|
420
394
|
const size = this.drawSize || this.size;
|
|
421
395
|
const pos = this.pos.add(size.scale(.5));
|
|
422
|
-
|
|
423
|
-
drawTile(pos, size, tileInfo, WHITE, 0, false, CLEAR_BLACK, useWebGL);
|
|
396
|
+
this.draw(pos, this.size, this.color, this.angle, this.mirror, this.additiveColor);
|
|
424
397
|
}
|
|
425
398
|
|
|
399
|
+
/** Called after this layer is redrawn, does nothing by default */
|
|
400
|
+
onRedraw() {}
|
|
401
|
+
|
|
426
402
|
/** Draw all the tile data to an offscreen canvas
|
|
427
|
-
* - This may be slow
|
|
403
|
+
* - This may be slow if not using webgl but only needs to be done once */
|
|
428
404
|
redraw()
|
|
429
405
|
{
|
|
430
406
|
this.redrawStart(true);
|
|
431
407
|
for (let x = this.size.x; x--;)
|
|
432
408
|
for (let y = this.size.y; y--;)
|
|
433
409
|
this.drawTileData(vec2(x,y), false);
|
|
410
|
+
this.isUsingWebGL && glFlush();
|
|
411
|
+
this.onRedraw();
|
|
434
412
|
this.redrawEnd();
|
|
435
|
-
this.useWebGL();
|
|
436
413
|
}
|
|
437
414
|
|
|
438
415
|
/** Call to start the redraw process
|
|
439
|
-
* - This can be used to manually update
|
|
416
|
+
* - This can be used to manually update parts of the level
|
|
440
417
|
* @param {boolean} [clear] - Should it clear the canvas before drawing */
|
|
441
418
|
redrawStart(clear=false)
|
|
442
419
|
{
|
|
443
420
|
if (!this.context) return;
|
|
444
|
-
|
|
421
|
+
ASSERT(drawContext !== this.context);
|
|
422
|
+
|
|
445
423
|
// save current render settings
|
|
446
424
|
/** @type {[CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D, Vector2, Vector2, number, Color]} */
|
|
447
425
|
this.savedRenderSettings = [drawContext, mainCanvasSize, cameraPos, cameraScale, canvasClearColor];
|
|
@@ -449,39 +427,42 @@ class TileLayer extends CanvasLayer
|
|
|
449
427
|
// set the draw canvas and context to this layer
|
|
450
428
|
// use camera settings to match this layer's canvas
|
|
451
429
|
drawContext = this.context;
|
|
452
|
-
|
|
453
|
-
const tileSize = this.tileInfo ? this.tileInfo.size : vec2(1);
|
|
454
|
-
cameraScale = tileSize.x;
|
|
455
|
-
canvasClearColor = CLEAR_BLACK;
|
|
430
|
+
const tileSize = this.tileInfo?.size ?? vec2(1);
|
|
456
431
|
mainCanvasSize = this.size.multiply(tileSize);
|
|
457
|
-
|
|
432
|
+
canvasClearColor = CLEAR_BLACK;
|
|
433
|
+
cameraPos = this.size.multiply(tileSize).scale(.5);
|
|
434
|
+
cameraScale = 1;
|
|
435
|
+
|
|
436
|
+
// set render target to this layer
|
|
437
|
+
this.isUsingWebGL = this.hasWebGL();
|
|
438
|
+
if (this.isUsingWebGL)
|
|
439
|
+
glSetRenderTarget(this.textureInfo.glTexture, clear);
|
|
440
|
+
else
|
|
458
441
|
{
|
|
459
|
-
//
|
|
460
|
-
this.
|
|
461
|
-
|
|
442
|
+
// disable smoothing for pixel art
|
|
443
|
+
this.context.imageSmoothingEnabled = !tilesPixelated;
|
|
444
|
+
if (clear)
|
|
445
|
+
{
|
|
446
|
+
// clear and set size
|
|
447
|
+
this.canvas.width = mainCanvasSize.x;
|
|
448
|
+
this.canvas.height = mainCanvasSize.y;
|
|
449
|
+
}
|
|
462
450
|
}
|
|
463
|
-
|
|
464
|
-
// disable smoothing for pixel art
|
|
465
|
-
drawContext.imageSmoothingEnabled = !tilesPixelated;
|
|
466
|
-
|
|
467
|
-
// setup gl rendering if enabled
|
|
468
|
-
glPreRender();
|
|
469
451
|
}
|
|
470
452
|
|
|
471
453
|
/** Call to end the redraw process */
|
|
472
454
|
redrawEnd()
|
|
473
455
|
{
|
|
474
456
|
if (!this.context) return;
|
|
475
|
-
|
|
476
|
-
ASSERT(drawContext === this.context, 'must call redrawStart() before drawing tiles');
|
|
477
|
-
glCopyToContext(drawContext);
|
|
478
|
-
//saveCanvas(this.canvas);
|
|
457
|
+
ASSERT(drawContext === this.context);
|
|
479
458
|
|
|
480
459
|
// set stuff back to normal
|
|
460
|
+
if (this.isUsingWebGL)
|
|
461
|
+
glSetRenderTarget();
|
|
481
462
|
[drawContext, mainCanvasSize, cameraPos, cameraScale, canvasClearColor] = this.savedRenderSettings;
|
|
482
463
|
}
|
|
483
464
|
|
|
484
|
-
/** Draw the tile at a given position in the tile
|
|
465
|
+
/** Draw the tile at a given position in the tile layer
|
|
485
466
|
* This can be used to clear out tiles when they are destroyed
|
|
486
467
|
* Tiles can also be redrawn if inside a redrawStart/End block
|
|
487
468
|
* @param {Vector2} layerPos
|
|
@@ -490,24 +471,75 @@ class TileLayer extends CanvasLayer
|
|
|
490
471
|
drawTileData(layerPos, clear=true)
|
|
491
472
|
{
|
|
492
473
|
if (!this.context) return;
|
|
474
|
+
ASSERT(drawContext === this.context, 'must call redrawStart() before drawing tiles');
|
|
493
475
|
|
|
494
|
-
// clear out where the tile was, for
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
const pos = layerPos.multiply(s);
|
|
499
|
-
this.context.clearRect(pos.x, this.canvas.height-pos.y, s.x, -s.y);
|
|
500
|
-
}
|
|
476
|
+
// clear out where the tile was, can be skipped for fully opaque tiles
|
|
477
|
+
const drawSize = this.tileInfo?.size ?? vec2(1);
|
|
478
|
+
const drawPos = layerPos.multiply(drawSize);
|
|
479
|
+
clear && this.clearLayerRect(drawPos, drawSize);
|
|
501
480
|
|
|
502
481
|
// draw the tile if it has layer data
|
|
503
482
|
const d = this.getData(layerPos);
|
|
504
|
-
if (d.tile
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
483
|
+
if (!d.tile) return;
|
|
484
|
+
|
|
485
|
+
const tileInfo = this.tileInfo && this.tileInfo.tile(d.tile);
|
|
486
|
+
this.drawLayerTile(drawPos, drawSize, tileInfo, d.color, d.direction*PI/2, d.mirror);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/** Draw the tile at a given position in the tile layer
|
|
490
|
+
* This can be used to clear tiles when they are destroyed
|
|
491
|
+
* For better performance use drawTileData inside a redrawStart/End block
|
|
492
|
+
* @param {Vector2} layerPos
|
|
493
|
+
* @param {boolean} [clear] - should the old tile be cleared
|
|
494
|
+
*/
|
|
495
|
+
redrawTileData(layerPos, clear=true)
|
|
496
|
+
{
|
|
497
|
+
if (!this.context) return;
|
|
498
|
+
ASSERT(drawContext !== this.context, 'redrawStart() should not be active when calling redrawTileData(), instead use drawTileData()');
|
|
499
|
+
|
|
500
|
+
this.redrawStart();
|
|
501
|
+
this.drawTileData(layerPos, clear);
|
|
502
|
+
this.redrawEnd();
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/** Draw textured tile in layer space
|
|
506
|
+
* @param {Vector2} pos - Position in pixel coordinates
|
|
507
|
+
* @param {Vector2} [size=vec2(1)] - Size of the tile
|
|
508
|
+
* @param {TileInfo} [tileInfo] - Tile info to use, untextured if undefined
|
|
509
|
+
* @param {Color} [color=WHITE] - Color to modulate with
|
|
510
|
+
* @param {number} [angle] - Angle to rotate by
|
|
511
|
+
* @param {boolean} [mirror] - Is image flipped along the Y axis?
|
|
512
|
+
* @param {Color} [additiveColor] - Additive color to be applied if any */
|
|
513
|
+
drawLayerTile(pos, size=vec2(1), tileInfo, color=WHITE,
|
|
514
|
+
angle=0, mirror, additiveColor)
|
|
515
|
+
{
|
|
516
|
+
const drawPos = pos.add(size.scale(.5));
|
|
517
|
+
drawTile(drawPos, size, tileInfo, color, angle, mirror, additiveColor, this.isUsingWebGL);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/** Clear a rectangle in layer space
|
|
521
|
+
* @param {Vector2} pos
|
|
522
|
+
* @param {Vector2} size
|
|
523
|
+
* @param {Color} [color=WHITE] - Color to modulate with
|
|
524
|
+
* @param {number} [angle] - Angle to rotate by
|
|
525
|
+
*/
|
|
526
|
+
drawLayerRect(pos, size, color, angle=0)
|
|
527
|
+
{ this.drawLayerTile(pos, size, undefined, color, angle); }
|
|
528
|
+
|
|
529
|
+
/** Clear a rectangle in layer space
|
|
530
|
+
* @param {Vector2} pos - position in pixel coordinates
|
|
531
|
+
* @param {Vector2} size
|
|
532
|
+
*/
|
|
533
|
+
clearLayerRect(pos, size)
|
|
534
|
+
{
|
|
535
|
+
ASSERT(drawContext === this.context, 'must call redrawStart() before clearing tiles');
|
|
536
|
+
|
|
537
|
+
const x = pos.x, y = this.canvas.height - pos.y - size.y;
|
|
538
|
+
const useWebGL = this.hasWebGL();
|
|
539
|
+
if (useWebGL)
|
|
540
|
+
glClearRect(x, y, size.x, size.y);
|
|
541
|
+
else
|
|
542
|
+
this.context.clearRect(x, y, size.x, size.y);
|
|
511
543
|
}
|
|
512
544
|
}
|
|
513
545
|
|
|
@@ -516,21 +548,21 @@ class TileLayer extends CanvasLayer
|
|
|
516
548
|
* Tile Collision Layer - a tile layer with collision
|
|
517
549
|
* - adds collision data and functions to TileLayer
|
|
518
550
|
* - there can be multiple tile collision layers
|
|
519
|
-
* - tile collision layers should not overlap each other
|
|
520
551
|
* @extends TileLayer
|
|
521
552
|
* @memberof TileLayers
|
|
522
553
|
*/
|
|
523
554
|
class TileCollisionLayer extends TileLayer
|
|
524
555
|
{
|
|
525
556
|
/** Create a tile layer object
|
|
526
|
-
* @param {Vector2}
|
|
527
|
-
* @param {Vector2} size
|
|
528
|
-
* @param {TileInfo} [tileInfo]
|
|
557
|
+
* @param {Vector2} pos - World space position
|
|
558
|
+
* @param {Vector2} size - World space size
|
|
559
|
+
* @param {TileInfo} [tileInfo] - Tile info for layer
|
|
529
560
|
* @param {number} [renderOrder] - Objects are sorted by renderOrder
|
|
561
|
+
* @param {boolean} [useWebGL] - Should this layer use WebGL for rendering
|
|
530
562
|
*/
|
|
531
|
-
constructor(
|
|
563
|
+
constructor(pos, size, tileInfo=tile(), renderOrder=0, useWebGL=true)
|
|
532
564
|
{
|
|
533
|
-
super(
|
|
565
|
+
super(pos, size.floor(), tileInfo, renderOrder, useWebGL);
|
|
534
566
|
|
|
535
567
|
/** @property {Array<number>} - The tile collision grid */
|
|
536
568
|
this.collisionData = [];
|
|
@@ -566,29 +598,34 @@ class TileCollisionLayer extends TileLayer
|
|
|
566
598
|
this.collisionData.fill(0);
|
|
567
599
|
}
|
|
568
600
|
|
|
569
|
-
/** Set tile collision data for a given cell in the
|
|
570
|
-
* @param {Vector2}
|
|
601
|
+
/** Set tile collision data for a given cell in the layer
|
|
602
|
+
* @param {Vector2} layerPos
|
|
571
603
|
* @param {number} [data] */
|
|
572
|
-
setCollisionData(
|
|
604
|
+
setCollisionData(layerPos, data=1)
|
|
573
605
|
{
|
|
574
|
-
ASSERT(isVector2(
|
|
575
|
-
const i = (
|
|
576
|
-
|
|
606
|
+
ASSERT(isVector2(layerPos), 'layerPos must be a Vector2');
|
|
607
|
+
const i = (layerPos.y|0)*this.size.x + layerPos.x|0;
|
|
608
|
+
layerPos.arrayCheck(this.size) && (this.collisionData[i] = data);
|
|
577
609
|
}
|
|
578
610
|
|
|
579
|
-
/**
|
|
580
|
-
* @param {Vector2}
|
|
611
|
+
/** Clear tile collision data for a given cell in the layer
|
|
612
|
+
* @param {Vector2} layerPos */
|
|
613
|
+
clearCollisionData(layerPos)
|
|
614
|
+
{ this.setCollisionData(layerPos, 0); }
|
|
615
|
+
|
|
616
|
+
/** Get tile collision data for a given cell in the layer
|
|
617
|
+
* @param {Vector2} layerPos
|
|
581
618
|
* @return {number} */
|
|
582
|
-
getCollisionData(
|
|
619
|
+
getCollisionData(layerPos)
|
|
583
620
|
{
|
|
584
|
-
ASSERT(isVector2(
|
|
585
|
-
const i = (
|
|
586
|
-
return
|
|
621
|
+
ASSERT(isVector2(layerPos), 'layerPos must be a Vector2');
|
|
622
|
+
const i = (layerPos.y|0)*this.size.x + layerPos.x|0;
|
|
623
|
+
return layerPos.arrayCheck(this.size) ? this.collisionData[i] : 0;
|
|
587
624
|
}
|
|
588
625
|
|
|
589
626
|
/** Check if collision with another object should occur
|
|
590
627
|
* @param {Vector2} pos
|
|
591
|
-
* @param {Vector2} [size=(
|
|
628
|
+
* @param {Vector2} [size=vec2()]
|
|
592
629
|
* @param {EngineObject} [object]
|
|
593
630
|
* @return {boolean} */
|
|
594
631
|
collisionTest(pos, size=new Vector2, object)
|