littlejsengine 1.8.6 → 1.8.9

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.
Files changed (38) hide show
  1. package/README.md +9 -3
  2. package/build/littlejs.d.ts +18 -9
  3. package/build/littlejs.esm.js +298 -92
  4. package/build/littlejs.esm.min.js +1 -1
  5. package/build/littlejs.js +296 -92
  6. package/build/littlejs.min.js +1 -1
  7. package/build/littlejs.release.js +296 -92
  8. package/examples/breakout/game.js +3 -0
  9. package/examples/breakout/index.html +3 -3
  10. package/examples/breakoutTutorial/index.html +2 -2
  11. package/examples/electron/game.js +3 -0
  12. package/examples/electron/index.html +2 -2
  13. package/examples/js13k/index.html +13 -13
  14. package/examples/logo.png +0 -0
  15. package/examples/module/game.js +3 -0
  16. package/examples/module/index.html +1 -1
  17. package/examples/particles/index.html +1 -1
  18. package/examples/platformer/game.js +3 -0
  19. package/examples/platformer/gameEffects.js +1 -1
  20. package/examples/platformer/index.html +6 -6
  21. package/examples/puzzle/game.js +3 -0
  22. package/examples/puzzle/index.html +2 -2
  23. package/examples/starter/game.js +4 -1
  24. package/examples/starter/index.html +13 -13
  25. package/examples/starter/tiles.png +0 -0
  26. package/examples/stress/index.html +3 -1
  27. package/examples/typescript/game.js +2 -0
  28. package/examples/typescript/game.ts +3 -0
  29. package/examples/typescript/index.html +1 -1
  30. package/package.json +1 -1
  31. package/src/engine.js +189 -9
  32. package/src/engineAudio.js +72 -58
  33. package/src/engineDraw.js +1 -1
  34. package/src/engineExport.js +2 -0
  35. package/src/engineParticles.js +7 -7
  36. package/src/engineSettings.js +11 -0
  37. package/src/engineUtilities.js +4 -5
  38. package/src/engineWebGL.js +12 -12
@@ -631,11 +631,10 @@ class Color
631
631
  * @return {Number} */
632
632
  rgbaInt()
633
633
  {
634
- const toByte = (c)=> clamp(c)*255|0;
635
- const r = toByte(this.r);
636
- const g = toByte(this.g)<<8;
637
- const b = toByte(this.b)<<16;
638
- const a = toByte(this.a)<<24;
634
+ const r = clamp(this.r)*255|0;
635
+ const g = clamp(this.g)*255<<8;
636
+ const b = clamp(this.b)*255<<16;
637
+ const a = clamp(this.a)*255<<24;
639
638
  return r + g + b + a;
640
639
  }
641
640
  }
@@ -743,6 +742,12 @@ let canvasPixelated = 1;
743
742
  * @memberof Settings */
744
743
  let fontDefault = 'arial';
745
744
 
745
+ /** Enable to show the LittleJS splash screen be shown on startup
746
+ * @type {Boolean}
747
+ * @default
748
+ * @memberof Settings */
749
+ let showSplashScreen = 0;
750
+
746
751
  ///////////////////////////////////////////////////////////////////////////////
747
752
  // WebGL settings
748
753
 
@@ -976,6 +981,11 @@ function setCanvasPixelated(pixelated) { canvasPixelated = pixelated; }
976
981
  * @memberof Settings */
977
982
  function setFontDefault(font) { fontDefault = font; }
978
983
 
984
+ /** Set if the LittleJS splash screen be shown on startup
985
+ * @param {Boolean} show
986
+ * @memberof Settings */
987
+ function setShowSplashScreen(show) { showSplashScreen = show; }
988
+
979
989
  /** Set if webgl rendering is enabled
980
990
  * @param {Boolean} enable
981
991
  * @memberof Settings */
@@ -1567,7 +1577,7 @@ let mainCanvasSize = vec2();
1567
1577
  * @memberof Draw */
1568
1578
  let textureInfos = [];
1569
1579
 
1570
- // Engine internal variables not exposed to documentation
1580
+ // Keep track of how many draw calls there were each frame for debugging
1571
1581
  let drawCount;
1572
1582
 
1573
1583
  ///////////////////////////////////////////////////////////////////////////////
@@ -2809,7 +2819,7 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0, sampleRate
2809
2819
  }
2810
2820
 
2811
2821
  ///////////////////////////////////////////////////////////////////////////////
2812
- // ZzFXMicro - Zuper Zmall Zound Zynth - v1.2.0 by Frank Force
2822
+ // ZzFXMicro - Zuper Zmall Zound Zynth - v1.3.0 by Frank Force
2813
2823
 
2814
2824
  /** Generate and play a ZzFX sound
2815
2825
  *
@@ -2845,6 +2855,7 @@ const zzfxR = 44100;
2845
2855
  * @param {Number} [sustainVolume=1] - Volume level for sustain (percent)
2846
2856
  * @param {Number} [decay=0] - Decay time, how long to reach sustain after attack (seconds)
2847
2857
  * @param {Number} [tremolo=0] - Trembling effect, rate controlled by repeat time (precent)
2858
+ * @param {Number} [filter=0] - Filter cutoff frequency, positive for HPF, negative for LPF (Hz)
2848
2859
  * @return {Array} - Array of audio samples
2849
2860
  * @memberof Audio
2850
2861
  */
@@ -2854,78 +2865,91 @@ function zzfxG
2854
2865
  volume = 1, randomness = .05, frequency = 220, attack = 0, sustain = 0,
2855
2866
  release = .1, shape = 0, shapeCurve = 1, slide = 0, deltaSlide = 0,
2856
2867
  pitchJump = 0, pitchJumpTime = 0, repeatTime = 0, noise = 0, modulation = 0,
2857
- bitCrush = 0, delay = 0, sustainVolume = 1, decay = 0, tremolo = 0
2868
+ bitCrush = 0, delay = 0, sustainVolume = 1, decay = 0, tremolo = 0, filter = 0
2858
2869
  )
2859
2870
  {
2860
- // locals
2861
- let PI2 = PI*2, startSlide = slide *= 500 * PI2 / zzfxR / zzfxR, b=[],
2862
- startFrequency = frequency *= (1 + randomness*rand(-1,1)) * PI2 / zzfxR,
2863
- t=0, tm=0, i=0, j=1, r=0, c=0, s=0, f, length
2871
+ // init parameters
2872
+ let PI2 = PI*2, sampleRate = zzfxR,
2873
+ startSlide = slide *= 500 * PI2 / sampleRate / sampleRate,
2874
+ startFrequency = frequency *=
2875
+ rand(1 + randomness, 1-randomness) * PI2 / sampleRate,
2876
+ b = [], t = 0, tm = 0, i = 0, j = 1, r = 0, c = 0, s = 0, f, length,
2877
+
2878
+ // biquad LP/HP filter
2879
+ quality = 2, w = PI2 * abs(filter) * 2 / sampleRate,
2880
+ cos = Math.cos(w), alpha = Math.sin(w) / 2 / quality,
2881
+ a0 = 1 + alpha, a1 = -2*cos / a0, a2 = (1 - alpha) / a0,
2882
+ b0 = (1 + sign(filter) * cos) / 2 / a0,
2883
+ b1 = -(sign(filter) + cos) / a0, b2 = b0,
2884
+ x2 = 0, x1 = 0, y2 = 0, y1 = 0;
2864
2885
 
2865
2886
  // scale by sample rate
2866
- attack = attack * zzfxR + 9; // minimum attack to prevent pop
2867
- decay *= zzfxR;
2868
- sustain *= zzfxR;
2869
- release *= zzfxR;
2870
- delay *= zzfxR;
2871
- deltaSlide *= 500 * PI2 / zzfxR**3;
2872
- modulation *= PI2 / zzfxR;
2873
- pitchJump *= PI2 / zzfxR;
2874
- pitchJumpTime *= zzfxR;
2875
- repeatTime = repeatTime * zzfxR | 0;
2887
+ attack = attack * sampleRate + 9; // minimum attack to prevent pop
2888
+ decay *= sampleRate;
2889
+ sustain *= sampleRate;
2890
+ release *= sampleRate;
2891
+ delay *= sampleRate;
2892
+ deltaSlide *= 500 * PI2 / sampleRate**3;
2893
+ modulation *= PI2 / sampleRate;
2894
+ pitchJump *= PI2 / sampleRate;
2895
+ pitchJumpTime *= sampleRate;
2896
+ repeatTime = repeatTime * sampleRate | 0;
2897
+ volume *= soundVolume;
2876
2898
 
2877
2899
  // generate waveform
2878
- for (length = attack + decay + sustain + release + delay | 0;
2879
- i < length; b[i++] = s)
2900
+ for(length = attack + decay + sustain + release + delay | 0;
2901
+ i < length; b[i++] = s * volume) // sample
2880
2902
  {
2881
- if (!(++c%(bitCrush*100|0))) // bit crush
2903
+ if (!(++c%(bitCrush*100|0))) // bit crush
2882
2904
  {
2883
- s = shape? shape>1? shape>2? shape>3? // wave shape
2884
- Math.sin((t%PI2)**3) : // 4 noise
2885
- max(min(Math.tan(t),1),-1): // 3 tan
2886
- 1-(2*t/PI2%2+2)%2: // 2 saw
2887
- 1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
2888
- Math.sin(t); // 0 sin
2889
-
2905
+ s = shape? shape>1? shape>2? shape>3? // wave shape
2906
+ Math.sin(t*t) : // 4 noise
2907
+ clamp(Math.tan(t),1,-1): // 3 tan
2908
+ 1-(2*t/PI2%2+2)%2: // 2 saw
2909
+ 1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
2910
+ Math.sin(t); // 0 sin
2911
+
2890
2912
  s = (repeatTime ?
2891
2913
  1 - tremolo + tremolo*Math.sin(PI2*i/repeatTime) // tremolo
2892
2914
  : 1) *
2893
- sign(s)*(abs(s)**shapeCurve) * // curve 0=square, 2=pointy
2894
- volume * soundVolume * ( // envelope
2895
- i < attack ? i/attack : // attack
2896
- i < attack + decay ? // decay
2897
- 1-((i-attack)/decay)*(1-sustainVolume) : // decay falloff
2898
- i < attack + decay + sustain ? // sustain
2899
- sustainVolume : // sustain volume
2900
- i < length - delay ? // release
2901
- (length - i - delay)/release * // release falloff
2902
- sustainVolume : // release volume
2903
- 0); // post release
2904
-
2905
- s = delay ? s/2 + (delay > i ? 0 : // delay
2906
- (i<length-delay? 1 : (length-i)/delay) * // release delay
2907
- b[i-delay|0]/2) : s; // sample delay
2908
- }
2909
-
2910
- f = (frequency += slide += deltaSlide) * // frequency
2911
- Math.cos(modulation*tm++); // modulation
2912
- t += f - f*noise*(1 - (Math.sin(i)+1)*1e9%2); // noise
2913
-
2914
- if (j && ++j > pitchJumpTime) // pitch jump
2915
- {
2916
- frequency += pitchJump; // apply pitch jump
2917
- startFrequency += pitchJump; // also apply to start
2918
- j = 0; // reset pitch jump time
2915
+ sign(s)*(abs(s)**shapeCurve) * // curve
2916
+ (i < attack ? i/attack : // attack
2917
+ i < attack + decay ? // decay
2918
+ 1-((i-attack)/decay)*(1-sustainVolume) : // decay falloff
2919
+ i < attack + decay + sustain ? // sustain
2920
+ sustainVolume : // sustain volume
2921
+ i < length - delay ? // release
2922
+ (length - i - delay)/release * // release falloff
2923
+ sustainVolume : // release volume
2924
+ 0); // post release
2925
+
2926
+ s = delay ? s/2 + (delay > i ? 0 : // delay
2927
+ (i<length-delay? 1 : (length-i)/delay) * // release delay
2928
+ b[i-delay|0]/2/volume) : s; // sample delay
2929
+
2930
+ if (filter) // apply filter
2931
+ s = y1 = b2*x2 + b1*(x2=x1) + b0*(x1=s) - a2*y2 - a1*(y2=y1);
2919
2932
  }
2920
2933
 
2921
- if (repeatTime && !(++r % repeatTime)) // repeat
2922
- {
2923
- frequency = startFrequency; // reset frequency
2924
- slide = startSlide; // reset slide
2925
- j ||= 1; // reset pitch jump time
2934
+ f = (frequency += slide += deltaSlide) *// frequency
2935
+ Math.cos(modulation*tm++); // modulation
2936
+ t += f + f*noise*Math.sin(i**5); // noise
2937
+
2938
+ if (j && ++j > pitchJumpTime) // pitch jump
2939
+ {
2940
+ frequency += pitchJump; // apply pitch jump
2941
+ startFrequency += pitchJump; // also apply to start
2942
+ j = 0; // stop pitch jump time
2943
+ }
2944
+
2945
+ if (repeatTime && !(++r % repeatTime)) // repeat
2946
+ {
2947
+ frequency = startFrequency; // reset frequency
2948
+ slide = startSlide; // reset slide
2949
+ j = j || 1; // reset pitch jump time
2926
2950
  }
2927
2951
  }
2928
-
2952
+
2929
2953
  return b;
2930
2954
  }
2931
2955
 
@@ -3421,13 +3445,13 @@ constructor(pos, size=tileCollisionSize, tileInfo=tile(), scale=vec2(1), renderO
3421
3445
  class ParticleEmitter extends EngineObject
3422
3446
  {
3423
3447
  /** Create a particle system with the given settings
3424
- * @param {Vector2} position - World space position of the emitter
3425
- * @param {Number} [angle=0] - Angle to emit the particles
3426
- * @param {Number} [emitSize=0] - World space size of the emitter (float for circle diameter, vec2 for rect)
3427
- * @param {Number} [emitTime=0] - How long to stay alive (0 is forever)
3428
- * @param {Number} [emitRate=100] - How many particles per second to spawn, does not emit if 0
3448
+ * @param {Vector2} position - World space position of the emitter
3449
+ * @param {Number} [angle=0] - Angle to emit the particles
3450
+ * @param {Number|Vector2} [emitSize=0] - World space size of the emitter (float for circle diameter, vec2 for rect)
3451
+ * @param {Number} [emitTime=0] - How long to stay alive (0 is forever)
3452
+ * @param {Number} [emitRate=100] - How many particles per second to spawn, does not emit if 0
3429
3453
  * @param {Number} [emitConeAngle=PI] - Local angle to apply velocity to particles from emitter
3430
- * @param {TileInfo} [tileInfo] - Tile info to render particles (undefined is untextured)
3454
+ * @param {TileInfo} [tileInfo] - Tile info to render particles (undefined is untextured)
3431
3455
  * @param {Color} [colorStartA=Color()] - Color at start of life 1, randomized between start colors
3432
3456
  * @param {Color} [colorStartB=Color()] - Color at start of life 2, randomized between start colors
3433
3457
  * @param {Color} [colorEndA=Color(1,1,1,0)] - Color at end of life 1, randomized between end colors
@@ -3483,7 +3507,7 @@ class ParticleEmitter extends EngineObject
3483
3507
  super(pos, vec2(), tileInfo, angle, undefined, renderOrder);
3484
3508
 
3485
3509
  // emitter settings
3486
- /** @property {Number} - World space size of the emitter (float for circle diameter, vec2 for rect) */
3510
+ /** @property {Number|Vector2} - World space size of the emitter (float for circle diameter, vec2 for rect) */
3487
3511
  this.emitSize = emitSize
3488
3512
  /** @property {Number} - How long to stay alive (0 is forever) */
3489
3513
  this.emitTime = emitTime;
@@ -4015,7 +4039,7 @@ let glCanvas;
4015
4039
  let glContext;
4016
4040
 
4017
4041
  // WebGL internal variables not exposed to documentation
4018
- let glActiveTexture, glShader, glArrayBuffer, glPositionData, glColorData, glBatchCount, glBatchAdditive, glAdditive;
4042
+ let glActiveTexture, glShader, glArrayBuffer, glVertexData, glPositionData, glColorData, glBatchCount, glBatchAdditive, glAdditive;
4019
4043
 
4020
4044
  ///////////////////////////////////////////////////////////////////////////////
4021
4045
 
@@ -4052,10 +4076,10 @@ function glInit()
4052
4076
  );
4053
4077
 
4054
4078
  // init buffers
4055
- const vertexData = new ArrayBuffer(gl_VERTEX_BUFFER_SIZE);
4079
+ glVertexData = new ArrayBuffer(gl_VERTEX_BUFFER_SIZE);
4080
+ glPositionData = new Float32Array(glVertexData);
4081
+ glColorData = new Uint32Array(glVertexData);
4056
4082
  glArrayBuffer = glContext.createBuffer();
4057
- glPositionData = new Float32Array(vertexData);
4058
- glColorData = new Uint32Array(vertexData);
4059
4083
  glBatchCount = 0;
4060
4084
  }
4061
4085
 
@@ -4083,7 +4107,7 @@ function glPreRender()
4083
4107
  glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
4084
4108
  offset += size*typeSize;
4085
4109
  }
4086
- initVertexAttribArray('p', gl_FLOAT, 4, 4); // position & texture coords
4110
+ initVertexAttribArray('p', gl_FLOAT, 4, 4); // position & texture
4087
4111
  initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
4088
4112
  initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
4089
4113
 
@@ -4171,6 +4195,7 @@ function glCreateTexture(image)
4171
4195
  glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, filter);
4172
4196
  glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_S, gl_CLAMP_TO_EDGE);
4173
4197
  glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_T, gl_CLAMP_TO_EDGE);
4198
+
4174
4199
  return texture;
4175
4200
  }
4176
4201
 
@@ -4185,8 +4210,7 @@ function glFlush()
4185
4210
  glContext.enable(gl_BLEND);
4186
4211
 
4187
4212
  // draw all the sprites in the batch and reset the buffer
4188
- glContext.bufferSubData(gl_ARRAY_BUFFER, 0,
4189
- glPositionData.subarray(0, glBatchCount * gl_INDICIES_PER_VERT));
4213
+ glContext.bufferSubData(gl_ARRAY_BUFFER, 0, glVertexData);
4190
4214
  glContext.drawArrays(gl_TRIANGLE_STRIP, 0, glBatchCount);
4191
4215
  glBatchCount = 0;
4192
4216
  glBatchAdditive = glAdditive;
@@ -4241,11 +4265,11 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdd
4241
4265
  // setup 2 triangle strip quad
4242
4266
  for(let i = vertCount, offset = glBatchCount * gl_INDICIES_PER_VERT; i--;)
4243
4267
  {
4244
- let j = clamp(i-1, 0, 3)*4; // degenerate tri at ends
4245
- glPositionData[offset++] = positionData[j++];
4246
- glPositionData[offset++] = positionData[j++];
4247
- glPositionData[offset++] = positionData[j++];
4248
- glPositionData[offset++] = positionData[j++];
4268
+ const j = clamp(i-1, 0, 3)*4; // degenerate tri at ends
4269
+ glPositionData[offset++] = positionData[j+0];
4270
+ glPositionData[offset++] = positionData[j+1];
4271
+ glPositionData[offset++] = positionData[j+2];
4272
+ glPositionData[offset++] = positionData[j+3];
4249
4273
  glColorData[offset++] = rgba;
4250
4274
  glColorData[offset++] = rgbaAdditive;
4251
4275
  }
@@ -4446,7 +4470,7 @@ const engineName = 'LittleJS';
4446
4470
  * @type {String}
4447
4471
  * @default
4448
4472
  * @memberof Engine */
4449
- const engineVersion = '1.8.6';
4473
+ const engineVersion = '1.8.9';
4450
4474
 
4451
4475
  /** Frames per second to update objects
4452
4476
  * @type {Number}
@@ -4629,7 +4653,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
4629
4653
  }
4630
4654
 
4631
4655
  // setup html
4632
- const styleBody =
4656
+ const styleBody =
4633
4657
  'margin:0;overflow:hidden;' + // fill the window
4634
4658
  'background:#000;' + // set background color
4635
4659
  'touch-action:none;' + // prevent mobile pinch to resize
@@ -4650,14 +4674,13 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
4650
4674
 
4651
4675
  // set canvas style
4652
4676
  const styleCanvas =
4653
- 'position:absolute;' + // position
4654
- 'top:50%;left:50%;transform:translate(-50%,-50%);' + // center
4655
- (canvasPixelated?'image-rendering:pixelated':''); // pixelated rendering
4677
+ 'position:absolute;' + // position
4678
+ 'top:50%;left:50%;transform:translate(-50%,-50%)'; // center
4656
4679
  (glCanvas||mainCanvas).style = mainCanvas.style = overlayCanvas.style = styleCanvas;
4657
4680
 
4658
- // load all of the images
4659
- Promise.all(imageSources.map((src, textureIndex)=>
4660
- new Promise((resolve, reject)=>
4681
+ // create promises for loading images
4682
+ const promises = imageSources.map((src, textureIndex)=>
4683
+ new Promise(resolve =>
4661
4684
  {
4662
4685
  const image = new Image;
4663
4686
  image.onerror = image.onload = ()=>
@@ -4667,7 +4690,24 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
4667
4690
  }
4668
4691
  image.src = src;
4669
4692
  })
4670
- )).then(()=>
4693
+ )
4694
+
4695
+ // draw splash screen
4696
+ showSplashScreen && promises.push(new Promise(resolve =>
4697
+ {
4698
+ let t = 0;
4699
+ console.log(`LittleJS Engine v${engineVersion}`);
4700
+ updateSplash();
4701
+ function updateSplash()
4702
+ {
4703
+ clearInput();
4704
+ drawEngineSplashScreen(t+=.01);
4705
+ t>1 ? resolve() : setTimeout(updateSplash,16);
4706
+ }
4707
+ }));
4708
+
4709
+ // load all of the images
4710
+ Promise.all(promises).then(()=>
4671
4711
  {
4672
4712
  // start the engine
4673
4713
  gameInit();
@@ -4745,4 +4785,168 @@ function engineObjectsCallback(pos, size, callbackFunction, objects=engineObject
4745
4785
  for (const o of objects)
4746
4786
  pos.distanceSquared(o.pos) < sizeSquared && callbackFunction(o);
4747
4787
  }
4788
+ }
4789
+
4790
+ ///////////////////////////////////////////////////////////////////////////////
4791
+ // LittleJS splash screen and logo
4792
+
4793
+ function drawEngineSplashScreen(t)
4794
+ {
4795
+ const x = mainContext;
4796
+ const w = mainCanvas.width = innerWidth;
4797
+ const h = mainCanvas.height = innerHeight;
4798
+ {
4799
+ // background
4800
+ const p3 = percent(t, 1, .8);
4801
+ const p4 = percent(t, 0, .5);
4802
+ const g = x.createRadialGradient(w/2,h/2,0,w/2,h/2,Math.hypot(w,h)*.7);
4803
+ g.addColorStop(0,hsl(0,0,lerp(p4,0,p3/2),p3));
4804
+ g.addColorStop(1,hsl(0,0,0,p3));
4805
+ x.save();
4806
+ x.fillStyle = g;
4807
+ x.fillRect(0,0,w,h);
4808
+ }
4809
+
4810
+ // draw LittleJS logo...
4811
+
4812
+ const rect = (X, Y, W, H, C)=>
4813
+ {
4814
+ x.beginPath();
4815
+ x.rect(X,Y,W,C?H*p:H);
4816
+ x.fillStyle = C;
4817
+ C ? x.fill() : x.stroke();
4818
+ };
4819
+ const line = (X, Y, Z, W)=>
4820
+ {
4821
+ x.beginPath();
4822
+ x.lineTo(X,Y);
4823
+ x.lineTo(Z,W);
4824
+ x.stroke();
4825
+ };
4826
+ const circle = (X, Y, R, A=0, B=2*PI, C, F)=>
4827
+ {
4828
+ const D = (A+B)/2, E = p*(B-A)/2;
4829
+ x.beginPath();
4830
+ F && x.lineTo(X,Y);
4831
+ x.arc(X,Y,R,D-E,D+E);
4832
+ x.fillStyle = C;
4833
+ C ? x.fill() : x.stroke();
4834
+ };
4835
+ const color = (c=0, l=0) =>
4836
+ hsl([.98,.3,.57,.14][c%4]-10,.8,[0,.3,.5,.8,.9][l]);
4837
+ const alpha = wave(1,1,t);
4838
+ const p = percent(alpha, .1, .5);
4839
+
4840
+ // setup
4841
+ x.translate(w/2,h/2);
4842
+ const size = min(6, min(w,h)/99); // fit to screen
4843
+ x.scale(size,size);
4844
+ x.translate(-40,-35);
4845
+ x.lineJoin = x.lineCap = 'round';
4846
+ x.lineWidth = 1+p;
4847
+
4848
+ // drawing effect
4849
+ const p2 = percent(alpha,.1,1);
4850
+ x.setLineDash([99*p2,99]);
4851
+
4852
+ // cab top
4853
+ rect(7,17,18,-8,color(2,2));
4854
+ rect(7,9,18,4,color(2,3));
4855
+ rect(25,9,8,8,color(2,1));
4856
+ rect(25,9,-18,8);
4857
+ rect(25,9,8,8);
4858
+
4859
+ // cab
4860
+ rect(25,17,7,22,color());
4861
+ rect(11,40,14,-23,color(1,1));
4862
+ rect(11,17,14,17,color(1,2));
4863
+ rect(11,17,14,9,color(1,3));
4864
+ rect(15,31,6,-9,color(2,2));
4865
+ circle(15,23,5,0,PI/2,color(2,4),1);
4866
+ rect(25,17,-14,23);
4867
+ rect(21,22,-6,9);
4868
+
4869
+ // little stack
4870
+ rect(37,14,9,6,color(3,2));
4871
+ rect(37,14,4,6,color(3,3));
4872
+ rect(37,14,9,6);
4873
+
4874
+ // big stack
4875
+ rect(50,20,10,-10,color(0,1));
4876
+ rect(50,20,6,-10,color(0,2));
4877
+ rect(50,20,3,-10,color(0,3));
4878
+ rect(50,10,10,10);
4879
+ circle(55,2,11.4,.5,PI-.5,color(3,3));
4880
+ circle(55,2,11.4,.5,PI/2,color(3,2),1);
4881
+ circle(55,2,11.4,.5,PI-.5);
4882
+ rect(45,7,20,-7,color(0,2));
4883
+ rect(45,0,20,3,color(0,3));
4884
+ rect(45,0,20,7);
4885
+
4886
+ // engine
4887
+ for (let i=5; i--;)
4888
+ {
4889
+ // stagger radius to fix slight seam
4890
+ circle(60-i*6,30, 9.9,0,2*PI,color(i+2,3));
4891
+ circle(60-i*6,30,10.0,-.5,PI+.5,color(i+2,2));
4892
+ circle(60-i*6,30,10.1,.5,PI-.5,color(i+2,1));
4893
+ }
4894
+
4895
+ // engine outline
4896
+ circle(36,30,10,PI/2,PI*3/2);
4897
+ circle(47,30,10,PI/2,PI*3/2);
4898
+ circle(60,30,10);
4899
+ line(36,20,60,20);
4900
+
4901
+ // engine front light
4902
+ circle(60,30,4,PI,3*PI,color(3,2));
4903
+ circle(60,30,4,PI,2*PI,color(3,3));
4904
+ circle(60,30,4,PI,3*PI);
4905
+
4906
+ // front brush
4907
+ for (let i=6; i--;)
4908
+ {
4909
+ x.beginPath();
4910
+ x.lineTo(53,54);
4911
+ x.lineTo(53,40);
4912
+ x.lineTo(53+(1+i*2.9)*p,40);
4913
+ x.lineTo(53+(4+i*3.5)*p,54);
4914
+ x.fillStyle = color(0,i%2+2);
4915
+ x.fill() || i%2 && x.stroke();
4916
+ }
4917
+
4918
+ // wheels
4919
+ rect(6,40,5,5);
4920
+ rect(6,40,5,5,color());
4921
+ rect(15,54,38,-14,color());
4922
+ for (let i=3; i--;)
4923
+ for (let j=2; j--;)
4924
+ {
4925
+ circle(15*i+15,47,j?7:1,PI,3*PI,color(i,3));
4926
+ x.stroke();
4927
+ circle(15*i+15,47,j?7:1,0,PI,color(i,2));
4928
+ x.stroke();
4929
+ }
4930
+ line(6,40,68,40); // center
4931
+ line(77,54,4,54); // bottom
4932
+
4933
+ // draw engine name
4934
+ const s = engineName;
4935
+ x.font = '900 16px arial';
4936
+ x.textAlign = 'center';
4937
+ x.textBaseline = 'top';
4938
+ x.lineWidth = 1+p*3;
4939
+ let w2 = 0;
4940
+ for (let i=0; i<s.length; ++i)
4941
+ w2 += x.measureText(s[i]).width;
4942
+ for (let j=2; j--;)
4943
+ for (let i=0, X=41-w2/2; i<s.length; ++i)
4944
+ {
4945
+ x.fillStyle = color(i,2);
4946
+ const w = x.measureText(s[i]).width;
4947
+ x[j?'strokeText':'fillText'](s[i],X+w/2,55.5,17*p);
4948
+ X += w;
4949
+ }
4950
+
4951
+ x.restore();
4748
4952
  }
@@ -8,6 +8,9 @@
8
8
 
9
9
  'use strict';
10
10
 
11
+ // show the LittleJS splash screen
12
+ showSplashScreen = 1;
13
+
11
14
  let levelSize, ball, paddle, score, brickCount;
12
15
 
13
16
  // sound effects
@@ -5,6 +5,6 @@
5
5
  <link rel=icon type=image/png href=../favicon.png>
6
6
  </head><body>
7
7
 
8
- <script src=../../build/littlejs.js?183></script>
9
- <script src=gameObjects.js?183></script>
10
- <script src=game.js?183></script>
8
+ <script src=../../build/littlejs.js?188></script>
9
+ <script src=gameObjects.js?188></script>
10
+ <script src=game.js?188></script>
@@ -5,5 +5,5 @@
5
5
  <link rel=icon type=image/png href=../favicon.png>
6
6
  </head><body>
7
7
 
8
- <script src=../../build/littlejs.js?183></script>
9
- <script src=game.js?183></script>
8
+ <script src=../../build/littlejs.js?188></script>
9
+ <script src=game.js?188></script>
@@ -16,6 +16,9 @@ medalsInit('Hello World');
16
16
  // game variables
17
17
  let particleEmiter;
18
18
 
19
+ // show the LittleJS splash screen
20
+ showSplashScreen = 1;
21
+
19
22
  ///////////////////////////////////////////////////////////////////////////////
20
23
  function gameInit()
21
24
  {
@@ -6,7 +6,7 @@
6
6
  </head><body>
7
7
 
8
8
  <!-- LittleJS Engine -->
9
- <script src=../../build/littlejs.js?183></script>
9
+ <script src=../../build/littlejs.js?188></script>
10
10
 
11
11
  <!-- Add your game scripts here -->
12
- <script src=game.js?183></script>
12
+ <script src=game.js?188></script>
@@ -1,18 +1,18 @@
1
1
  <head><title>LittleJS JS13K Project</title></head><body>
2
2
 
3
3
  <!-- LittleJS Engine -->
4
- <script src=../../src/engineDebug.js?183></script>
5
- <script src=../../src/engineUtilities.js?183></script>
6
- <script src=../../src/engineSettings.js?183></script>
7
- <script src=../../src/engineObject.js?183></script>
8
- <script src=../../src/engineDraw.js?183></script>
9
- <script src=../../src/engineInput.js?183></script>
10
- <script src=../../src/engineAudio.js?183></script>
11
- <script src=../../src/engineTileLayer.js?183></script>
12
- <script src=../../src/engineParticles.js?183></script>
13
- <script src=../../src/engineMedals.js?183></script>
14
- <script src=../../src/engineWebGL.js?183></script>
15
- <script src=../../src/engine.js?183></script>
4
+ <script src=../../src/engineDebug.js?188></script>
5
+ <script src=../../src/engineUtilities.js?188></script>
6
+ <script src=../../src/engineSettings.js?188></script>
7
+ <script src=../../src/engineObject.js?188></script>
8
+ <script src=../../src/engineDraw.js?188></script>
9
+ <script src=../../src/engineInput.js?188></script>
10
+ <script src=../../src/engineAudio.js?188></script>
11
+ <script src=../../src/engineTileLayer.js?188></script>
12
+ <script src=../../src/engineParticles.js?188></script>
13
+ <script src=../../src/engineMedals.js?188></script>
14
+ <script src=../../src/engineWebGL.js?188></script>
15
+ <script src=../../src/engine.js?188></script>
16
16
 
17
17
  <!-- Add your game scripts here -->
18
- <script src=game.js?183></script>
18
+ <script src=game.js?188></script>
Binary file
@@ -10,6 +10,9 @@
10
10
  import * as LittleJS from '../../build/littlejs.esm.js';
11
11
  const {Vector2, Color, Timer, vec2, tile} = LittleJS;
12
12
 
13
+ // show the LittleJS splash screen
14
+ LittleJS.setShowSplashScreen(1);
15
+
13
16
  // sound effects
14
17
  const sound_click = new LittleJS.Sound([1,.5]);
15
18
 
@@ -6,4 +6,4 @@
6
6
  </head><body>
7
7
 
8
8
  <!-- Add your game scripts here -->
9
- <script src=game.js?183 type=module></script>
9
+ <script src=game.js?188 type=module></script>
@@ -9,7 +9,7 @@ button { margin:1px; }
9
9
  </style>
10
10
  </head><body>
11
11
 
12
- <script src=../../build/littlejs.js?183></script>
12
+ <script src=../../build/littlejs.js?188></script>
13
13
  <script>
14
14
 
15
15
  'use strict';