littlejsengine 1.1.17 → 1.2.0
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 +13 -3
- package/build.bat +1 -0
- package/engine/engine.all.js +520 -522
- package/engine/engine.all.min.js +1 -1
- package/engine/engine.all.release.js +444 -278
- package/engine/engine.js +68 -33
- package/engine/engineAudio.js +21 -7
- package/engine/engineBuild.bat +9 -1
- package/engine/engineBuildSetup.bat +2 -1
- package/engine/engineDebug.js +80 -246
- package/engine/engineDraw.js +106 -21
- package/engine/engineInput.js +89 -52
- package/engine/engineMedals.js +14 -17
- package/engine/engineObject.js +14 -23
- package/engine/engineParticles.js +3 -3
- package/engine/engineRelease.js +3 -1
- package/engine/engineSettings.js +39 -29
- package/engine/engineTileLayer.js +26 -24
- package/engine/engineUtilities.js +14 -12
- package/engine/engineWebGL.js +47 -56
- package/engine/index.d.ts +1612 -0
- package/examples/breakout/game.js +9 -7
- package/examples/breakout/gameObjects.js +1 -1
- package/examples/breakout/index.html +6 -4
- package/examples/platformer/game.js +2 -2
- package/examples/platformer/gameEffects.js +8 -11
- package/examples/platformer/gameLevel.js +14 -7
- package/examples/platformer/gameObjects.js +1 -1
- package/examples/platformer/gamePlayer.js +13 -8
- package/examples/platformer/index.html +9 -7
- package/examples/platformer/tiles.png +0 -0
- package/examples/puzzle/game.js +1 -1
- package/examples/puzzle/index.html +5 -3
- package/examples/stress/index.html +6 -4
- package/game.js +5 -4
- package/index.html +16 -14
- package/package.json +1 -1
package/engine/engineDebug.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
LittleJS - Debug Build
|
|
3
|
+
MIT License - Copyright 2021 Frank Force
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* LittleJS Debug System
|
|
3
|
-
* <br> -
|
|
8
|
+
* <br> - Press ~ to show debug overlay with mouse pick
|
|
9
|
+
* <br> - Number keys toggle debug functions
|
|
10
|
+
* <br> - +/- apply time scale
|
|
4
11
|
* <br> - Debug primitive rendering
|
|
5
|
-
* <br> - Save
|
|
12
|
+
* <br> - Save a 2d canvas as an image
|
|
6
13
|
* @namespace Debug
|
|
7
14
|
*/
|
|
8
15
|
|
|
@@ -34,7 +41,7 @@ let showWatermark = 1;
|
|
|
34
41
|
let godMode = 0;
|
|
35
42
|
|
|
36
43
|
// Engine internal variables not exposed to documentation
|
|
37
|
-
let debugPrimitives = [], debugOverlay = 0, debugPhysics = 0, debugRaycast = 0,
|
|
44
|
+
let debugPrimitives = [], debugOverlay = 0, debugPhysics = 0, debugRaycast = 0,
|
|
38
45
|
debugParticles = 0, debugGamepads = 0, debugMedals = 0, debugTakeScreenshot, downloadLink;
|
|
39
46
|
|
|
40
47
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -156,22 +163,25 @@ const debugUpdate = ()=>
|
|
|
156
163
|
|
|
157
164
|
if (keyWasPressed(192)) // ~
|
|
158
165
|
debugOverlay = !debugOverlay;
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
166
|
+
if (debugOverlay)
|
|
167
|
+
{
|
|
168
|
+
if (keyWasPressed(48)) // 0
|
|
169
|
+
showWatermark = !showWatermark;
|
|
170
|
+
if (keyWasPressed(49)) // 1
|
|
171
|
+
debugPhysics = !debugPhysics, debugParticles = 0;
|
|
172
|
+
if (keyWasPressed(50)) // 2
|
|
173
|
+
debugParticles = !debugParticles, debugPhysics = 0;
|
|
174
|
+
if (keyWasPressed(51)) // 3
|
|
175
|
+
debugGamepads = !debugGamepads;
|
|
176
|
+
if (keyWasPressed(52)) // 4
|
|
177
|
+
godMode = !godMode;
|
|
178
|
+
if (keyWasPressed(53)) // 5
|
|
179
|
+
debugTakeScreenshot = 1;
|
|
180
|
+
//if (keyWasPressed(54)) // 6
|
|
181
|
+
//if (keyWasPressed(55)) // 7
|
|
182
|
+
//if (keyWasPressed(56)) // 8
|
|
183
|
+
//if (keyWasPressed(57)) // 9
|
|
184
|
+
}
|
|
175
185
|
}
|
|
176
186
|
|
|
177
187
|
const debugRender = ()=>
|
|
@@ -191,21 +201,20 @@ const debugRender = ()=>
|
|
|
191
201
|
|
|
192
202
|
if (debugGamepads && gamepadsEnable && navigator.getGamepads)
|
|
193
203
|
{
|
|
194
|
-
//
|
|
204
|
+
// gamepad debug display
|
|
195
205
|
const gamepads = navigator.getGamepads();
|
|
196
206
|
for (let i = gamepads.length; i--;)
|
|
197
207
|
{
|
|
198
208
|
const gamepad = gamepads[i];
|
|
199
209
|
if (gamepad)
|
|
200
210
|
{
|
|
201
|
-
// gamepad debug display
|
|
202
211
|
const stickScale = 1;
|
|
203
212
|
const buttonScale = .2;
|
|
204
213
|
const centerPos = cameraPos;
|
|
205
214
|
const sticks = stickData[i];
|
|
206
215
|
for (let j = sticks.length; j--;)
|
|
207
216
|
{
|
|
208
|
-
const drawPos = centerPos.add(vec2(j*stickScale*2,i*stickScale*3));
|
|
217
|
+
const drawPos = centerPos.add(vec2(j*stickScale*2, i*stickScale*3));
|
|
209
218
|
const stickPos = drawPos.add(sticks[j].scale(stickScale));
|
|
210
219
|
debugCircle(drawPos, stickScale, '#fff7',0,1);
|
|
211
220
|
debugLine(drawPos, stickPos, '#f00');
|
|
@@ -224,38 +233,36 @@ const debugRender = ()=>
|
|
|
224
233
|
|
|
225
234
|
if (debugOverlay)
|
|
226
235
|
{
|
|
236
|
+
// mouse pick
|
|
237
|
+
let bestDistance = Infinity, bestObject;
|
|
227
238
|
for (const o of engineObjects)
|
|
228
239
|
{
|
|
229
|
-
if (o.canvas)
|
|
240
|
+
if (o.canvas || o.destroyed)
|
|
230
241
|
continue; // skip tile layers
|
|
231
242
|
|
|
232
243
|
const size = o.size.copy();
|
|
233
|
-
size.x
|
|
234
|
-
|
|
244
|
+
if (!size.x || !size.y)
|
|
245
|
+
continue;
|
|
246
|
+
|
|
247
|
+
const distance = mousePos.distanceSquared(o.pos);
|
|
248
|
+
if (distance < bestDistance)
|
|
249
|
+
{
|
|
250
|
+
bestDistance = distance;
|
|
251
|
+
bestObject = o
|
|
252
|
+
}
|
|
235
253
|
|
|
254
|
+
// show object info
|
|
236
255
|
const color = new Color(
|
|
237
256
|
o.collideTiles?1:0,
|
|
238
257
|
o.collideSolidObjects?1:0,
|
|
239
258
|
o.isSolid?1:0,
|
|
240
259
|
o.parent ? .2 : .5);
|
|
241
|
-
|
|
242
|
-
|
|
260
|
+
size.x = max(size.x, .2);
|
|
261
|
+
size.y = max(size.y, .2);
|
|
243
262
|
drawRect(o.pos, size, color);
|
|
244
263
|
drawRect(o.pos, size.scale(.8), o.parent ? new Color(1,1,1,.5) : new Color(0,0,0,.8));
|
|
245
264
|
o.parent && drawLine(o.pos, o.parent.pos, .1, new Color(0,0,1,.5));
|
|
246
265
|
}
|
|
247
|
-
|
|
248
|
-
// mouse pick
|
|
249
|
-
let bestDistance = Infinity, bestObject;
|
|
250
|
-
for (const o of engineObjects)
|
|
251
|
-
{
|
|
252
|
-
const distance = mousePos.distanceSquared(o.pos);
|
|
253
|
-
if (distance < bestDistance)
|
|
254
|
-
{
|
|
255
|
-
bestDistance = distance;
|
|
256
|
-
bestObject = o
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
266
|
|
|
260
267
|
if (bestObject)
|
|
261
268
|
{
|
|
@@ -275,7 +282,8 @@ const debugRender = ()=>
|
|
|
275
282
|
pos = pos.add(height), ...args);
|
|
276
283
|
drawText('vel = ' + printVec2(bestObject.velocity), pos = pos.add(height), ...args);
|
|
277
284
|
drawText('size = ' + printVec2(bestObject.size), pos = pos.add(height), ...args);
|
|
278
|
-
drawText('
|
|
285
|
+
drawText('type = ' + ( bestObject.constructor.name), pos = mousePos.subtract(height), ...args);
|
|
286
|
+
drawText('collision = ' + getTileCollisionData(mousePos), pos = mousePos.subtract(height.scale(2)), ...args);
|
|
279
287
|
mainContext = saveContext;
|
|
280
288
|
}
|
|
281
289
|
|
|
@@ -283,16 +291,15 @@ const debugRender = ()=>
|
|
|
283
291
|
}
|
|
284
292
|
|
|
285
293
|
{
|
|
286
|
-
//
|
|
287
|
-
overlayContext.
|
|
294
|
+
// draw debug primitives
|
|
295
|
+
overlayContext.save();
|
|
296
|
+
overlayContext.lineWidth = 2;
|
|
288
297
|
const pointSize = debugPointSize * cameraScale;
|
|
289
298
|
debugPrimitives.forEach(p=>
|
|
290
299
|
{
|
|
291
300
|
// create canvas transform from world space to screen space
|
|
292
301
|
const pos = worldToScreen(p.pos);
|
|
293
302
|
|
|
294
|
-
overlayContext.save();
|
|
295
|
-
overlayContext.lineWidth = 2;
|
|
296
303
|
overlayContext.translate(pos.x|0, pos.y|0);
|
|
297
304
|
overlayContext.rotate(p.angle);
|
|
298
305
|
overlayContext.fillStyle = overlayContext.strokeStyle = p.color;
|
|
@@ -325,15 +332,17 @@ const debugRender = ()=>
|
|
|
325
332
|
p.fill && overlayContext.fill();
|
|
326
333
|
overlayContext.stroke();
|
|
327
334
|
}
|
|
328
|
-
|
|
329
|
-
overlayContext.restore();
|
|
330
335
|
});
|
|
331
336
|
|
|
332
|
-
|
|
337
|
+
// remove expired pritives
|
|
338
|
+
debugPrimitives = debugPrimitives.filter(r=>r.time.get()<0);
|
|
339
|
+
|
|
340
|
+
overlayContext.restore();
|
|
333
341
|
}
|
|
334
342
|
|
|
335
343
|
{
|
|
336
|
-
|
|
344
|
+
// draw debug overlay
|
|
345
|
+
overlayContext.save();
|
|
337
346
|
overlayContext.fillStyle = '#fff';
|
|
338
347
|
overlayContext.textAlign = 'left';
|
|
339
348
|
overlayContext.textBaseline = 'top';
|
|
@@ -341,6 +350,7 @@ const debugRender = ()=>
|
|
|
341
350
|
overlayContext.shadowColor = '#000';
|
|
342
351
|
overlayContext.shadowBlur = 9;
|
|
343
352
|
|
|
353
|
+
let x = 9, y = -20, h = 30;
|
|
344
354
|
if (debugOverlay)
|
|
345
355
|
{
|
|
346
356
|
overlayContext.fillText(engineName, x, y += h);
|
|
@@ -353,214 +363,38 @@ const debugRender = ()=>
|
|
|
353
363
|
overlayContext.fillText('1: Debug Physics', x, y += h);
|
|
354
364
|
overlayContext.fillStyle = debugParticles ? '#f00' : '#fff';
|
|
355
365
|
overlayContext.fillText('2: Debug Particles', x, y += h);
|
|
366
|
+
overlayContext.fillStyle = debugGamepads ? '#f00' : '#fff';
|
|
367
|
+
overlayContext.fillText('3: Debug Gamepads', x, y += h);
|
|
356
368
|
overlayContext.fillStyle = godMode ? '#f00' : '#fff';
|
|
357
|
-
overlayContext.fillText('
|
|
369
|
+
overlayContext.fillText('4: God Mode', x, y += h);
|
|
358
370
|
overlayContext.fillStyle = '#fff';
|
|
359
371
|
overlayContext.fillText('5: Save Screenshot', x, y += h);
|
|
360
|
-
//overlayContext.fillStyle = debugParticleEditor ? '#f00' : '#fff';
|
|
361
|
-
//overlayContext.fillText('6: Particle Editor', x, y += h);
|
|
362
|
-
overlayContext.fillStyle = debugGamepads ? '#f00' : '#fff';
|
|
363
|
-
overlayContext.fillText('7: Debug Gamepads', x, y += h);
|
|
364
|
-
}
|
|
365
|
-
else
|
|
366
|
-
{
|
|
367
|
-
overlayContext.fillText(debugPhysics ? 'Debug Physics' : '', x, y += h);
|
|
368
|
-
overlayContext.fillText(debugParticles ? 'Debug Particles' : '', x, y += h);
|
|
369
|
-
overlayContext.fillText(godMode ? 'God Mode' : '', x, y += h);
|
|
370
|
-
overlayContext.fillText(debugGamepads ? 'Debug Gamepads' : '', x, y += h);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
overlayContext.shadowBlur = 0;
|
|
374
|
-
}
|
|
375
372
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
380
|
-
// particle system editor (work in progress)
|
|
381
|
-
let debugParticleEditor = 0, debugParticleSystem, debugParticleSystemDiv, particleSystemCode;
|
|
382
|
-
|
|
383
|
-
const debugToggleParticleEditor = ()=>
|
|
384
|
-
{
|
|
385
|
-
debugParticleEditor = !debugParticleEditor;
|
|
386
|
-
|
|
387
|
-
if (debugParticleEditor)
|
|
388
|
-
{
|
|
389
|
-
if (!debugParticleSystem || debugParticleSystem.destroyed)
|
|
390
|
-
debugParticleSystem = new ParticleEmitter(cameraPos);
|
|
391
|
-
}
|
|
392
|
-
else if (debugParticleSystem && !debugParticleSystem.destroyed)
|
|
393
|
-
debugParticleSystem.destroy();
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const colorToHex = (color)=>
|
|
397
|
-
{
|
|
398
|
-
const componentToHex = (c)=>
|
|
399
|
-
{
|
|
400
|
-
const hex = (c*255|0).toString(16);
|
|
401
|
-
return hex.length == 1 ? '0' + hex : hex;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
return '#' + componentToHex(color.r) + componentToHex(color.g) + componentToHex(color.b);
|
|
405
|
-
}
|
|
406
|
-
const hexToColor = (hex)=>
|
|
407
|
-
{
|
|
408
|
-
return new Color(
|
|
409
|
-
parseInt(hex.substr(1,2), 16)/255,
|
|
410
|
-
parseInt(hex.substr(3,2), 16)/255,
|
|
411
|
-
parseInt(hex.substr(5,2), 16)/255)
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
if (!debugParticleSystemDiv)
|
|
415
|
-
{
|
|
416
|
-
const div = debugParticleSystemDiv = document.createElement('div');
|
|
417
|
-
div.innerHTML = '<big><b>Particle Editor';
|
|
418
|
-
div.style = 'position:absolute;top:10;left:10;color:#fff';
|
|
419
|
-
document.body.appendChild(div);
|
|
420
|
-
|
|
421
|
-
for ( const setting of debugParticleSettings)
|
|
422
|
-
{
|
|
423
|
-
const input = setting[2] = document.createElement('input');
|
|
424
|
-
const name = setting[0];
|
|
425
|
-
const type = setting[1];
|
|
426
|
-
if (type)
|
|
373
|
+
let keysPressed = '';
|
|
374
|
+
for(const i in inputData[0])
|
|
427
375
|
{
|
|
428
|
-
if (
|
|
429
|
-
|
|
430
|
-
input.type = type;
|
|
431
|
-
const color = debugParticleSystem[name];
|
|
432
|
-
input.value = colorToHex(color);
|
|
433
|
-
}
|
|
434
|
-
else if (type == 'alpha' && name == 'colorStartAlpha')
|
|
435
|
-
input.value = debugParticleSystem.colorStartA.a;
|
|
436
|
-
else if (type == 'alpha' && name == 'colorEndAlpha')
|
|
437
|
-
input.value = debugParticleSystem.colorEndA.a;
|
|
438
|
-
else if (name == 'tileSizeX')
|
|
439
|
-
input.value = debugParticleSystem.tileSize.x;
|
|
440
|
-
else if (name == 'tileSizeY')
|
|
441
|
-
input.value = debugParticleSystem.tileSize.y;
|
|
376
|
+
if (i && keyIsDown(i, 0))
|
|
377
|
+
keysPressed += i + ' ' ;
|
|
442
378
|
}
|
|
443
|
-
|
|
444
|
-
input.value = debugParticleSystem[name] || '0';
|
|
379
|
+
keysPressed && overlayContext.fillText('Keys Down: ' + keysPressed, x, y += h);
|
|
445
380
|
|
|
446
|
-
|
|
381
|
+
let buttonsPressed = '';
|
|
382
|
+
if (inputData[1])
|
|
383
|
+
for(const i in inputData[1])
|
|
447
384
|
{
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
{
|
|
451
|
-
if (type == 'color')
|
|
452
|
-
{
|
|
453
|
-
const color = hexToColor(input.value);
|
|
454
|
-
debugParticleSystem[name].r = color.r;
|
|
455
|
-
debugParticleSystem[name].g = color.g;
|
|
456
|
-
debugParticleSystem[name].b = color.b;
|
|
457
|
-
}
|
|
458
|
-
else if (type == 'alpha' && name == 'colorStartAlpha')
|
|
459
|
-
{
|
|
460
|
-
debugParticleSystem.colorStartA.a = clamp(inputFloat);
|
|
461
|
-
debugParticleSystem.colorStartB.a = clamp(inputFloat);
|
|
462
|
-
}
|
|
463
|
-
else if (type == 'alpha' && name == 'colorEndAlpha')
|
|
464
|
-
{
|
|
465
|
-
debugParticleSystem.colorEndA.a = clamp(inputFloat);
|
|
466
|
-
debugParticleSystem.colorEndB.a = clamp(inputFloat);
|
|
467
|
-
}
|
|
468
|
-
else if (name == 'tileSizeX')
|
|
469
|
-
{
|
|
470
|
-
debugParticleSystem.tileSize = vec2(parseInt(input.value), debugParticleSystem.tileSize.y);
|
|
471
|
-
}
|
|
472
|
-
else if (name == 'tileSizeY')
|
|
473
|
-
{
|
|
474
|
-
debugParticleSystem.tileSize.y = vec2(debugParticleSystem.tileSize.x, parseInt(input.value));
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
else
|
|
478
|
-
debugParticleSystem[name] = inputFloat;
|
|
479
|
-
|
|
480
|
-
updateCode();
|
|
385
|
+
if (i && keyIsDown(i, 1))
|
|
386
|
+
buttonsPressed += i + ' ' ;
|
|
481
387
|
}
|
|
482
|
-
|
|
483
|
-
div.appendChild(input);
|
|
484
|
-
div.appendChild(document.createTextNode(' ' + name));
|
|
388
|
+
buttonsPressed && overlayContext.fillText('Gamepad: ' + buttonsPressed, x, y += h);
|
|
485
389
|
}
|
|
486
|
-
|
|
487
|
-
div.appendChild(document.createElement('br'));
|
|
488
|
-
div.appendChild(document.createElement('br'));
|
|
489
|
-
div.appendChild(particleSystemCode = document.createElement('input'));
|
|
490
|
-
particleSystemCode.disabled = true;
|
|
491
|
-
div.appendChild(document.createTextNode(' code'));
|
|
492
|
-
|
|
493
|
-
div.appendChild(document.createElement('br'));
|
|
494
|
-
const button = document.createElement('button')
|
|
495
|
-
div.appendChild(button);
|
|
496
|
-
button.innerHTML = 'Copy To Clipboard';
|
|
497
|
-
|
|
498
|
-
button.onclick = (e)=> navigator.clipboard.writeText(particleSystemCode.value);
|
|
499
|
-
|
|
500
|
-
const updateCode = ()=>
|
|
390
|
+
else
|
|
501
391
|
{
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
const name = setting[0];
|
|
507
|
-
const type = setting[1];
|
|
508
|
-
let value;
|
|
509
|
-
if (name == 'tileSizeX' || type == 'alpha')
|
|
510
|
-
continue;
|
|
511
|
-
|
|
512
|
-
if (count++)
|
|
513
|
-
code += ', ';
|
|
514
|
-
|
|
515
|
-
if (name == 'tileSizeY')
|
|
516
|
-
{
|
|
517
|
-
value = `vec2(${debugParticleSystem.tileSize.x},${debugParticleSystem.tileSize.y})`;
|
|
518
|
-
}
|
|
519
|
-
else if (type == 'color')
|
|
520
|
-
{
|
|
521
|
-
const c = debugParticleSystem[name];
|
|
522
|
-
value = `new Color(${c.r},${c.g},${c.b},${c.a})`;
|
|
523
|
-
}
|
|
524
|
-
else
|
|
525
|
-
value = debugParticleSystem[name];
|
|
526
|
-
code += value;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
particleSystemCode.value = '...[' + code + ']';
|
|
392
|
+
overlayContext.fillText(debugPhysics ? 'Debug Physics' : '', x, y += h);
|
|
393
|
+
overlayContext.fillText(debugParticles ? 'Debug Particles' : '', x, y += h);
|
|
394
|
+
overlayContext.fillText(godMode ? 'God Mode' : '', x, y += h);
|
|
395
|
+
overlayContext.fillText(debugGamepads ? 'Debug Gamepads' : '', x, y += h);
|
|
530
396
|
}
|
|
531
|
-
|
|
397
|
+
|
|
398
|
+
overlayContext.restore();
|
|
532
399
|
}
|
|
533
|
-
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
const debugParticleSettings =
|
|
537
|
-
[
|
|
538
|
-
['emitSize'],
|
|
539
|
-
['emitTime'],
|
|
540
|
-
['emitRate'],
|
|
541
|
-
['emitConeAngle'],
|
|
542
|
-
['tileIndex'],
|
|
543
|
-
['tileSizeX', 'tileSize'],
|
|
544
|
-
['tileSizeY', 'tileSize'],
|
|
545
|
-
['colorStartA', 'color'],
|
|
546
|
-
['colorStartB', 'color'],
|
|
547
|
-
['colorStartAlpha', 'alpha'],
|
|
548
|
-
['colorEndA', 'color'],
|
|
549
|
-
['colorEndB', 'color'],
|
|
550
|
-
['colorEndAlpha', 'alpha'],
|
|
551
|
-
['particleTime'],
|
|
552
|
-
['sizeStart'],
|
|
553
|
-
['sizeEnd'],
|
|
554
|
-
['speed'],
|
|
555
|
-
['angleSpeed'],
|
|
556
|
-
['damping'],
|
|
557
|
-
['angleDamping'],
|
|
558
|
-
['gravityScale'],
|
|
559
|
-
['particleConeAngle'],
|
|
560
|
-
['fadeRate'],
|
|
561
|
-
['randomness'],
|
|
562
|
-
['collideTiles'],
|
|
563
|
-
['additive'],
|
|
564
|
-
['randomColorComponents'],
|
|
565
|
-
['renderOrder'],
|
|
566
|
-
];
|
|
400
|
+
}
|
package/engine/engineDraw.js
CHANGED
|
@@ -92,17 +92,13 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
|
|
|
92
92
|
{
|
|
93
93
|
// calculate uvs and render
|
|
94
94
|
const cols = tileImageSize.x / tileSize.x |0;
|
|
95
|
-
const uvSizeX = tileSize.x
|
|
96
|
-
const uvSizeY = tileSize.y
|
|
95
|
+
const uvSizeX = tileSize.x / tileImageSize.x;
|
|
96
|
+
const uvSizeY = tileSize.y / tileImageSize.y;
|
|
97
97
|
const uvX = (tileIndex%cols)*uvSizeX, uvY = (tileIndex/cols|0)*uvSizeY;
|
|
98
|
-
|
|
99
|
-
// shrink uvs to prevent bleeding
|
|
100
|
-
const shrinkTilesX = tileBleedShrinkFix * tileImageSizeInverse.x;
|
|
101
|
-
const shrinkTilesY = tileBleedShrinkFix * tileImageSizeInverse.y;
|
|
102
98
|
|
|
103
99
|
glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
|
|
104
|
-
uvX +
|
|
105
|
-
uvX -
|
|
100
|
+
uvX + tileImageFixBleed.x, uvY + tileImageFixBleed.y,
|
|
101
|
+
uvX - tileImageFixBleed.x + uvSizeX, uvY - tileImageFixBleed.y + uvSizeY,
|
|
106
102
|
color.rgbaInt(), additiveColor.rgbaInt());
|
|
107
103
|
}
|
|
108
104
|
}
|
|
@@ -121,10 +117,10 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
|
|
|
121
117
|
{
|
|
122
118
|
// calculate uvs and render
|
|
123
119
|
const cols = tileImageSize.x / tileSize.x |0;
|
|
124
|
-
const sX = (tileIndex%cols)*tileSize.x +
|
|
125
|
-
const sY = (tileIndex/cols|0)*tileSize.y +
|
|
126
|
-
const sWidth = tileSize.x - 2*
|
|
127
|
-
const sHeight = tileSize.y - 2*
|
|
120
|
+
const sX = (tileIndex%cols)*tileSize.x + tileFixBleedScale;
|
|
121
|
+
const sY = (tileIndex/cols|0)*tileSize.y + tileFixBleedScale;
|
|
122
|
+
const sWidth = tileSize.x - 2*tileFixBleedScale;
|
|
123
|
+
const sHeight = tileSize.y - 2*tileFixBleedScale;
|
|
128
124
|
context.globalAlpha = color.a; // only alpha is supported
|
|
129
125
|
context.drawImage(tileImage, sX, sY, sWidth, sHeight, -.5, -.5, 1, 1);
|
|
130
126
|
}
|
|
@@ -207,6 +203,18 @@ function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainCont
|
|
|
207
203
|
context.restore();
|
|
208
204
|
}
|
|
209
205
|
|
|
206
|
+
/** Enable normal or additive blend mode
|
|
207
|
+
* @param {Boolean} [additive=0]
|
|
208
|
+
* @param {Boolean} [useWebGL=glEnable]
|
|
209
|
+
* @memberof Draw */
|
|
210
|
+
function setBlendMode(additive, useWebGL=glEnable)
|
|
211
|
+
{
|
|
212
|
+
if (glEnable && useWebGL)
|
|
213
|
+
glSetBlendMode(additive);
|
|
214
|
+
else
|
|
215
|
+
mainContext.globalCompositeOperation = additive ? 'lighter' : 'source-over';
|
|
216
|
+
}
|
|
217
|
+
|
|
210
218
|
/** Draw text on overlay canvas in world space
|
|
211
219
|
* @param {String} text
|
|
212
220
|
* @param {Vector2} pos
|
|
@@ -232,16 +240,93 @@ function drawText(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new
|
|
|
232
240
|
overlayContext.fillText(text, pos.x, pos.y);
|
|
233
241
|
}
|
|
234
242
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
*
|
|
239
|
-
|
|
243
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Font Image Object - Draw text on a 2D canvas by using characters in an image
|
|
247
|
+
* <br> - 96 characters (from space to tilde) are stored in an image
|
|
248
|
+
* <br> - Uses a default 8x8 font if none is supplied
|
|
249
|
+
* <br> - You can also use fonts from the main tile sheet
|
|
250
|
+
* @example
|
|
251
|
+
* // use built in font
|
|
252
|
+
* const font = new ImageFont;
|
|
253
|
+
*
|
|
254
|
+
* // draw text
|
|
255
|
+
* font.drawTextScreen("LittleJS\nHello World!", vec2(200, 50));
|
|
256
|
+
*/
|
|
257
|
+
class FontImage
|
|
240
258
|
{
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
259
|
+
/** Create an image font
|
|
260
|
+
* @param {Image} [image] - The image the font is stored in, if undefined the default font is used
|
|
261
|
+
* @param {Vector2} [tileSize=vec2(8)] - The size of the font source tiles
|
|
262
|
+
* @param {Vector2} [paddingSize=vec2(0,1)] - How much extra space to add between characters
|
|
263
|
+
* @param {Number} [startTileIndex=0] - Tile index in image where font starts
|
|
264
|
+
* @param {CanvasRenderingContext2D} [context=overlayContext] - context to draw to
|
|
265
|
+
*/
|
|
266
|
+
constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1), startTileIndex=0, context=overlayContext)
|
|
267
|
+
{
|
|
268
|
+
if (!image)
|
|
269
|
+
{
|
|
270
|
+
// use default font image
|
|
271
|
+
image = new Image();
|
|
272
|
+
image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6MCIBdFY+Q0PMNgf0yCgsSAaZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWw1hPWNRcEyWh2npdpBmSUBrRaN1WSlQAWXaWLF0kkwR7C/N7XUvIaQr4xpeqeQigjLwBRZ/6KkufAACcv5z7GYhvgWHII8xN/4C2hvLCkmZSVgIJMHNTxpYOsJOiitEjUQnIQAFFP+opoQfCbjWmfzWiNzCjEvxAPFARmw/Y5Te0sl2zEp4M+m7cToJjdJS7y1xcFlFT7EtWBZ8nl7uLSff7UgYewtlyY6yHM4RrjNrnsfn/W0DBK9xNZctZ7gsTeXTe5eqLqXFlKnAn+vkNXzH6TqPW10ksKoSlauKk1TcncZLSTxNnQ8Av/8RGPXOFIuMCZ/fpwIZx5vU4QIRQ44HwUyHx/QrZhm5VtXFex7ja2se0KBpnPT0DSwS4xd86uAy+SqnLBgkPY5JolhJ33ENyK6n0VyRzCnzebIkFdY/NUtM66lTdhix1KUss6q5snH5ftVJXG0QITb1gUDvzD3z/BbyOLMirwCtPzAAAAAElFTkSuQmCC';
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
this.image = image;
|
|
276
|
+
this.tileSize = tileSize;
|
|
277
|
+
this.paddingSize = paddingSize;
|
|
278
|
+
this.startTileIndex = startTileIndex;
|
|
279
|
+
this.context = context;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** Draw text in screen space using the image font
|
|
283
|
+
* @param {String} text
|
|
284
|
+
* @param {Vector2} pos
|
|
285
|
+
* @param {Number} [scale=4]
|
|
286
|
+
* @param {Boolean} [center]
|
|
287
|
+
*/
|
|
288
|
+
drawTextScreen(text, pos, scale=4, center)
|
|
289
|
+
{
|
|
290
|
+
const context = this.context;
|
|
291
|
+
context.save();
|
|
292
|
+
context.imageSmoothingEnabled = !cavasPixelated;
|
|
293
|
+
|
|
294
|
+
const size = this.tileSize;
|
|
295
|
+
const drawSize = size.add(this.paddingSize).scale(scale);
|
|
296
|
+
const cols = this.image.width / this.tileSize.x |0;
|
|
297
|
+
text.split('\n').forEach((line, i)=>
|
|
298
|
+
{
|
|
299
|
+
const centerOffset = center ? line.length * size.x * scale / 2 |0 : 0;
|
|
300
|
+
for(let j=line.length; j--;)
|
|
301
|
+
{
|
|
302
|
+
// draw each character
|
|
303
|
+
let charCode = line[j].charCodeAt();
|
|
304
|
+
if (charCode < 32 || charCode > 127)
|
|
305
|
+
charCode = 127; // unknown character
|
|
306
|
+
|
|
307
|
+
// get the character source location and draw it
|
|
308
|
+
const tile = this.startTileIndex + charCode - 32;
|
|
309
|
+
const x = tile % cols;
|
|
310
|
+
const y = tile / cols |0;
|
|
311
|
+
const drawPos = pos.add(vec2(j,i).multiply(drawSize));
|
|
312
|
+
context.drawImage(this.image, x * size.x, y * size.y, size.x, size.y,
|
|
313
|
+
drawPos.x - centerOffset, drawPos.y, size.x * scale, size.y * scale);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
context.restore();
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** Draw text in world space using the image font
|
|
321
|
+
* @param {String} text
|
|
322
|
+
* @param {Vector2} pos
|
|
323
|
+
* @param {Number} [scale=.25]
|
|
324
|
+
* @param {Boolean} [center]
|
|
325
|
+
*/
|
|
326
|
+
drawText(text, pos, scale=1, center)
|
|
327
|
+
{
|
|
328
|
+
this.drawTextScreen(text, worldToScreen(pos).floor(), scale*cameraScale|0, center);
|
|
329
|
+
}
|
|
245
330
|
}
|
|
246
331
|
|
|
247
332
|
///////////////////////////////////////////////////////////////////////////////
|