littlejsengine 1.7.13 → 1.7.21
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/build/littlejs.d.ts +152 -18
- package/build/littlejs.esm.js +158 -115
- package/build/littlejs.esm.min.js +1 -1
- package/build/littlejs.js +158 -115
- package/build/littlejs.min.js +1 -1
- package/build/littlejs.release.js +158 -115
- package/examples/electron/build.js +2 -0
- package/examples/js13k/build.js +2 -0
- package/examples/screenshot.jpg +0 -0
- package/examples/starter/build.js +2 -0
- package/examples/starter/game.js +1 -1
- package/examples/typescript/build.js +2 -0
- package/package.json +1 -1
- package/src/engine.js +10 -7
- package/src/engineAudio.js +67 -41
- package/src/engineBuild.js +23 -7
- package/src/engineDraw.js +2 -2
- package/src/engineInput.js +22 -10
- package/src/engineWebGL.js +43 -43
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
// LittleJS - MIT License - Copyright 2021 Frank Force
|
|
2
2
|
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* LittleJS - Release Mode
|
|
5
7
|
* - This file is used for release builds in place of engineDebug.js
|
|
6
8
|
* - Debug functionality is disabled to reduce size and increase performance
|
|
7
9
|
*/
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
let showWatermark = 0;
|
|
12
14
|
let debugKeyCode = 0;
|
|
@@ -41,7 +43,7 @@ function debugSaveCanvas (){}
|
|
|
41
43
|
* @namespace Utilities
|
|
42
44
|
*/
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
|
|
45
47
|
|
|
46
48
|
/** A shortcut to get Math.PI
|
|
47
49
|
* @type {Number}
|
|
@@ -696,7 +698,7 @@ class Timer
|
|
|
696
698
|
* @namespace Settings
|
|
697
699
|
*/
|
|
698
700
|
|
|
699
|
-
|
|
701
|
+
|
|
700
702
|
|
|
701
703
|
///////////////////////////////////////////////////////////////////////////////
|
|
702
704
|
// Camera settings
|
|
@@ -944,7 +946,7 @@ let medalsPreventUnlock;
|
|
|
944
946
|
* LittleJS Object System
|
|
945
947
|
*/
|
|
946
948
|
|
|
947
|
-
|
|
949
|
+
|
|
948
950
|
|
|
949
951
|
/**
|
|
950
952
|
* LittleJS Object Base Object Class
|
|
@@ -1340,7 +1342,7 @@ class EngineObject
|
|
|
1340
1342
|
* @namespace Draw
|
|
1341
1343
|
*/
|
|
1342
1344
|
|
|
1343
|
-
|
|
1345
|
+
|
|
1344
1346
|
|
|
1345
1347
|
/** The primary 2D canvas visible to the user
|
|
1346
1348
|
* @type {HTMLCanvasElement}
|
|
@@ -1531,12 +1533,12 @@ function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainCont
|
|
|
1531
1533
|
{
|
|
1532
1534
|
if (!screenSpace)
|
|
1533
1535
|
{
|
|
1534
|
-
//
|
|
1536
|
+
// transform from world space to screen space
|
|
1535
1537
|
pos = worldToScreen(pos);
|
|
1536
1538
|
size = size.scale(cameraScale);
|
|
1537
1539
|
}
|
|
1538
1540
|
context.save();
|
|
1539
|
-
context.translate(pos.x+.5
|
|
1541
|
+
context.translate(pos.x+.5, pos.y+.5);
|
|
1540
1542
|
context.rotate(angle);
|
|
1541
1543
|
context.scale(mirror ? -size.x : size.x, size.y);
|
|
1542
1544
|
drawFunction(context);
|
|
@@ -1721,7 +1723,7 @@ function toggleFullscreen()
|
|
|
1721
1723
|
* @namespace Input
|
|
1722
1724
|
*/
|
|
1723
1725
|
|
|
1724
|
-
|
|
1726
|
+
|
|
1725
1727
|
|
|
1726
1728
|
/** Returns true if device key is down
|
|
1727
1729
|
* @param {Number} key
|
|
@@ -1905,18 +1907,26 @@ function mouseToScreen(mousePos)
|
|
|
1905
1907
|
const stickData = [];
|
|
1906
1908
|
function gamepadsUpdate()
|
|
1907
1909
|
{
|
|
1908
|
-
|
|
1910
|
+
// update touch gamepad if enabled
|
|
1911
|
+
if (touchGamepadEnable && isTouchDevice)
|
|
1909
1912
|
{
|
|
1910
|
-
//
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
+
// create the touch gamepad if it doesn't exist
|
|
1914
|
+
if (!touchGamepadButtons)
|
|
1915
|
+
createTouchGamepad();
|
|
1913
1916
|
|
|
1914
|
-
|
|
1915
|
-
const data = inputData[1] || (inputData[1] = []);
|
|
1916
|
-
for (let i=10; i--;)
|
|
1917
|
+
if (touchGamepadTimer.isSet())
|
|
1917
1918
|
{
|
|
1918
|
-
|
|
1919
|
-
|
|
1919
|
+
// read virtual analog stick
|
|
1920
|
+
const sticks = stickData[0] || (stickData[0] = []);
|
|
1921
|
+
sticks[0] = vec2(touchGamepadStick.x, -touchGamepadStick.y); // flip vertical
|
|
1922
|
+
|
|
1923
|
+
// read virtual gamepad buttons
|
|
1924
|
+
const data = inputData[1] || (inputData[1] = []);
|
|
1925
|
+
for (let i=10; i--;)
|
|
1926
|
+
{
|
|
1927
|
+
const j = i == 3 ? 2 : i == 2 ? 3 : i; // fix button locations
|
|
1928
|
+
data[j] = touchGamepadButtons[i] ? 1 + 2*!gamepadIsDown(j,0) : 4*gamepadIsDown(j,0);
|
|
1929
|
+
}
|
|
1920
1930
|
}
|
|
1921
1931
|
}
|
|
1922
1932
|
|
|
@@ -2013,6 +2023,10 @@ if (isTouchDevice)
|
|
|
2013
2023
|
// set was touching
|
|
2014
2024
|
wasTouching = touching;
|
|
2015
2025
|
|
|
2026
|
+
// prevent default handling like copy and magnifier lens
|
|
2027
|
+
if (document.hasFocus()) // allow document to get focus
|
|
2028
|
+
e.preventDefault();
|
|
2029
|
+
|
|
2016
2030
|
// must return true so the document will get focus
|
|
2017
2031
|
return true;
|
|
2018
2032
|
}
|
|
@@ -2025,7 +2039,7 @@ if (isTouchDevice)
|
|
|
2025
2039
|
let touchGamepadTimer = new Timer, touchGamepadButtons, touchGamepadStick;
|
|
2026
2040
|
|
|
2027
2041
|
// create the touch gamepad, called automatically by the engine
|
|
2028
|
-
|
|
2042
|
+
function createTouchGamepad()
|
|
2029
2043
|
{
|
|
2030
2044
|
// touch input internal variables
|
|
2031
2045
|
touchGamepadButtons = [];
|
|
@@ -2159,7 +2173,7 @@ function touchGamepadRender()
|
|
|
2159
2173
|
* @namespace Audio
|
|
2160
2174
|
*/
|
|
2161
2175
|
|
|
2162
|
-
|
|
2176
|
+
|
|
2163
2177
|
|
|
2164
2178
|
/**
|
|
2165
2179
|
* Sound Object - Stores a zzfx sound for later use and can be played positionally
|
|
@@ -2195,8 +2209,9 @@ class Sound
|
|
|
2195
2209
|
if (zzfxSound)
|
|
2196
2210
|
{
|
|
2197
2211
|
// generate zzfx sound now for fast playback
|
|
2198
|
-
this.randomness = zzfxSound[1] || (zzfxSound[1] = 0);
|
|
2199
|
-
this.
|
|
2212
|
+
this.randomness = zzfxSound[1] || (zzfxSound[1] = 0);
|
|
2213
|
+
this.sampleChannels = [zzfxG(...zzfxSound)];
|
|
2214
|
+
this.sampleRate = zzfxR;
|
|
2200
2215
|
}
|
|
2201
2216
|
}
|
|
2202
2217
|
|
|
@@ -2205,11 +2220,12 @@ class Sound
|
|
|
2205
2220
|
* @param {Number} [volume=1] - How much to scale volume by (in addition to range fade)
|
|
2206
2221
|
* @param {Number} [pitch=1] - How much to scale pitch by (also adjusted by this.randomness)
|
|
2207
2222
|
* @param {Number} [randomnessScale=1] - How much to scale randomness
|
|
2208
|
-
* @
|
|
2223
|
+
* @param {Boolean} [loop=0] - Should the sound loop
|
|
2224
|
+
* @return {AudioBufferSourceNode} - The audio source node
|
|
2209
2225
|
*/
|
|
2210
|
-
play(pos, volume=1, pitch=1, randomnessScale=1)
|
|
2226
|
+
play(pos, volume=1, pitch=1, randomnessScale=1, loop=0)
|
|
2211
2227
|
{
|
|
2212
|
-
if (!soundEnable || !this.
|
|
2228
|
+
if (!soundEnable || !this.sampleChannels) return;
|
|
2213
2229
|
|
|
2214
2230
|
let pan;
|
|
2215
2231
|
if (pos)
|
|
@@ -2232,43 +2248,80 @@ class Sound
|
|
|
2232
2248
|
|
|
2233
2249
|
// play the sound
|
|
2234
2250
|
const playbackRate = pitch + pitch * this.randomness*randomnessScale*rand(-1,1);
|
|
2235
|
-
return playSamples(
|
|
2251
|
+
return this.source = playSamples(this.sampleChannels, volume, playbackRate, pan, loop, this.sampleRate);
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
/** Stop the last instance of this sound that was played */
|
|
2255
|
+
stop()
|
|
2256
|
+
{
|
|
2257
|
+
if (this.source)
|
|
2258
|
+
this.source.stop();
|
|
2259
|
+
this.source = 0;
|
|
2236
2260
|
}
|
|
2237
2261
|
|
|
2238
2262
|
/** Play the sound as a note with a semitone offset
|
|
2239
2263
|
* @param {Number} semitoneOffset - How many semitones to offset pitch
|
|
2240
2264
|
* @param {Vector2} [pos] - World space position to play the sound, sound is not attenuated if null
|
|
2241
2265
|
* @param {Number} [volume=1] - How much to scale volume by (in addition to range fade)
|
|
2242
|
-
* @return {AudioBufferSourceNode} - The audio
|
|
2266
|
+
* @return {AudioBufferSourceNode} - The audio source node
|
|
2243
2267
|
*/
|
|
2244
2268
|
playNote(semitoneOffset, pos, volume)
|
|
2245
2269
|
{ return this.play(pos, volume, 2**(semitoneOffset/12), 0); }
|
|
2270
|
+
|
|
2271
|
+
/** Get how long this sound is in seconds
|
|
2272
|
+
* @return {Number} - How long the sound is in seconds (undefined if loading)
|
|
2273
|
+
*/
|
|
2274
|
+
getDuration()
|
|
2275
|
+
{ return this.sampleChannels && this.sampleChannels[0].length / this.sampleRate; }
|
|
2276
|
+
|
|
2277
|
+
/** Check if the last instance of this sound is playing
|
|
2278
|
+
* @return {Boolean} - True if the sound is playing
|
|
2279
|
+
*/
|
|
2280
|
+
isPlaying() { return this.source && !this.source.ended; }
|
|
2281
|
+
|
|
2282
|
+
/** Check if sound is loading, for sounds fetched from a url
|
|
2283
|
+
* @return {Boolean} - True if sound is loading and not ready to play
|
|
2284
|
+
*/
|
|
2285
|
+
isLoading() { return !this.sampleChannels; }
|
|
2246
2286
|
}
|
|
2247
2287
|
|
|
2248
2288
|
/**
|
|
2249
2289
|
* Sound Wave Object - Stores a wave sound for later use and can be played positionally
|
|
2290
|
+
* - this can be used to play wave, mp3, and ogg files
|
|
2291
|
+
* @example
|
|
2292
|
+
* // create a sound
|
|
2293
|
+
* const sound_example = new SoundWave('sound.mp3');
|
|
2294
|
+
*
|
|
2295
|
+
* // play the sound
|
|
2296
|
+
* sound_example.play();
|
|
2250
2297
|
*/
|
|
2251
2298
|
class SoundWave extends Sound
|
|
2252
2299
|
{
|
|
2253
2300
|
/** Create a sound object and cache the wave file for later use
|
|
2254
|
-
* @param {String}
|
|
2255
|
-
* @param {Number} [randomness
|
|
2301
|
+
* @param {String} filename - Filename of audio file to load
|
|
2302
|
+
* @param {Number} [randomness=0] - How much to randomize frequency each time sound plays
|
|
2256
2303
|
* @param {Number} [range=soundDefaultRange] - World space max range of sound, will not play if camera is farther away
|
|
2257
2304
|
* @param {Number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering off
|
|
2258
2305
|
*/
|
|
2259
|
-
constructor(
|
|
2306
|
+
constructor(filename, randomness=0, range, taper)
|
|
2260
2307
|
{
|
|
2261
2308
|
super(0, range, taper);
|
|
2262
2309
|
this.randomness = randomness;
|
|
2263
2310
|
|
|
2264
2311
|
if (!soundEnable) return;
|
|
2265
|
-
if (!
|
|
2312
|
+
if (!soundDecoderContext)
|
|
2266
2313
|
soundDecoderContext = new AudioContext;
|
|
2267
2314
|
|
|
2268
|
-
fetch(
|
|
2315
|
+
fetch(filename)
|
|
2269
2316
|
.then(response => response.arrayBuffer())
|
|
2270
|
-
.then(arrayBuffer =>
|
|
2271
|
-
.then(audioBuffer =>
|
|
2317
|
+
.then(arrayBuffer => soundDecoderContext.decodeAudioData(arrayBuffer))
|
|
2318
|
+
.then(audioBuffer =>
|
|
2319
|
+
{
|
|
2320
|
+
this.sampleChannels = [];
|
|
2321
|
+
for (let i = audioBuffer.numberOfChannels; i--;)
|
|
2322
|
+
this.sampleChannels[i] = audioBuffer.getChannelData(i);
|
|
2323
|
+
this.sampleRate = audioBuffer.sampleRate;
|
|
2324
|
+
});
|
|
2272
2325
|
}
|
|
2273
2326
|
}
|
|
2274
2327
|
let soundDecoderContext; // audio context used only to decode audio files
|
|
@@ -2303,48 +2356,34 @@ let soundDecoderContext; // audio context used only to decode audio files
|
|
|
2303
2356
|
* // play the music
|
|
2304
2357
|
* music_example.play();
|
|
2305
2358
|
*/
|
|
2306
|
-
class Music
|
|
2359
|
+
class Music extends Sound
|
|
2307
2360
|
{
|
|
2308
2361
|
/** Create a music object and cache the zzfx music samples for later use
|
|
2309
2362
|
* @param {Array} zzfxMusic - Array of zzfx music parameters
|
|
2310
2363
|
*/
|
|
2311
2364
|
constructor(zzfxMusic)
|
|
2312
2365
|
{
|
|
2313
|
-
|
|
2366
|
+
super();
|
|
2314
2367
|
|
|
2315
|
-
|
|
2368
|
+
if (!soundEnable) return;
|
|
2369
|
+
this.randomness = 0;
|
|
2370
|
+
this.sampleChannels = zzfxM(...zzfxMusic);
|
|
2371
|
+
this.sampleRate = zzfxR;
|
|
2316
2372
|
}
|
|
2317
2373
|
|
|
2318
2374
|
/** Play the music
|
|
2319
2375
|
* @param {Number} [volume=1] - How much to scale volume by
|
|
2320
|
-
* @param {Boolean} [loop=1] - True if the music should loop
|
|
2321
|
-
* @return {AudioBufferSourceNode} - The audio node
|
|
2376
|
+
* @param {Boolean} [loop=1] - True if the music should loop
|
|
2377
|
+
* @return {AudioBufferSourceNode} - The audio source node
|
|
2322
2378
|
*/
|
|
2323
2379
|
play(volume, loop = 1)
|
|
2324
|
-
{
|
|
2325
|
-
if (!soundEnable) return;
|
|
2326
|
-
|
|
2327
|
-
return this.source = playSamples(this.cachedSamples, volume, 1, 0, loop);
|
|
2328
|
-
}
|
|
2329
|
-
|
|
2330
|
-
/** Stop the music */
|
|
2331
|
-
stop()
|
|
2332
|
-
{
|
|
2333
|
-
if (this.source)
|
|
2334
|
-
this.source.stop();
|
|
2335
|
-
this.source = 0;
|
|
2336
|
-
}
|
|
2337
|
-
|
|
2338
|
-
/** Check if music is playing
|
|
2339
|
-
* @return {Boolean}
|
|
2340
|
-
*/
|
|
2341
|
-
isPlaying() { return this.source; }
|
|
2380
|
+
{ return super.play(0, volume, 1, 1, loop); }
|
|
2342
2381
|
}
|
|
2343
2382
|
|
|
2344
|
-
/** Play an mp3 or wav audio from a local file or url
|
|
2383
|
+
/** Play an mp3, ogg, or wav audio from a local file or url
|
|
2345
2384
|
* @param {String} url - Location of sound file to play
|
|
2346
2385
|
* @param {Number} [volume=1] - How much to scale volume by
|
|
2347
|
-
* @param {Boolean} [loop=1] - True if the music should loop
|
|
2386
|
+
* @param {Boolean} [loop=1] - True if the music should loop
|
|
2348
2387
|
* @return {HTMLAudioElement} - The audio element for this sound
|
|
2349
2388
|
* @memberof Audio */
|
|
2350
2389
|
function playAudioFile(url, volume=1, loop=1)
|
|
@@ -2408,9 +2447,10 @@ let audioContext;
|
|
|
2408
2447
|
* @param {Number} [rate=1] - The playback rate to use
|
|
2409
2448
|
* @param {Number} [pan=0] - How much to apply stereo panning
|
|
2410
2449
|
* @param {Boolean} [loop=0] - True if the sound should loop when it reaches the end
|
|
2450
|
+
* @param {Number} [sampleRate=44100] - Sample rate for the sound
|
|
2411
2451
|
* @return {AudioBufferSourceNode} - The audio node of the sound played
|
|
2412
2452
|
* @memberof Audio */
|
|
2413
|
-
function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0)
|
|
2453
|
+
function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0, sampleRate=zzfxR)
|
|
2414
2454
|
{
|
|
2415
2455
|
if (!soundEnable) return;
|
|
2416
2456
|
|
|
@@ -2427,7 +2467,7 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0)
|
|
|
2427
2467
|
}
|
|
2428
2468
|
|
|
2429
2469
|
// create buffer and source
|
|
2430
|
-
const buffer = audioContext.createBuffer(sampleChannels.length, sampleChannels[0].length,
|
|
2470
|
+
const buffer = audioContext.createBuffer(sampleChannels.length, sampleChannels[0].length, sampleRate),
|
|
2431
2471
|
source = audioContext.createBufferSource();
|
|
2432
2472
|
|
|
2433
2473
|
// copy samples to buffer and setup source
|
|
@@ -2686,7 +2726,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
|
|
|
2686
2726
|
* @namespace TileCollision
|
|
2687
2727
|
*/
|
|
2688
2728
|
|
|
2689
|
-
|
|
2729
|
+
|
|
2690
2730
|
|
|
2691
2731
|
/** The tile collision layer array, use setTileCollisionData and getTileCollisionData to access
|
|
2692
2732
|
* @type {Array}
|
|
@@ -3039,7 +3079,7 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
3039
3079
|
* LittleJS Particle System
|
|
3040
3080
|
*/
|
|
3041
3081
|
|
|
3042
|
-
|
|
3082
|
+
|
|
3043
3083
|
|
|
3044
3084
|
/**
|
|
3045
3085
|
* Particle Emitter - Spawns particles with the given settings
|
|
@@ -3349,7 +3389,7 @@ class Particle extends EngineObject
|
|
|
3349
3389
|
* @namespace Medals
|
|
3350
3390
|
*/
|
|
3351
3391
|
|
|
3352
|
-
|
|
3392
|
+
|
|
3353
3393
|
|
|
3354
3394
|
/** List of all medals
|
|
3355
3395
|
* @type {Array}
|
|
@@ -3673,7 +3713,7 @@ class Newgrounds
|
|
|
3673
3713
|
* @namespace WebGL
|
|
3674
3714
|
*/
|
|
3675
3715
|
|
|
3676
|
-
|
|
3716
|
+
|
|
3677
3717
|
|
|
3678
3718
|
/** The WebGL canvas which appears above the main canvas and below the overlay canvas
|
|
3679
3719
|
* @type {HTMLCanvasElement}
|
|
@@ -3695,7 +3735,7 @@ let glActiveTexture, glShader, glArrayBuffer, glPositionData, glColorData, glBat
|
|
|
3695
3735
|
|
|
3696
3736
|
///////////////////////////////////////////////////////////////////////////////
|
|
3697
3737
|
|
|
3698
|
-
//
|
|
3738
|
+
// Initalize WebGL, called automatically by the engine
|
|
3699
3739
|
function glInit()
|
|
3700
3740
|
{
|
|
3701
3741
|
// create the canvas and tile texture
|
|
@@ -3734,6 +3774,48 @@ function glInit()
|
|
|
3734
3774
|
glBatchCount = 0;
|
|
3735
3775
|
}
|
|
3736
3776
|
|
|
3777
|
+
// Setup render each frame, called automatically by engine
|
|
3778
|
+
function glPreRender()
|
|
3779
|
+
{
|
|
3780
|
+
// clear and set to same size as main canvas
|
|
3781
|
+
glContext.viewport(0, 0, glCanvas.width = mainCanvas.width, glCanvas.height = mainCanvas.height);
|
|
3782
|
+
glContext.clear(gl_COLOR_BUFFER_BIT);
|
|
3783
|
+
|
|
3784
|
+
// set up the shader
|
|
3785
|
+
glContext.useProgram(glShader);
|
|
3786
|
+
glContext.activeTexture(gl_TEXTURE0);
|
|
3787
|
+
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = glTileTexture);
|
|
3788
|
+
glContext.bindBuffer(gl_ARRAY_BUFFER, glArrayBuffer);
|
|
3789
|
+
glContext.bufferData(gl_ARRAY_BUFFER, gl_VERTEX_BUFFER_SIZE, gl_DYNAMIC_DRAW);
|
|
3790
|
+
glSetBlendMode();
|
|
3791
|
+
|
|
3792
|
+
// set vertex attributes
|
|
3793
|
+
let offset = 0;
|
|
3794
|
+
const initVertexAttribArray = (name, type, typeSize, size, normalize=0)=>
|
|
3795
|
+
{
|
|
3796
|
+
const location = glContext.getAttribLocation(glShader, name);
|
|
3797
|
+
glContext.enableVertexAttribArray(location);
|
|
3798
|
+
glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
|
|
3799
|
+
offset += size*typeSize;
|
|
3800
|
+
}
|
|
3801
|
+
initVertexAttribArray('p', gl_FLOAT, 4, 2); // position
|
|
3802
|
+
initVertexAttribArray('t', gl_FLOAT, 4, 2); // texture coords
|
|
3803
|
+
initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
|
|
3804
|
+
initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
|
|
3805
|
+
|
|
3806
|
+
// build the transform matrix
|
|
3807
|
+
const sx = 2 * cameraScale / mainCanvas.width;
|
|
3808
|
+
const sy = 2 * cameraScale / mainCanvas.height;
|
|
3809
|
+
glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader, 'm'), 0,
|
|
3810
|
+
new Float32Array([
|
|
3811
|
+
sx, 0, 0, 0,
|
|
3812
|
+
0, sy, 0, 0,
|
|
3813
|
+
1, 1, -1, 1,
|
|
3814
|
+
-1-sx*cameraPos.x, -1-sy*cameraPos.y, 0, 0
|
|
3815
|
+
])
|
|
3816
|
+
);
|
|
3817
|
+
}
|
|
3818
|
+
|
|
3737
3819
|
/** Set the WebGl blend mode, normally you should call setBlendMode instead
|
|
3738
3820
|
* @param {Boolean} [additive=0]
|
|
3739
3821
|
* @memberof WebGL */
|
|
@@ -3813,48 +3895,6 @@ function glCreateTexture(image)
|
|
|
3813
3895
|
return texture;
|
|
3814
3896
|
}
|
|
3815
3897
|
|
|
3816
|
-
// called automatically by engine before render
|
|
3817
|
-
function glPreRender()
|
|
3818
|
-
{
|
|
3819
|
-
// clear and set to same size as main canvas
|
|
3820
|
-
glContext.viewport(0, 0, glCanvas.width = mainCanvas.width, glCanvas.height = mainCanvas.height);
|
|
3821
|
-
glContext.clear(gl_COLOR_BUFFER_BIT);
|
|
3822
|
-
|
|
3823
|
-
// set up the shader
|
|
3824
|
-
glContext.useProgram(glShader);
|
|
3825
|
-
glContext.activeTexture(gl_TEXTURE0);
|
|
3826
|
-
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = glTileTexture);
|
|
3827
|
-
glContext.bindBuffer(gl_ARRAY_BUFFER, glArrayBuffer);
|
|
3828
|
-
glContext.bufferData(gl_ARRAY_BUFFER, gl_VERTEX_BUFFER_SIZE, gl_DYNAMIC_DRAW);
|
|
3829
|
-
glSetBlendMode();
|
|
3830
|
-
|
|
3831
|
-
// set vertex attributes
|
|
3832
|
-
let offset = 0;
|
|
3833
|
-
const initVertexAttribArray = (name, type, typeSize, size, normalize=0)=>
|
|
3834
|
-
{
|
|
3835
|
-
const location = glContext.getAttribLocation(glShader, name);
|
|
3836
|
-
glContext.enableVertexAttribArray(location);
|
|
3837
|
-
glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
|
|
3838
|
-
offset += size*typeSize;
|
|
3839
|
-
}
|
|
3840
|
-
initVertexAttribArray('p', gl_FLOAT, 4, 2); // position
|
|
3841
|
-
initVertexAttribArray('t', gl_FLOAT, 4, 2); // texture coords
|
|
3842
|
-
initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
|
|
3843
|
-
initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
|
|
3844
|
-
|
|
3845
|
-
// build the transform matrix
|
|
3846
|
-
const sx = 2 * cameraScale / mainCanvas.width;
|
|
3847
|
-
const sy = 2 * cameraScale / mainCanvas.height;
|
|
3848
|
-
glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader, 'm'), 0,
|
|
3849
|
-
new Float32Array([
|
|
3850
|
-
sx, 0, 0, 0,
|
|
3851
|
-
0, sy, 0, 0,
|
|
3852
|
-
1, 1, -1, 1,
|
|
3853
|
-
-1-sx*cameraPos.x, -1-sy*cameraPos.y, 0, 0
|
|
3854
|
-
])
|
|
3855
|
-
);
|
|
3856
|
-
}
|
|
3857
|
-
|
|
3858
3898
|
/** Draw all sprites and clear out the buffer, called automatically by the system whenever necessary
|
|
3859
3899
|
* @memberof WebGL */
|
|
3860
3900
|
function glFlush()
|
|
@@ -4112,7 +4152,7 @@ gl_VERTEX_BUFFER_SIZE = gl_MAX_BATCH * gl_VERTEX_BYTE_STRIDE;
|
|
|
4112
4152
|
* @namespace Engine
|
|
4113
4153
|
*/
|
|
4114
4154
|
|
|
4115
|
-
|
|
4155
|
+
|
|
4116
4156
|
|
|
4117
4157
|
/** Name of engine
|
|
4118
4158
|
* @type {String}
|
|
@@ -4124,7 +4164,7 @@ const engineName = 'LittleJS';
|
|
|
4124
4164
|
* @type {String}
|
|
4125
4165
|
* @default
|
|
4126
4166
|
* @memberof Engine */
|
|
4127
|
-
const engineVersion = '1.7.
|
|
4167
|
+
const engineVersion = '1.7.21';
|
|
4128
4168
|
|
|
4129
4169
|
/** Frames per second to update objects
|
|
4130
4170
|
* @type {Number}
|
|
@@ -4194,11 +4234,13 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4194
4234
|
debug && (tileImage.onload=()=>ASSERT(1)); // tile sheet can not reloaded
|
|
4195
4235
|
|
|
4196
4236
|
// setup html
|
|
4197
|
-
const styleBody =
|
|
4198
|
-
'
|
|
4199
|
-
'
|
|
4200
|
-
'
|
|
4201
|
-
'
|
|
4237
|
+
const styleBody =
|
|
4238
|
+
'margin:0;overflow:hidden;' + // fill the window
|
|
4239
|
+
'background:#000;' + // set background color
|
|
4240
|
+
'touch-action:none;' + // prevent mobile pinch to resize
|
|
4241
|
+
'user-select:none;' + // prevent mobile hold to select
|
|
4242
|
+
'-webkit-user-select:none;' + // compatibility for ios
|
|
4243
|
+
'-webkit-touch-callout:none'; // compatibility for ios
|
|
4202
4244
|
document.body.style = styleBody;
|
|
4203
4245
|
document.body.appendChild(mainCanvas = document.createElement('canvas'));
|
|
4204
4246
|
mainContext = mainCanvas.getContext('2d');
|
|
@@ -4212,7 +4254,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4212
4254
|
overlayContext = overlayCanvas.getContext('2d');
|
|
4213
4255
|
|
|
4214
4256
|
// set canvas style
|
|
4215
|
-
const styleCanvas =
|
|
4257
|
+
const styleCanvas =
|
|
4258
|
+
'position:absolute;' + // position canvas
|
|
4216
4259
|
'top:50%;left:50%;transform:translate(-50%,-50%);' + // center the canvas
|
|
4217
4260
|
(canvasPixelated?'image-rendering:pixelated':''); // set pixelated rendering
|
|
4218
4261
|
(glCanvas||mainCanvas).style = mainCanvas.style = overlayCanvas.style = styleCanvas;
|
package/examples/js13k/build.js
CHANGED
package/examples/screenshot.jpg
CHANGED
|
Binary file
|
package/examples/starter/game.js
CHANGED
|
@@ -99,7 +99,7 @@ function gameUpdatePost()
|
|
|
99
99
|
function gameRender()
|
|
100
100
|
{
|
|
101
101
|
// draw a grey square in the background without using webgl
|
|
102
|
-
drawRect(cameraPos, tileCollisionSize.add(vec2(5)), new Color(.
|
|
102
|
+
drawRect(cameraPos, tileCollisionSize.add(vec2(5)), new Color(.4,.4,.4), 0, 0);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
///////////////////////////////////////////////////////////////////////////////
|
package/package.json
CHANGED
package/src/engine.js
CHANGED
|
@@ -30,7 +30,7 @@ const engineName = 'LittleJS';
|
|
|
30
30
|
* @type {String}
|
|
31
31
|
* @default
|
|
32
32
|
* @memberof Engine */
|
|
33
|
-
const engineVersion = '1.7.
|
|
33
|
+
const engineVersion = '1.7.21';
|
|
34
34
|
|
|
35
35
|
/** Frames per second to update objects
|
|
36
36
|
* @type {Number}
|
|
@@ -100,11 +100,13 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
100
100
|
debug && (tileImage.onload=()=>ASSERT(1)); // tile sheet can not reloaded
|
|
101
101
|
|
|
102
102
|
// setup html
|
|
103
|
-
const styleBody =
|
|
104
|
-
'
|
|
105
|
-
'
|
|
106
|
-
'
|
|
107
|
-
'
|
|
103
|
+
const styleBody =
|
|
104
|
+
'margin:0;overflow:hidden;' + // fill the window
|
|
105
|
+
'background:#000;' + // set background color
|
|
106
|
+
'touch-action:none;' + // prevent mobile pinch to resize
|
|
107
|
+
'user-select:none;' + // prevent mobile hold to select
|
|
108
|
+
'-webkit-user-select:none;' + // compatibility for ios
|
|
109
|
+
'-webkit-touch-callout:none'; // compatibility for ios
|
|
108
110
|
document.body.style = styleBody;
|
|
109
111
|
document.body.appendChild(mainCanvas = document.createElement('canvas'));
|
|
110
112
|
mainContext = mainCanvas.getContext('2d');
|
|
@@ -118,7 +120,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
118
120
|
overlayContext = overlayCanvas.getContext('2d');
|
|
119
121
|
|
|
120
122
|
// set canvas style
|
|
121
|
-
const styleCanvas =
|
|
123
|
+
const styleCanvas =
|
|
124
|
+
'position:absolute;' + // position canvas
|
|
122
125
|
'top:50%;left:50%;transform:translate(-50%,-50%);' + // center the canvas
|
|
123
126
|
(canvasPixelated?'image-rendering:pixelated':''); // set pixelated rendering
|
|
124
127
|
(glCanvas||mainCanvas).style = mainCanvas.style = overlayCanvas.style = styleCanvas;
|