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.
- package/README.md +9 -3
- package/build/littlejs.d.ts +18 -9
- package/build/littlejs.esm.js +298 -92
- package/build/littlejs.esm.min.js +1 -1
- package/build/littlejs.js +296 -92
- package/build/littlejs.min.js +1 -1
- package/build/littlejs.release.js +296 -92
- package/examples/breakout/game.js +3 -0
- package/examples/breakout/index.html +3 -3
- package/examples/breakoutTutorial/index.html +2 -2
- package/examples/electron/game.js +3 -0
- package/examples/electron/index.html +2 -2
- package/examples/js13k/index.html +13 -13
- package/examples/logo.png +0 -0
- package/examples/module/game.js +3 -0
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +1 -1
- package/examples/platformer/game.js +3 -0
- package/examples/platformer/gameEffects.js +1 -1
- package/examples/platformer/index.html +6 -6
- package/examples/puzzle/game.js +3 -0
- package/examples/puzzle/index.html +2 -2
- package/examples/starter/game.js +4 -1
- package/examples/starter/index.html +13 -13
- package/examples/starter/tiles.png +0 -0
- package/examples/stress/index.html +3 -1
- package/examples/typescript/game.js +2 -0
- package/examples/typescript/game.ts +3 -0
- package/examples/typescript/index.html +1 -1
- package/package.json +1 -1
- package/src/engine.js +189 -9
- package/src/engineAudio.js +72 -58
- package/src/engineDraw.js +1 -1
- package/src/engineExport.js +2 -0
- package/src/engineParticles.js +7 -7
- package/src/engineSettings.js +11 -0
- package/src/engineUtilities.js +4 -5
- package/src/engineWebGL.js +12 -12
package/build/littlejs.js
CHANGED
|
@@ -1008,11 +1008,10 @@ class Color
|
|
|
1008
1008
|
* @return {Number} */
|
|
1009
1009
|
rgbaInt()
|
|
1010
1010
|
{
|
|
1011
|
-
const
|
|
1012
|
-
const
|
|
1013
|
-
const
|
|
1014
|
-
const
|
|
1015
|
-
const a = toByte(this.a)<<24;
|
|
1011
|
+
const r = clamp(this.r)*255|0;
|
|
1012
|
+
const g = clamp(this.g)*255<<8;
|
|
1013
|
+
const b = clamp(this.b)*255<<16;
|
|
1014
|
+
const a = clamp(this.a)*255<<24;
|
|
1016
1015
|
return r + g + b + a;
|
|
1017
1016
|
}
|
|
1018
1017
|
}
|
|
@@ -1120,6 +1119,12 @@ let canvasPixelated = 1;
|
|
|
1120
1119
|
* @memberof Settings */
|
|
1121
1120
|
let fontDefault = 'arial';
|
|
1122
1121
|
|
|
1122
|
+
/** Enable to show the LittleJS splash screen be shown on startup
|
|
1123
|
+
* @type {Boolean}
|
|
1124
|
+
* @default
|
|
1125
|
+
* @memberof Settings */
|
|
1126
|
+
let showSplashScreen = 0;
|
|
1127
|
+
|
|
1123
1128
|
///////////////////////////////////////////////////////////////////////////////
|
|
1124
1129
|
// WebGL settings
|
|
1125
1130
|
|
|
@@ -1353,6 +1358,11 @@ function setCanvasPixelated(pixelated) { canvasPixelated = pixelated; }
|
|
|
1353
1358
|
* @memberof Settings */
|
|
1354
1359
|
function setFontDefault(font) { fontDefault = font; }
|
|
1355
1360
|
|
|
1361
|
+
/** Set if the LittleJS splash screen be shown on startup
|
|
1362
|
+
* @param {Boolean} show
|
|
1363
|
+
* @memberof Settings */
|
|
1364
|
+
function setShowSplashScreen(show) { showSplashScreen = show; }
|
|
1365
|
+
|
|
1356
1366
|
/** Set if webgl rendering is enabled
|
|
1357
1367
|
* @param {Boolean} enable
|
|
1358
1368
|
* @memberof Settings */
|
|
@@ -1944,7 +1954,7 @@ let mainCanvasSize = vec2();
|
|
|
1944
1954
|
* @memberof Draw */
|
|
1945
1955
|
let textureInfos = [];
|
|
1946
1956
|
|
|
1947
|
-
//
|
|
1957
|
+
// Keep track of how many draw calls there were each frame for debugging
|
|
1948
1958
|
let drawCount;
|
|
1949
1959
|
|
|
1950
1960
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -3186,7 +3196,7 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0, sampleRate
|
|
|
3186
3196
|
}
|
|
3187
3197
|
|
|
3188
3198
|
///////////////////////////////////////////////////////////////////////////////
|
|
3189
|
-
// ZzFXMicro - Zuper Zmall Zound Zynth - v1.
|
|
3199
|
+
// ZzFXMicro - Zuper Zmall Zound Zynth - v1.3.0 by Frank Force
|
|
3190
3200
|
|
|
3191
3201
|
/** Generate and play a ZzFX sound
|
|
3192
3202
|
*
|
|
@@ -3222,6 +3232,7 @@ const zzfxR = 44100;
|
|
|
3222
3232
|
* @param {Number} [sustainVolume=1] - Volume level for sustain (percent)
|
|
3223
3233
|
* @param {Number} [decay=0] - Decay time, how long to reach sustain after attack (seconds)
|
|
3224
3234
|
* @param {Number} [tremolo=0] - Trembling effect, rate controlled by repeat time (precent)
|
|
3235
|
+
* @param {Number} [filter=0] - Filter cutoff frequency, positive for HPF, negative for LPF (Hz)
|
|
3225
3236
|
* @return {Array} - Array of audio samples
|
|
3226
3237
|
* @memberof Audio
|
|
3227
3238
|
*/
|
|
@@ -3231,78 +3242,91 @@ function zzfxG
|
|
|
3231
3242
|
volume = 1, randomness = .05, frequency = 220, attack = 0, sustain = 0,
|
|
3232
3243
|
release = .1, shape = 0, shapeCurve = 1, slide = 0, deltaSlide = 0,
|
|
3233
3244
|
pitchJump = 0, pitchJumpTime = 0, repeatTime = 0, noise = 0, modulation = 0,
|
|
3234
|
-
bitCrush = 0, delay = 0, sustainVolume = 1, decay = 0, tremolo = 0
|
|
3245
|
+
bitCrush = 0, delay = 0, sustainVolume = 1, decay = 0, tremolo = 0, filter = 0
|
|
3235
3246
|
)
|
|
3236
3247
|
{
|
|
3237
|
-
//
|
|
3238
|
-
let PI2 = PI*2,
|
|
3239
|
-
|
|
3240
|
-
|
|
3248
|
+
// init parameters
|
|
3249
|
+
let PI2 = PI*2, sampleRate = zzfxR,
|
|
3250
|
+
startSlide = slide *= 500 * PI2 / sampleRate / sampleRate,
|
|
3251
|
+
startFrequency = frequency *=
|
|
3252
|
+
rand(1 + randomness, 1-randomness) * PI2 / sampleRate,
|
|
3253
|
+
b = [], t = 0, tm = 0, i = 0, j = 1, r = 0, c = 0, s = 0, f, length,
|
|
3254
|
+
|
|
3255
|
+
// biquad LP/HP filter
|
|
3256
|
+
quality = 2, w = PI2 * abs(filter) * 2 / sampleRate,
|
|
3257
|
+
cos = Math.cos(w), alpha = Math.sin(w) / 2 / quality,
|
|
3258
|
+
a0 = 1 + alpha, a1 = -2*cos / a0, a2 = (1 - alpha) / a0,
|
|
3259
|
+
b0 = (1 + sign(filter) * cos) / 2 / a0,
|
|
3260
|
+
b1 = -(sign(filter) + cos) / a0, b2 = b0,
|
|
3261
|
+
x2 = 0, x1 = 0, y2 = 0, y1 = 0;
|
|
3241
3262
|
|
|
3242
3263
|
// scale by sample rate
|
|
3243
|
-
attack = attack *
|
|
3244
|
-
decay *=
|
|
3245
|
-
sustain *=
|
|
3246
|
-
release *=
|
|
3247
|
-
delay *=
|
|
3248
|
-
deltaSlide *= 500 * PI2 /
|
|
3249
|
-
modulation *= PI2 /
|
|
3250
|
-
pitchJump *= PI2 /
|
|
3251
|
-
pitchJumpTime *=
|
|
3252
|
-
repeatTime = repeatTime *
|
|
3264
|
+
attack = attack * sampleRate + 9; // minimum attack to prevent pop
|
|
3265
|
+
decay *= sampleRate;
|
|
3266
|
+
sustain *= sampleRate;
|
|
3267
|
+
release *= sampleRate;
|
|
3268
|
+
delay *= sampleRate;
|
|
3269
|
+
deltaSlide *= 500 * PI2 / sampleRate**3;
|
|
3270
|
+
modulation *= PI2 / sampleRate;
|
|
3271
|
+
pitchJump *= PI2 / sampleRate;
|
|
3272
|
+
pitchJumpTime *= sampleRate;
|
|
3273
|
+
repeatTime = repeatTime * sampleRate | 0;
|
|
3274
|
+
volume *= soundVolume;
|
|
3253
3275
|
|
|
3254
3276
|
// generate waveform
|
|
3255
|
-
for
|
|
3256
|
-
i < length; b[i++] = s)
|
|
3277
|
+
for(length = attack + decay + sustain + release + delay | 0;
|
|
3278
|
+
i < length; b[i++] = s * volume) // sample
|
|
3257
3279
|
{
|
|
3258
|
-
if (!(++c%(bitCrush*100|0)))
|
|
3280
|
+
if (!(++c%(bitCrush*100|0))) // bit crush
|
|
3259
3281
|
{
|
|
3260
|
-
s = shape? shape>1? shape>2? shape>3?
|
|
3261
|
-
Math.sin(
|
|
3262
|
-
|
|
3263
|
-
1-(2*t/PI2%2+2)%2:
|
|
3264
|
-
1-4*abs(Math.round(t/PI2)-t/PI2):
|
|
3265
|
-
Math.sin(t);
|
|
3266
|
-
|
|
3282
|
+
s = shape? shape>1? shape>2? shape>3? // wave shape
|
|
3283
|
+
Math.sin(t*t) : // 4 noise
|
|
3284
|
+
clamp(Math.tan(t),1,-1): // 3 tan
|
|
3285
|
+
1-(2*t/PI2%2+2)%2: // 2 saw
|
|
3286
|
+
1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
|
|
3287
|
+
Math.sin(t); // 0 sin
|
|
3288
|
+
|
|
3267
3289
|
s = (repeatTime ?
|
|
3268
3290
|
1 - tremolo + tremolo*Math.sin(PI2*i/repeatTime) // tremolo
|
|
3269
3291
|
: 1) *
|
|
3270
|
-
sign(s)*(abs(s)**shapeCurve) *
|
|
3271
|
-
|
|
3272
|
-
i < attack
|
|
3273
|
-
i
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
f = (frequency += slide += deltaSlide) * // frequency
|
|
3288
|
-
Math.cos(modulation*tm++); // modulation
|
|
3289
|
-
t += f - f*noise*(1 - (Math.sin(i)+1)*1e9%2); // noise
|
|
3290
|
-
|
|
3291
|
-
if (j && ++j > pitchJumpTime) // pitch jump
|
|
3292
|
-
{
|
|
3293
|
-
frequency += pitchJump; // apply pitch jump
|
|
3294
|
-
startFrequency += pitchJump; // also apply to start
|
|
3295
|
-
j = 0; // reset pitch jump time
|
|
3292
|
+
sign(s)*(abs(s)**shapeCurve) * // curve
|
|
3293
|
+
(i < attack ? i/attack : // attack
|
|
3294
|
+
i < attack + decay ? // decay
|
|
3295
|
+
1-((i-attack)/decay)*(1-sustainVolume) : // decay falloff
|
|
3296
|
+
i < attack + decay + sustain ? // sustain
|
|
3297
|
+
sustainVolume : // sustain volume
|
|
3298
|
+
i < length - delay ? // release
|
|
3299
|
+
(length - i - delay)/release * // release falloff
|
|
3300
|
+
sustainVolume : // release volume
|
|
3301
|
+
0); // post release
|
|
3302
|
+
|
|
3303
|
+
s = delay ? s/2 + (delay > i ? 0 : // delay
|
|
3304
|
+
(i<length-delay? 1 : (length-i)/delay) * // release delay
|
|
3305
|
+
b[i-delay|0]/2/volume) : s; // sample delay
|
|
3306
|
+
|
|
3307
|
+
if (filter) // apply filter
|
|
3308
|
+
s = y1 = b2*x2 + b1*(x2=x1) + b0*(x1=s) - a2*y2 - a1*(y2=y1);
|
|
3296
3309
|
}
|
|
3297
3310
|
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3311
|
+
f = (frequency += slide += deltaSlide) *// frequency
|
|
3312
|
+
Math.cos(modulation*tm++); // modulation
|
|
3313
|
+
t += f + f*noise*Math.sin(i**5); // noise
|
|
3314
|
+
|
|
3315
|
+
if (j && ++j > pitchJumpTime) // pitch jump
|
|
3316
|
+
{
|
|
3317
|
+
frequency += pitchJump; // apply pitch jump
|
|
3318
|
+
startFrequency += pitchJump; // also apply to start
|
|
3319
|
+
j = 0; // stop pitch jump time
|
|
3320
|
+
}
|
|
3321
|
+
|
|
3322
|
+
if (repeatTime && !(++r % repeatTime)) // repeat
|
|
3323
|
+
{
|
|
3324
|
+
frequency = startFrequency; // reset frequency
|
|
3325
|
+
slide = startSlide; // reset slide
|
|
3326
|
+
j = j || 1; // reset pitch jump time
|
|
3303
3327
|
}
|
|
3304
3328
|
}
|
|
3305
|
-
|
|
3329
|
+
|
|
3306
3330
|
return b;
|
|
3307
3331
|
}
|
|
3308
3332
|
|
|
@@ -3798,13 +3822,13 @@ constructor(pos, size=tileCollisionSize, tileInfo=tile(), scale=vec2(1), renderO
|
|
|
3798
3822
|
class ParticleEmitter extends EngineObject
|
|
3799
3823
|
{
|
|
3800
3824
|
/** Create a particle system with the given settings
|
|
3801
|
-
* @param {Vector2} position
|
|
3802
|
-
* @param {Number} [angle=0]
|
|
3803
|
-
* @param {Number} [emitSize=0]
|
|
3804
|
-
* @param {Number} [emitTime=0]
|
|
3805
|
-
* @param {Number} [emitRate=100]
|
|
3825
|
+
* @param {Vector2} position - World space position of the emitter
|
|
3826
|
+
* @param {Number} [angle=0] - Angle to emit the particles
|
|
3827
|
+
* @param {Number|Vector2} [emitSize=0] - World space size of the emitter (float for circle diameter, vec2 for rect)
|
|
3828
|
+
* @param {Number} [emitTime=0] - How long to stay alive (0 is forever)
|
|
3829
|
+
* @param {Number} [emitRate=100] - How many particles per second to spawn, does not emit if 0
|
|
3806
3830
|
* @param {Number} [emitConeAngle=PI] - Local angle to apply velocity to particles from emitter
|
|
3807
|
-
* @param {TileInfo} [tileInfo]
|
|
3831
|
+
* @param {TileInfo} [tileInfo] - Tile info to render particles (undefined is untextured)
|
|
3808
3832
|
* @param {Color} [colorStartA=Color()] - Color at start of life 1, randomized between start colors
|
|
3809
3833
|
* @param {Color} [colorStartB=Color()] - Color at start of life 2, randomized between start colors
|
|
3810
3834
|
* @param {Color} [colorEndA=Color(1,1,1,0)] - Color at end of life 1, randomized between end colors
|
|
@@ -3860,7 +3884,7 @@ class ParticleEmitter extends EngineObject
|
|
|
3860
3884
|
super(pos, vec2(), tileInfo, angle, undefined, renderOrder);
|
|
3861
3885
|
|
|
3862
3886
|
// emitter settings
|
|
3863
|
-
/** @property {Number} - World space size of the emitter (float for circle diameter, vec2 for rect) */
|
|
3887
|
+
/** @property {Number|Vector2} - World space size of the emitter (float for circle diameter, vec2 for rect) */
|
|
3864
3888
|
this.emitSize = emitSize
|
|
3865
3889
|
/** @property {Number} - How long to stay alive (0 is forever) */
|
|
3866
3890
|
this.emitTime = emitTime;
|
|
@@ -4392,7 +4416,7 @@ let glCanvas;
|
|
|
4392
4416
|
let glContext;
|
|
4393
4417
|
|
|
4394
4418
|
// WebGL internal variables not exposed to documentation
|
|
4395
|
-
let glActiveTexture, glShader, glArrayBuffer, glPositionData, glColorData, glBatchCount, glBatchAdditive, glAdditive;
|
|
4419
|
+
let glActiveTexture, glShader, glArrayBuffer, glVertexData, glPositionData, glColorData, glBatchCount, glBatchAdditive, glAdditive;
|
|
4396
4420
|
|
|
4397
4421
|
///////////////////////////////////////////////////////////////////////////////
|
|
4398
4422
|
|
|
@@ -4429,10 +4453,10 @@ function glInit()
|
|
|
4429
4453
|
);
|
|
4430
4454
|
|
|
4431
4455
|
// init buffers
|
|
4432
|
-
|
|
4456
|
+
glVertexData = new ArrayBuffer(gl_VERTEX_BUFFER_SIZE);
|
|
4457
|
+
glPositionData = new Float32Array(glVertexData);
|
|
4458
|
+
glColorData = new Uint32Array(glVertexData);
|
|
4433
4459
|
glArrayBuffer = glContext.createBuffer();
|
|
4434
|
-
glPositionData = new Float32Array(vertexData);
|
|
4435
|
-
glColorData = new Uint32Array(vertexData);
|
|
4436
4460
|
glBatchCount = 0;
|
|
4437
4461
|
}
|
|
4438
4462
|
|
|
@@ -4460,7 +4484,7 @@ function glPreRender()
|
|
|
4460
4484
|
glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
|
|
4461
4485
|
offset += size*typeSize;
|
|
4462
4486
|
}
|
|
4463
|
-
initVertexAttribArray('p', gl_FLOAT, 4, 4); // position & texture
|
|
4487
|
+
initVertexAttribArray('p', gl_FLOAT, 4, 4); // position & texture
|
|
4464
4488
|
initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
|
|
4465
4489
|
initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
|
|
4466
4490
|
|
|
@@ -4548,6 +4572,7 @@ function glCreateTexture(image)
|
|
|
4548
4572
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, filter);
|
|
4549
4573
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_S, gl_CLAMP_TO_EDGE);
|
|
4550
4574
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_T, gl_CLAMP_TO_EDGE);
|
|
4575
|
+
|
|
4551
4576
|
return texture;
|
|
4552
4577
|
}
|
|
4553
4578
|
|
|
@@ -4562,8 +4587,7 @@ function glFlush()
|
|
|
4562
4587
|
glContext.enable(gl_BLEND);
|
|
4563
4588
|
|
|
4564
4589
|
// draw all the sprites in the batch and reset the buffer
|
|
4565
|
-
glContext.bufferSubData(gl_ARRAY_BUFFER, 0,
|
|
4566
|
-
glPositionData.subarray(0, glBatchCount * gl_INDICIES_PER_VERT));
|
|
4590
|
+
glContext.bufferSubData(gl_ARRAY_BUFFER, 0, glVertexData);
|
|
4567
4591
|
glContext.drawArrays(gl_TRIANGLE_STRIP, 0, glBatchCount);
|
|
4568
4592
|
glBatchCount = 0;
|
|
4569
4593
|
glBatchAdditive = glAdditive;
|
|
@@ -4618,11 +4642,11 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdd
|
|
|
4618
4642
|
// setup 2 triangle strip quad
|
|
4619
4643
|
for(let i = vertCount, offset = glBatchCount * gl_INDICIES_PER_VERT; i--;)
|
|
4620
4644
|
{
|
|
4621
|
-
|
|
4622
|
-
glPositionData[offset++] = positionData[j
|
|
4623
|
-
glPositionData[offset++] = positionData[j
|
|
4624
|
-
glPositionData[offset++] = positionData[j
|
|
4625
|
-
glPositionData[offset++] = positionData[j
|
|
4645
|
+
const j = clamp(i-1, 0, 3)*4; // degenerate tri at ends
|
|
4646
|
+
glPositionData[offset++] = positionData[j+0];
|
|
4647
|
+
glPositionData[offset++] = positionData[j+1];
|
|
4648
|
+
glPositionData[offset++] = positionData[j+2];
|
|
4649
|
+
glPositionData[offset++] = positionData[j+3];
|
|
4626
4650
|
glColorData[offset++] = rgba;
|
|
4627
4651
|
glColorData[offset++] = rgbaAdditive;
|
|
4628
4652
|
}
|
|
@@ -4823,7 +4847,7 @@ const engineName = 'LittleJS';
|
|
|
4823
4847
|
* @type {String}
|
|
4824
4848
|
* @default
|
|
4825
4849
|
* @memberof Engine */
|
|
4826
|
-
const engineVersion = '1.8.
|
|
4850
|
+
const engineVersion = '1.8.9';
|
|
4827
4851
|
|
|
4828
4852
|
/** Frames per second to update objects
|
|
4829
4853
|
* @type {Number}
|
|
@@ -5006,7 +5030,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5006
5030
|
}
|
|
5007
5031
|
|
|
5008
5032
|
// setup html
|
|
5009
|
-
|
|
5033
|
+
const styleBody =
|
|
5010
5034
|
'margin:0;overflow:hidden;' + // fill the window
|
|
5011
5035
|
'background:#000;' + // set background color
|
|
5012
5036
|
'touch-action:none;' + // prevent mobile pinch to resize
|
|
@@ -5027,14 +5051,13 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5027
5051
|
|
|
5028
5052
|
// set canvas style
|
|
5029
5053
|
const styleCanvas =
|
|
5030
|
-
'position:absolute;' +
|
|
5031
|
-
'top:50%;left:50%;transform:translate(-50%,-50%);
|
|
5032
|
-
(canvasPixelated?'image-rendering:pixelated':''); // pixelated rendering
|
|
5054
|
+
'position:absolute;' + // position
|
|
5055
|
+
'top:50%;left:50%;transform:translate(-50%,-50%)'; // center
|
|
5033
5056
|
(glCanvas||mainCanvas).style = mainCanvas.style = overlayCanvas.style = styleCanvas;
|
|
5034
5057
|
|
|
5035
|
-
//
|
|
5036
|
-
|
|
5037
|
-
new Promise(
|
|
5058
|
+
// create promises for loading images
|
|
5059
|
+
const promises = imageSources.map((src, textureIndex)=>
|
|
5060
|
+
new Promise(resolve =>
|
|
5038
5061
|
{
|
|
5039
5062
|
const image = new Image;
|
|
5040
5063
|
image.onerror = image.onload = ()=>
|
|
@@ -5044,7 +5067,24 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5044
5067
|
}
|
|
5045
5068
|
image.src = src;
|
|
5046
5069
|
})
|
|
5047
|
-
)
|
|
5070
|
+
)
|
|
5071
|
+
|
|
5072
|
+
// draw splash screen
|
|
5073
|
+
showSplashScreen && promises.push(new Promise(resolve =>
|
|
5074
|
+
{
|
|
5075
|
+
let t = 0;
|
|
5076
|
+
console.log(`LittleJS Engine v${engineVersion}`);
|
|
5077
|
+
updateSplash();
|
|
5078
|
+
function updateSplash()
|
|
5079
|
+
{
|
|
5080
|
+
clearInput();
|
|
5081
|
+
drawEngineSplashScreen(t+=.01);
|
|
5082
|
+
t>1 ? resolve() : setTimeout(updateSplash,16);
|
|
5083
|
+
}
|
|
5084
|
+
}));
|
|
5085
|
+
|
|
5086
|
+
// load all of the images
|
|
5087
|
+
Promise.all(promises).then(()=>
|
|
5048
5088
|
{
|
|
5049
5089
|
// start the engine
|
|
5050
5090
|
gameInit();
|
|
@@ -5122,4 +5162,168 @@ function engineObjectsCallback(pos, size, callbackFunction, objects=engineObject
|
|
|
5122
5162
|
for (const o of objects)
|
|
5123
5163
|
pos.distanceSquared(o.pos) < sizeSquared && callbackFunction(o);
|
|
5124
5164
|
}
|
|
5165
|
+
}
|
|
5166
|
+
|
|
5167
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5168
|
+
// LittleJS splash screen and logo
|
|
5169
|
+
|
|
5170
|
+
function drawEngineSplashScreen(t)
|
|
5171
|
+
{
|
|
5172
|
+
const x = mainContext;
|
|
5173
|
+
const w = mainCanvas.width = innerWidth;
|
|
5174
|
+
const h = mainCanvas.height = innerHeight;
|
|
5175
|
+
{
|
|
5176
|
+
// background
|
|
5177
|
+
const p3 = percent(t, 1, .8);
|
|
5178
|
+
const p4 = percent(t, 0, .5);
|
|
5179
|
+
const g = x.createRadialGradient(w/2,h/2,0,w/2,h/2,Math.hypot(w,h)*.7);
|
|
5180
|
+
g.addColorStop(0,hsl(0,0,lerp(p4,0,p3/2),p3));
|
|
5181
|
+
g.addColorStop(1,hsl(0,0,0,p3));
|
|
5182
|
+
x.save();
|
|
5183
|
+
x.fillStyle = g;
|
|
5184
|
+
x.fillRect(0,0,w,h);
|
|
5185
|
+
}
|
|
5186
|
+
|
|
5187
|
+
// draw LittleJS logo...
|
|
5188
|
+
|
|
5189
|
+
const rect = (X, Y, W, H, C)=>
|
|
5190
|
+
{
|
|
5191
|
+
x.beginPath();
|
|
5192
|
+
x.rect(X,Y,W,C?H*p:H);
|
|
5193
|
+
x.fillStyle = C;
|
|
5194
|
+
C ? x.fill() : x.stroke();
|
|
5195
|
+
};
|
|
5196
|
+
const line = (X, Y, Z, W)=>
|
|
5197
|
+
{
|
|
5198
|
+
x.beginPath();
|
|
5199
|
+
x.lineTo(X,Y);
|
|
5200
|
+
x.lineTo(Z,W);
|
|
5201
|
+
x.stroke();
|
|
5202
|
+
};
|
|
5203
|
+
const circle = (X, Y, R, A=0, B=2*PI, C, F)=>
|
|
5204
|
+
{
|
|
5205
|
+
const D = (A+B)/2, E = p*(B-A)/2;
|
|
5206
|
+
x.beginPath();
|
|
5207
|
+
F && x.lineTo(X,Y);
|
|
5208
|
+
x.arc(X,Y,R,D-E,D+E);
|
|
5209
|
+
x.fillStyle = C;
|
|
5210
|
+
C ? x.fill() : x.stroke();
|
|
5211
|
+
};
|
|
5212
|
+
const color = (c=0, l=0) =>
|
|
5213
|
+
hsl([.98,.3,.57,.14][c%4]-10,.8,[0,.3,.5,.8,.9][l]);
|
|
5214
|
+
const alpha = wave(1,1,t);
|
|
5215
|
+
const p = percent(alpha, .1, .5);
|
|
5216
|
+
|
|
5217
|
+
// setup
|
|
5218
|
+
x.translate(w/2,h/2);
|
|
5219
|
+
const size = min(6, min(w,h)/99); // fit to screen
|
|
5220
|
+
x.scale(size,size);
|
|
5221
|
+
x.translate(-40,-35);
|
|
5222
|
+
x.lineJoin = x.lineCap = 'round';
|
|
5223
|
+
x.lineWidth = 1+p;
|
|
5224
|
+
|
|
5225
|
+
// drawing effect
|
|
5226
|
+
const p2 = percent(alpha,.1,1);
|
|
5227
|
+
x.setLineDash([99*p2,99]);
|
|
5228
|
+
|
|
5229
|
+
// cab top
|
|
5230
|
+
rect(7,17,18,-8,color(2,2));
|
|
5231
|
+
rect(7,9,18,4,color(2,3));
|
|
5232
|
+
rect(25,9,8,8,color(2,1));
|
|
5233
|
+
rect(25,9,-18,8);
|
|
5234
|
+
rect(25,9,8,8);
|
|
5235
|
+
|
|
5236
|
+
// cab
|
|
5237
|
+
rect(25,17,7,22,color());
|
|
5238
|
+
rect(11,40,14,-23,color(1,1));
|
|
5239
|
+
rect(11,17,14,17,color(1,2));
|
|
5240
|
+
rect(11,17,14,9,color(1,3));
|
|
5241
|
+
rect(15,31,6,-9,color(2,2));
|
|
5242
|
+
circle(15,23,5,0,PI/2,color(2,4),1);
|
|
5243
|
+
rect(25,17,-14,23);
|
|
5244
|
+
rect(21,22,-6,9);
|
|
5245
|
+
|
|
5246
|
+
// little stack
|
|
5247
|
+
rect(37,14,9,6,color(3,2));
|
|
5248
|
+
rect(37,14,4,6,color(3,3));
|
|
5249
|
+
rect(37,14,9,6);
|
|
5250
|
+
|
|
5251
|
+
// big stack
|
|
5252
|
+
rect(50,20,10,-10,color(0,1));
|
|
5253
|
+
rect(50,20,6,-10,color(0,2));
|
|
5254
|
+
rect(50,20,3,-10,color(0,3));
|
|
5255
|
+
rect(50,10,10,10);
|
|
5256
|
+
circle(55,2,11.4,.5,PI-.5,color(3,3));
|
|
5257
|
+
circle(55,2,11.4,.5,PI/2,color(3,2),1);
|
|
5258
|
+
circle(55,2,11.4,.5,PI-.5);
|
|
5259
|
+
rect(45,7,20,-7,color(0,2));
|
|
5260
|
+
rect(45,0,20,3,color(0,3));
|
|
5261
|
+
rect(45,0,20,7);
|
|
5262
|
+
|
|
5263
|
+
// engine
|
|
5264
|
+
for (let i=5; i--;)
|
|
5265
|
+
{
|
|
5266
|
+
// stagger radius to fix slight seam
|
|
5267
|
+
circle(60-i*6,30, 9.9,0,2*PI,color(i+2,3));
|
|
5268
|
+
circle(60-i*6,30,10.0,-.5,PI+.5,color(i+2,2));
|
|
5269
|
+
circle(60-i*6,30,10.1,.5,PI-.5,color(i+2,1));
|
|
5270
|
+
}
|
|
5271
|
+
|
|
5272
|
+
// engine outline
|
|
5273
|
+
circle(36,30,10,PI/2,PI*3/2);
|
|
5274
|
+
circle(47,30,10,PI/2,PI*3/2);
|
|
5275
|
+
circle(60,30,10);
|
|
5276
|
+
line(36,20,60,20);
|
|
5277
|
+
|
|
5278
|
+
// engine front light
|
|
5279
|
+
circle(60,30,4,PI,3*PI,color(3,2));
|
|
5280
|
+
circle(60,30,4,PI,2*PI,color(3,3));
|
|
5281
|
+
circle(60,30,4,PI,3*PI);
|
|
5282
|
+
|
|
5283
|
+
// front brush
|
|
5284
|
+
for (let i=6; i--;)
|
|
5285
|
+
{
|
|
5286
|
+
x.beginPath();
|
|
5287
|
+
x.lineTo(53,54);
|
|
5288
|
+
x.lineTo(53,40);
|
|
5289
|
+
x.lineTo(53+(1+i*2.9)*p,40);
|
|
5290
|
+
x.lineTo(53+(4+i*3.5)*p,54);
|
|
5291
|
+
x.fillStyle = color(0,i%2+2);
|
|
5292
|
+
x.fill() || i%2 && x.stroke();
|
|
5293
|
+
}
|
|
5294
|
+
|
|
5295
|
+
// wheels
|
|
5296
|
+
rect(6,40,5,5);
|
|
5297
|
+
rect(6,40,5,5,color());
|
|
5298
|
+
rect(15,54,38,-14,color());
|
|
5299
|
+
for (let i=3; i--;)
|
|
5300
|
+
for (let j=2; j--;)
|
|
5301
|
+
{
|
|
5302
|
+
circle(15*i+15,47,j?7:1,PI,3*PI,color(i,3));
|
|
5303
|
+
x.stroke();
|
|
5304
|
+
circle(15*i+15,47,j?7:1,0,PI,color(i,2));
|
|
5305
|
+
x.stroke();
|
|
5306
|
+
}
|
|
5307
|
+
line(6,40,68,40); // center
|
|
5308
|
+
line(77,54,4,54); // bottom
|
|
5309
|
+
|
|
5310
|
+
// draw engine name
|
|
5311
|
+
const s = engineName;
|
|
5312
|
+
x.font = '900 16px arial';
|
|
5313
|
+
x.textAlign = 'center';
|
|
5314
|
+
x.textBaseline = 'top';
|
|
5315
|
+
x.lineWidth = 1+p*3;
|
|
5316
|
+
let w2 = 0;
|
|
5317
|
+
for (let i=0; i<s.length; ++i)
|
|
5318
|
+
w2 += x.measureText(s[i]).width;
|
|
5319
|
+
for (let j=2; j--;)
|
|
5320
|
+
for (let i=0, X=41-w2/2; i<s.length; ++i)
|
|
5321
|
+
{
|
|
5322
|
+
x.fillStyle = color(i,2);
|
|
5323
|
+
const w = x.measureText(s[i]).width;
|
|
5324
|
+
x[j?'strokeText':'fillText'](s[i],X+w/2,55.5,17*p);
|
|
5325
|
+
X += w;
|
|
5326
|
+
}
|
|
5327
|
+
|
|
5328
|
+
x.restore();
|
|
5125
5329
|
}
|