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
package/build/littlejs.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// LittleJS - MIT License - Copyright 2021 Frank Force
|
|
2
2
|
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* LittleJS Debug System
|
|
5
7
|
* - Press Esc to show debug overlay with mouse pick
|
|
@@ -10,7 +12,7 @@
|
|
|
10
12
|
* @namespace Debug
|
|
11
13
|
*/
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
|
|
14
16
|
|
|
15
17
|
/** True if debug is enabled
|
|
16
18
|
* @type {Boolean}
|
|
@@ -418,7 +420,7 @@ function debugRender()
|
|
|
418
420
|
* @namespace Utilities
|
|
419
421
|
*/
|
|
420
422
|
|
|
421
|
-
|
|
423
|
+
|
|
422
424
|
|
|
423
425
|
/** A shortcut to get Math.PI
|
|
424
426
|
* @type {Number}
|
|
@@ -1073,7 +1075,7 @@ class Timer
|
|
|
1073
1075
|
* @namespace Settings
|
|
1074
1076
|
*/
|
|
1075
1077
|
|
|
1076
|
-
|
|
1078
|
+
|
|
1077
1079
|
|
|
1078
1080
|
///////////////////////////////////////////////////////////////////////////////
|
|
1079
1081
|
// Camera settings
|
|
@@ -1321,7 +1323,7 @@ let medalsPreventUnlock;
|
|
|
1321
1323
|
* LittleJS Object System
|
|
1322
1324
|
*/
|
|
1323
1325
|
|
|
1324
|
-
|
|
1326
|
+
|
|
1325
1327
|
|
|
1326
1328
|
/**
|
|
1327
1329
|
* LittleJS Object Base Object Class
|
|
@@ -1717,7 +1719,7 @@ class EngineObject
|
|
|
1717
1719
|
* @namespace Draw
|
|
1718
1720
|
*/
|
|
1719
1721
|
|
|
1720
|
-
|
|
1722
|
+
|
|
1721
1723
|
|
|
1722
1724
|
/** The primary 2D canvas visible to the user
|
|
1723
1725
|
* @type {HTMLCanvasElement}
|
|
@@ -1908,12 +1910,12 @@ function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainCont
|
|
|
1908
1910
|
{
|
|
1909
1911
|
if (!screenSpace)
|
|
1910
1912
|
{
|
|
1911
|
-
//
|
|
1913
|
+
// transform from world space to screen space
|
|
1912
1914
|
pos = worldToScreen(pos);
|
|
1913
1915
|
size = size.scale(cameraScale);
|
|
1914
1916
|
}
|
|
1915
1917
|
context.save();
|
|
1916
|
-
context.translate(pos.x+.5
|
|
1918
|
+
context.translate(pos.x+.5, pos.y+.5);
|
|
1917
1919
|
context.rotate(angle);
|
|
1918
1920
|
context.scale(mirror ? -size.x : size.x, size.y);
|
|
1919
1921
|
drawFunction(context);
|
|
@@ -2098,7 +2100,7 @@ function toggleFullscreen()
|
|
|
2098
2100
|
* @namespace Input
|
|
2099
2101
|
*/
|
|
2100
2102
|
|
|
2101
|
-
|
|
2103
|
+
|
|
2102
2104
|
|
|
2103
2105
|
/** Returns true if device key is down
|
|
2104
2106
|
* @param {Number} key
|
|
@@ -2282,18 +2284,26 @@ function mouseToScreen(mousePos)
|
|
|
2282
2284
|
const stickData = [];
|
|
2283
2285
|
function gamepadsUpdate()
|
|
2284
2286
|
{
|
|
2285
|
-
|
|
2287
|
+
// update touch gamepad if enabled
|
|
2288
|
+
if (touchGamepadEnable && isTouchDevice)
|
|
2286
2289
|
{
|
|
2287
|
-
//
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
+
// create the touch gamepad if it doesn't exist
|
|
2291
|
+
if (!touchGamepadButtons)
|
|
2292
|
+
createTouchGamepad();
|
|
2290
2293
|
|
|
2291
|
-
|
|
2292
|
-
const data = inputData[1] || (inputData[1] = []);
|
|
2293
|
-
for (let i=10; i--;)
|
|
2294
|
+
if (touchGamepadTimer.isSet())
|
|
2294
2295
|
{
|
|
2295
|
-
|
|
2296
|
-
|
|
2296
|
+
// read virtual analog stick
|
|
2297
|
+
const sticks = stickData[0] || (stickData[0] = []);
|
|
2298
|
+
sticks[0] = vec2(touchGamepadStick.x, -touchGamepadStick.y); // flip vertical
|
|
2299
|
+
|
|
2300
|
+
// read virtual gamepad buttons
|
|
2301
|
+
const data = inputData[1] || (inputData[1] = []);
|
|
2302
|
+
for (let i=10; i--;)
|
|
2303
|
+
{
|
|
2304
|
+
const j = i == 3 ? 2 : i == 2 ? 3 : i; // fix button locations
|
|
2305
|
+
data[j] = touchGamepadButtons[i] ? 1 + 2*!gamepadIsDown(j,0) : 4*gamepadIsDown(j,0);
|
|
2306
|
+
}
|
|
2297
2307
|
}
|
|
2298
2308
|
}
|
|
2299
2309
|
|
|
@@ -2390,6 +2400,10 @@ if (isTouchDevice)
|
|
|
2390
2400
|
// set was touching
|
|
2391
2401
|
wasTouching = touching;
|
|
2392
2402
|
|
|
2403
|
+
// prevent default handling like copy and magnifier lens
|
|
2404
|
+
if (document.hasFocus()) // allow document to get focus
|
|
2405
|
+
e.preventDefault();
|
|
2406
|
+
|
|
2393
2407
|
// must return true so the document will get focus
|
|
2394
2408
|
return true;
|
|
2395
2409
|
}
|
|
@@ -2402,7 +2416,7 @@ if (isTouchDevice)
|
|
|
2402
2416
|
let touchGamepadTimer = new Timer, touchGamepadButtons, touchGamepadStick;
|
|
2403
2417
|
|
|
2404
2418
|
// create the touch gamepad, called automatically by the engine
|
|
2405
|
-
|
|
2419
|
+
function createTouchGamepad()
|
|
2406
2420
|
{
|
|
2407
2421
|
// touch input internal variables
|
|
2408
2422
|
touchGamepadButtons = [];
|
|
@@ -2536,7 +2550,7 @@ function touchGamepadRender()
|
|
|
2536
2550
|
* @namespace Audio
|
|
2537
2551
|
*/
|
|
2538
2552
|
|
|
2539
|
-
|
|
2553
|
+
|
|
2540
2554
|
|
|
2541
2555
|
/**
|
|
2542
2556
|
* Sound Object - Stores a zzfx sound for later use and can be played positionally
|
|
@@ -2572,8 +2586,9 @@ class Sound
|
|
|
2572
2586
|
if (zzfxSound)
|
|
2573
2587
|
{
|
|
2574
2588
|
// generate zzfx sound now for fast playback
|
|
2575
|
-
this.randomness = zzfxSound[1] || (zzfxSound[1] = 0);
|
|
2576
|
-
this.
|
|
2589
|
+
this.randomness = zzfxSound[1] || (zzfxSound[1] = 0);
|
|
2590
|
+
this.sampleChannels = [zzfxG(...zzfxSound)];
|
|
2591
|
+
this.sampleRate = zzfxR;
|
|
2577
2592
|
}
|
|
2578
2593
|
}
|
|
2579
2594
|
|
|
@@ -2582,11 +2597,12 @@ class Sound
|
|
|
2582
2597
|
* @param {Number} [volume=1] - How much to scale volume by (in addition to range fade)
|
|
2583
2598
|
* @param {Number} [pitch=1] - How much to scale pitch by (also adjusted by this.randomness)
|
|
2584
2599
|
* @param {Number} [randomnessScale=1] - How much to scale randomness
|
|
2585
|
-
* @
|
|
2600
|
+
* @param {Boolean} [loop=0] - Should the sound loop
|
|
2601
|
+
* @return {AudioBufferSourceNode} - The audio source node
|
|
2586
2602
|
*/
|
|
2587
|
-
play(pos, volume=1, pitch=1, randomnessScale=1)
|
|
2603
|
+
play(pos, volume=1, pitch=1, randomnessScale=1, loop=0)
|
|
2588
2604
|
{
|
|
2589
|
-
if (!soundEnable || !this.
|
|
2605
|
+
if (!soundEnable || !this.sampleChannels) return;
|
|
2590
2606
|
|
|
2591
2607
|
let pan;
|
|
2592
2608
|
if (pos)
|
|
@@ -2609,43 +2625,80 @@ class Sound
|
|
|
2609
2625
|
|
|
2610
2626
|
// play the sound
|
|
2611
2627
|
const playbackRate = pitch + pitch * this.randomness*randomnessScale*rand(-1,1);
|
|
2612
|
-
return playSamples(
|
|
2628
|
+
return this.source = playSamples(this.sampleChannels, volume, playbackRate, pan, loop, this.sampleRate);
|
|
2629
|
+
}
|
|
2630
|
+
|
|
2631
|
+
/** Stop the last instance of this sound that was played */
|
|
2632
|
+
stop()
|
|
2633
|
+
{
|
|
2634
|
+
if (this.source)
|
|
2635
|
+
this.source.stop();
|
|
2636
|
+
this.source = 0;
|
|
2613
2637
|
}
|
|
2614
2638
|
|
|
2615
2639
|
/** Play the sound as a note with a semitone offset
|
|
2616
2640
|
* @param {Number} semitoneOffset - How many semitones to offset pitch
|
|
2617
2641
|
* @param {Vector2} [pos] - World space position to play the sound, sound is not attenuated if null
|
|
2618
2642
|
* @param {Number} [volume=1] - How much to scale volume by (in addition to range fade)
|
|
2619
|
-
* @return {AudioBufferSourceNode} - The audio
|
|
2643
|
+
* @return {AudioBufferSourceNode} - The audio source node
|
|
2620
2644
|
*/
|
|
2621
2645
|
playNote(semitoneOffset, pos, volume)
|
|
2622
2646
|
{ return this.play(pos, volume, 2**(semitoneOffset/12), 0); }
|
|
2647
|
+
|
|
2648
|
+
/** Get how long this sound is in seconds
|
|
2649
|
+
* @return {Number} - How long the sound is in seconds (undefined if loading)
|
|
2650
|
+
*/
|
|
2651
|
+
getDuration()
|
|
2652
|
+
{ return this.sampleChannels && this.sampleChannels[0].length / this.sampleRate; }
|
|
2653
|
+
|
|
2654
|
+
/** Check if the last instance of this sound is playing
|
|
2655
|
+
* @return {Boolean} - True if the sound is playing
|
|
2656
|
+
*/
|
|
2657
|
+
isPlaying() { return this.source && !this.source.ended; }
|
|
2658
|
+
|
|
2659
|
+
/** Check if sound is loading, for sounds fetched from a url
|
|
2660
|
+
* @return {Boolean} - True if sound is loading and not ready to play
|
|
2661
|
+
*/
|
|
2662
|
+
isLoading() { return !this.sampleChannels; }
|
|
2623
2663
|
}
|
|
2624
2664
|
|
|
2625
2665
|
/**
|
|
2626
2666
|
* Sound Wave Object - Stores a wave sound for later use and can be played positionally
|
|
2667
|
+
* - this can be used to play wave, mp3, and ogg files
|
|
2668
|
+
* @example
|
|
2669
|
+
* // create a sound
|
|
2670
|
+
* const sound_example = new SoundWave('sound.mp3');
|
|
2671
|
+
*
|
|
2672
|
+
* // play the sound
|
|
2673
|
+
* sound_example.play();
|
|
2627
2674
|
*/
|
|
2628
2675
|
class SoundWave extends Sound
|
|
2629
2676
|
{
|
|
2630
2677
|
/** Create a sound object and cache the wave file for later use
|
|
2631
|
-
* @param {String}
|
|
2632
|
-
* @param {Number} [randomness
|
|
2678
|
+
* @param {String} filename - Filename of audio file to load
|
|
2679
|
+
* @param {Number} [randomness=0] - How much to randomize frequency each time sound plays
|
|
2633
2680
|
* @param {Number} [range=soundDefaultRange] - World space max range of sound, will not play if camera is farther away
|
|
2634
2681
|
* @param {Number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering off
|
|
2635
2682
|
*/
|
|
2636
|
-
constructor(
|
|
2683
|
+
constructor(filename, randomness=0, range, taper)
|
|
2637
2684
|
{
|
|
2638
2685
|
super(0, range, taper);
|
|
2639
2686
|
this.randomness = randomness;
|
|
2640
2687
|
|
|
2641
2688
|
if (!soundEnable) return;
|
|
2642
|
-
if (!
|
|
2689
|
+
if (!soundDecoderContext)
|
|
2643
2690
|
soundDecoderContext = new AudioContext;
|
|
2644
2691
|
|
|
2645
|
-
fetch(
|
|
2692
|
+
fetch(filename)
|
|
2646
2693
|
.then(response => response.arrayBuffer())
|
|
2647
|
-
.then(arrayBuffer =>
|
|
2648
|
-
.then(audioBuffer =>
|
|
2694
|
+
.then(arrayBuffer => soundDecoderContext.decodeAudioData(arrayBuffer))
|
|
2695
|
+
.then(audioBuffer =>
|
|
2696
|
+
{
|
|
2697
|
+
this.sampleChannels = [];
|
|
2698
|
+
for (let i = audioBuffer.numberOfChannels; i--;)
|
|
2699
|
+
this.sampleChannels[i] = audioBuffer.getChannelData(i);
|
|
2700
|
+
this.sampleRate = audioBuffer.sampleRate;
|
|
2701
|
+
});
|
|
2649
2702
|
}
|
|
2650
2703
|
}
|
|
2651
2704
|
let soundDecoderContext; // audio context used only to decode audio files
|
|
@@ -2680,48 +2733,34 @@ let soundDecoderContext; // audio context used only to decode audio files
|
|
|
2680
2733
|
* // play the music
|
|
2681
2734
|
* music_example.play();
|
|
2682
2735
|
*/
|
|
2683
|
-
class Music
|
|
2736
|
+
class Music extends Sound
|
|
2684
2737
|
{
|
|
2685
2738
|
/** Create a music object and cache the zzfx music samples for later use
|
|
2686
2739
|
* @param {Array} zzfxMusic - Array of zzfx music parameters
|
|
2687
2740
|
*/
|
|
2688
2741
|
constructor(zzfxMusic)
|
|
2689
2742
|
{
|
|
2690
|
-
|
|
2743
|
+
super();
|
|
2691
2744
|
|
|
2692
|
-
|
|
2745
|
+
if (!soundEnable) return;
|
|
2746
|
+
this.randomness = 0;
|
|
2747
|
+
this.sampleChannels = zzfxM(...zzfxMusic);
|
|
2748
|
+
this.sampleRate = zzfxR;
|
|
2693
2749
|
}
|
|
2694
2750
|
|
|
2695
2751
|
/** Play the music
|
|
2696
2752
|
* @param {Number} [volume=1] - How much to scale volume by
|
|
2697
|
-
* @param {Boolean} [loop=1] - True if the music should loop
|
|
2698
|
-
* @return {AudioBufferSourceNode} - The audio node
|
|
2753
|
+
* @param {Boolean} [loop=1] - True if the music should loop
|
|
2754
|
+
* @return {AudioBufferSourceNode} - The audio source node
|
|
2699
2755
|
*/
|
|
2700
2756
|
play(volume, loop = 1)
|
|
2701
|
-
{
|
|
2702
|
-
if (!soundEnable) return;
|
|
2703
|
-
|
|
2704
|
-
return this.source = playSamples(this.cachedSamples, volume, 1, 0, loop);
|
|
2705
|
-
}
|
|
2706
|
-
|
|
2707
|
-
/** Stop the music */
|
|
2708
|
-
stop()
|
|
2709
|
-
{
|
|
2710
|
-
if (this.source)
|
|
2711
|
-
this.source.stop();
|
|
2712
|
-
this.source = 0;
|
|
2713
|
-
}
|
|
2714
|
-
|
|
2715
|
-
/** Check if music is playing
|
|
2716
|
-
* @return {Boolean}
|
|
2717
|
-
*/
|
|
2718
|
-
isPlaying() { return this.source; }
|
|
2757
|
+
{ return super.play(0, volume, 1, 1, loop); }
|
|
2719
2758
|
}
|
|
2720
2759
|
|
|
2721
|
-
/** Play an mp3 or wav audio from a local file or url
|
|
2760
|
+
/** Play an mp3, ogg, or wav audio from a local file or url
|
|
2722
2761
|
* @param {String} url - Location of sound file to play
|
|
2723
2762
|
* @param {Number} [volume=1] - How much to scale volume by
|
|
2724
|
-
* @param {Boolean} [loop=1] - True if the music should loop
|
|
2763
|
+
* @param {Boolean} [loop=1] - True if the music should loop
|
|
2725
2764
|
* @return {HTMLAudioElement} - The audio element for this sound
|
|
2726
2765
|
* @memberof Audio */
|
|
2727
2766
|
function playAudioFile(url, volume=1, loop=1)
|
|
@@ -2785,9 +2824,10 @@ let audioContext;
|
|
|
2785
2824
|
* @param {Number} [rate=1] - The playback rate to use
|
|
2786
2825
|
* @param {Number} [pan=0] - How much to apply stereo panning
|
|
2787
2826
|
* @param {Boolean} [loop=0] - True if the sound should loop when it reaches the end
|
|
2827
|
+
* @param {Number} [sampleRate=44100] - Sample rate for the sound
|
|
2788
2828
|
* @return {AudioBufferSourceNode} - The audio node of the sound played
|
|
2789
2829
|
* @memberof Audio */
|
|
2790
|
-
function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0)
|
|
2830
|
+
function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0, sampleRate=zzfxR)
|
|
2791
2831
|
{
|
|
2792
2832
|
if (!soundEnable) return;
|
|
2793
2833
|
|
|
@@ -2804,7 +2844,7 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0)
|
|
|
2804
2844
|
}
|
|
2805
2845
|
|
|
2806
2846
|
// create buffer and source
|
|
2807
|
-
const buffer = audioContext.createBuffer(sampleChannels.length, sampleChannels[0].length,
|
|
2847
|
+
const buffer = audioContext.createBuffer(sampleChannels.length, sampleChannels[0].length, sampleRate),
|
|
2808
2848
|
source = audioContext.createBufferSource();
|
|
2809
2849
|
|
|
2810
2850
|
// copy samples to buffer and setup source
|
|
@@ -3063,7 +3103,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
|
|
|
3063
3103
|
* @namespace TileCollision
|
|
3064
3104
|
*/
|
|
3065
3105
|
|
|
3066
|
-
|
|
3106
|
+
|
|
3067
3107
|
|
|
3068
3108
|
/** The tile collision layer array, use setTileCollisionData and getTileCollisionData to access
|
|
3069
3109
|
* @type {Array}
|
|
@@ -3416,7 +3456,7 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
3416
3456
|
* LittleJS Particle System
|
|
3417
3457
|
*/
|
|
3418
3458
|
|
|
3419
|
-
|
|
3459
|
+
|
|
3420
3460
|
|
|
3421
3461
|
/**
|
|
3422
3462
|
* Particle Emitter - Spawns particles with the given settings
|
|
@@ -3726,7 +3766,7 @@ class Particle extends EngineObject
|
|
|
3726
3766
|
* @namespace Medals
|
|
3727
3767
|
*/
|
|
3728
3768
|
|
|
3729
|
-
|
|
3769
|
+
|
|
3730
3770
|
|
|
3731
3771
|
/** List of all medals
|
|
3732
3772
|
* @type {Array}
|
|
@@ -4050,7 +4090,7 @@ class Newgrounds
|
|
|
4050
4090
|
* @namespace WebGL
|
|
4051
4091
|
*/
|
|
4052
4092
|
|
|
4053
|
-
|
|
4093
|
+
|
|
4054
4094
|
|
|
4055
4095
|
/** The WebGL canvas which appears above the main canvas and below the overlay canvas
|
|
4056
4096
|
* @type {HTMLCanvasElement}
|
|
@@ -4072,7 +4112,7 @@ let glActiveTexture, glShader, glArrayBuffer, glPositionData, glColorData, glBat
|
|
|
4072
4112
|
|
|
4073
4113
|
///////////////////////////////////////////////////////////////////////////////
|
|
4074
4114
|
|
|
4075
|
-
//
|
|
4115
|
+
// Initalize WebGL, called automatically by the engine
|
|
4076
4116
|
function glInit()
|
|
4077
4117
|
{
|
|
4078
4118
|
// create the canvas and tile texture
|
|
@@ -4111,6 +4151,48 @@ function glInit()
|
|
|
4111
4151
|
glBatchCount = 0;
|
|
4112
4152
|
}
|
|
4113
4153
|
|
|
4154
|
+
// Setup render each frame, called automatically by engine
|
|
4155
|
+
function glPreRender()
|
|
4156
|
+
{
|
|
4157
|
+
// clear and set to same size as main canvas
|
|
4158
|
+
glContext.viewport(0, 0, glCanvas.width = mainCanvas.width, glCanvas.height = mainCanvas.height);
|
|
4159
|
+
glContext.clear(gl_COLOR_BUFFER_BIT);
|
|
4160
|
+
|
|
4161
|
+
// set up the shader
|
|
4162
|
+
glContext.useProgram(glShader);
|
|
4163
|
+
glContext.activeTexture(gl_TEXTURE0);
|
|
4164
|
+
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = glTileTexture);
|
|
4165
|
+
glContext.bindBuffer(gl_ARRAY_BUFFER, glArrayBuffer);
|
|
4166
|
+
glContext.bufferData(gl_ARRAY_BUFFER, gl_VERTEX_BUFFER_SIZE, gl_DYNAMIC_DRAW);
|
|
4167
|
+
glSetBlendMode();
|
|
4168
|
+
|
|
4169
|
+
// set vertex attributes
|
|
4170
|
+
let offset = 0;
|
|
4171
|
+
const initVertexAttribArray = (name, type, typeSize, size, normalize=0)=>
|
|
4172
|
+
{
|
|
4173
|
+
const location = glContext.getAttribLocation(glShader, name);
|
|
4174
|
+
glContext.enableVertexAttribArray(location);
|
|
4175
|
+
glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
|
|
4176
|
+
offset += size*typeSize;
|
|
4177
|
+
}
|
|
4178
|
+
initVertexAttribArray('p', gl_FLOAT, 4, 2); // position
|
|
4179
|
+
initVertexAttribArray('t', gl_FLOAT, 4, 2); // texture coords
|
|
4180
|
+
initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
|
|
4181
|
+
initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
|
|
4182
|
+
|
|
4183
|
+
// build the transform matrix
|
|
4184
|
+
const sx = 2 * cameraScale / mainCanvas.width;
|
|
4185
|
+
const sy = 2 * cameraScale / mainCanvas.height;
|
|
4186
|
+
glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader, 'm'), 0,
|
|
4187
|
+
new Float32Array([
|
|
4188
|
+
sx, 0, 0, 0,
|
|
4189
|
+
0, sy, 0, 0,
|
|
4190
|
+
1, 1, -1, 1,
|
|
4191
|
+
-1-sx*cameraPos.x, -1-sy*cameraPos.y, 0, 0
|
|
4192
|
+
])
|
|
4193
|
+
);
|
|
4194
|
+
}
|
|
4195
|
+
|
|
4114
4196
|
/** Set the WebGl blend mode, normally you should call setBlendMode instead
|
|
4115
4197
|
* @param {Boolean} [additive=0]
|
|
4116
4198
|
* @memberof WebGL */
|
|
@@ -4190,48 +4272,6 @@ function glCreateTexture(image)
|
|
|
4190
4272
|
return texture;
|
|
4191
4273
|
}
|
|
4192
4274
|
|
|
4193
|
-
// called automatically by engine before render
|
|
4194
|
-
function glPreRender()
|
|
4195
|
-
{
|
|
4196
|
-
// clear and set to same size as main canvas
|
|
4197
|
-
glContext.viewport(0, 0, glCanvas.width = mainCanvas.width, glCanvas.height = mainCanvas.height);
|
|
4198
|
-
glContext.clear(gl_COLOR_BUFFER_BIT);
|
|
4199
|
-
|
|
4200
|
-
// set up the shader
|
|
4201
|
-
glContext.useProgram(glShader);
|
|
4202
|
-
glContext.activeTexture(gl_TEXTURE0);
|
|
4203
|
-
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = glTileTexture);
|
|
4204
|
-
glContext.bindBuffer(gl_ARRAY_BUFFER, glArrayBuffer);
|
|
4205
|
-
glContext.bufferData(gl_ARRAY_BUFFER, gl_VERTEX_BUFFER_SIZE, gl_DYNAMIC_DRAW);
|
|
4206
|
-
glSetBlendMode();
|
|
4207
|
-
|
|
4208
|
-
// set vertex attributes
|
|
4209
|
-
let offset = 0;
|
|
4210
|
-
const initVertexAttribArray = (name, type, typeSize, size, normalize=0)=>
|
|
4211
|
-
{
|
|
4212
|
-
const location = glContext.getAttribLocation(glShader, name);
|
|
4213
|
-
glContext.enableVertexAttribArray(location);
|
|
4214
|
-
glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
|
|
4215
|
-
offset += size*typeSize;
|
|
4216
|
-
}
|
|
4217
|
-
initVertexAttribArray('p', gl_FLOAT, 4, 2); // position
|
|
4218
|
-
initVertexAttribArray('t', gl_FLOAT, 4, 2); // texture coords
|
|
4219
|
-
initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
|
|
4220
|
-
initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
|
|
4221
|
-
|
|
4222
|
-
// build the transform matrix
|
|
4223
|
-
const sx = 2 * cameraScale / mainCanvas.width;
|
|
4224
|
-
const sy = 2 * cameraScale / mainCanvas.height;
|
|
4225
|
-
glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader, 'm'), 0,
|
|
4226
|
-
new Float32Array([
|
|
4227
|
-
sx, 0, 0, 0,
|
|
4228
|
-
0, sy, 0, 0,
|
|
4229
|
-
1, 1, -1, 1,
|
|
4230
|
-
-1-sx*cameraPos.x, -1-sy*cameraPos.y, 0, 0
|
|
4231
|
-
])
|
|
4232
|
-
);
|
|
4233
|
-
}
|
|
4234
|
-
|
|
4235
4275
|
/** Draw all sprites and clear out the buffer, called automatically by the system whenever necessary
|
|
4236
4276
|
* @memberof WebGL */
|
|
4237
4277
|
function glFlush()
|
|
@@ -4489,7 +4529,7 @@ gl_VERTEX_BUFFER_SIZE = gl_MAX_BATCH * gl_VERTEX_BYTE_STRIDE;
|
|
|
4489
4529
|
* @namespace Engine
|
|
4490
4530
|
*/
|
|
4491
4531
|
|
|
4492
|
-
|
|
4532
|
+
|
|
4493
4533
|
|
|
4494
4534
|
/** Name of engine
|
|
4495
4535
|
* @type {String}
|
|
@@ -4501,7 +4541,7 @@ const engineName = 'LittleJS';
|
|
|
4501
4541
|
* @type {String}
|
|
4502
4542
|
* @default
|
|
4503
4543
|
* @memberof Engine */
|
|
4504
|
-
const engineVersion = '1.7.
|
|
4544
|
+
const engineVersion = '1.7.21';
|
|
4505
4545
|
|
|
4506
4546
|
/** Frames per second to update objects
|
|
4507
4547
|
* @type {Number}
|
|
@@ -4571,11 +4611,13 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4571
4611
|
debug && (tileImage.onload=()=>ASSERT(1)); // tile sheet can not reloaded
|
|
4572
4612
|
|
|
4573
4613
|
// setup html
|
|
4574
|
-
const styleBody =
|
|
4575
|
-
'
|
|
4576
|
-
'
|
|
4577
|
-
'
|
|
4578
|
-
'
|
|
4614
|
+
const styleBody =
|
|
4615
|
+
'margin:0;overflow:hidden;' + // fill the window
|
|
4616
|
+
'background:#000;' + // set background color
|
|
4617
|
+
'touch-action:none;' + // prevent mobile pinch to resize
|
|
4618
|
+
'user-select:none;' + // prevent mobile hold to select
|
|
4619
|
+
'-webkit-user-select:none;' + // compatibility for ios
|
|
4620
|
+
'-webkit-touch-callout:none'; // compatibility for ios
|
|
4579
4621
|
document.body.style = styleBody;
|
|
4580
4622
|
document.body.appendChild(mainCanvas = document.createElement('canvas'));
|
|
4581
4623
|
mainContext = mainCanvas.getContext('2d');
|
|
@@ -4589,7 +4631,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4589
4631
|
overlayContext = overlayCanvas.getContext('2d');
|
|
4590
4632
|
|
|
4591
4633
|
// set canvas style
|
|
4592
|
-
const styleCanvas =
|
|
4634
|
+
const styleCanvas =
|
|
4635
|
+
'position:absolute;' + // position canvas
|
|
4593
4636
|
'top:50%;left:50%;transform:translate(-50%,-50%);' + // center the canvas
|
|
4594
4637
|
(canvasPixelated?'image-rendering:pixelated':''); // set pixelated rendering
|
|
4595
4638
|
(glCanvas||mainCanvas).style = mainCanvas.style = overlayCanvas.style = styleCanvas;
|