littlejsengine 1.15.9 → 1.16.2
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/dist/littlejs.d.ts +154 -158
- package/dist/littlejs.esm.js +573 -570
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +553 -553
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +392 -396
- package/examples/box2d/game.js +1 -1
- package/examples/box2d/gameObjects.js +5 -5
- package/examples/breakout/game.js +3 -3
- package/examples/electron/game.js +1 -2
- package/examples/electron/index.html +2 -2
- package/examples/htmlMenu/game.js +0 -1
- package/examples/index.html +1 -1
- package/examples/logo.png +0 -0
- package/examples/logo2.png +0 -0
- package/examples/module/game.js +1 -2
- package/examples/particles/index.html +1 -1
- package/examples/platformer/game.js +4 -4
- package/examples/platformer/gameEffects.js +1 -1
- package/examples/puzzle/game.js +2 -2
- package/examples/shorts/base.html +4 -3
- package/examples/shorts/box2dPool.js +2 -2
- package/examples/shorts/empty.js +1 -1
- package/examples/shorts/{systemFont.js → fontImage.js} +3 -3
- package/examples/shorts/fps.js +1 -1
- package/examples/shorts/helloWorld.js +2 -2
- package/examples/shorts/nineSlice.js +2 -2
- package/examples/shorts/slidingPuzzle.js +1 -1
- package/examples/starter/game.js +1 -2
- package/examples/starter/index.html +3 -2
- package/examples/stress/index.html +1 -1
- package/examples/typescript/game.js +1 -2
- package/examples/typescript/game.ts +1 -2
- package/package.json +1 -1
- package/plugins/box2d.js +8 -8
- package/plugins/drawUtilities.js +6 -6
- package/plugins/postProcess.js +13 -20
- package/plugins/uiSystem.js +16 -4
- package/reference.md +9 -11
- package/src/engine.js +40 -54
- package/src/engineAudio.js +5 -7
- package/src/engineBuild.js +1 -0
- package/src/engineDebug.js +163 -161
- package/src/engineDraw.js +108 -130
- package/src/engineExport.js +20 -17
- package/src/engineInput.js +4 -7
- package/src/engineMath.js +1201 -0
- package/src/engineMedals.js +7 -7
- package/src/engineObject.js +5 -4
- package/src/engineRelease.js +2 -4
- package/src/engineSettings.js +22 -32
- package/src/engineTileLayer.js +9 -10
- package/src/engineUtilities.js +34 -1187
- package/src/engineWebGL.js +13 -15
package/src/engineDraw.js
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
* There are 3 canvas/contexts available to draw to...
|
|
11
11
|
* mainCanvas - 2D background canvas, non WebGL stuff like tile layers are drawn here.
|
|
12
12
|
* glCanvas - Used by the accelerated WebGL batch rendering system.
|
|
13
|
-
* overlayCanvas - Another 2D canvas that appears on top of the other 2 canvases.
|
|
14
13
|
*
|
|
15
14
|
* The WebGL rendering system is very fast with some caveats...
|
|
16
15
|
* - Switching blend modes (additive) or textures causes another draw call which is expensive in excess
|
|
@@ -32,21 +31,6 @@ let mainCanvas;
|
|
|
32
31
|
* @memberof Draw */
|
|
33
32
|
let mainContext;
|
|
34
33
|
|
|
35
|
-
/** A canvas that appears on top of everything the same size as mainCanvas
|
|
36
|
-
* @type {HTMLCanvasElement}
|
|
37
|
-
* @memberof Draw */
|
|
38
|
-
let overlayCanvas;
|
|
39
|
-
|
|
40
|
-
/** 2d context for overlayCanvas
|
|
41
|
-
* @type {CanvasRenderingContext2D}
|
|
42
|
-
* @memberof Draw */
|
|
43
|
-
let overlayContext;
|
|
44
|
-
|
|
45
|
-
/** The default canvas to use for drawing, usually mainCanvas
|
|
46
|
-
* @type {HTMLCanvasElement|OffscreenCanvas}
|
|
47
|
-
* @memberof Draw */
|
|
48
|
-
let drawCanvas;
|
|
49
|
-
|
|
50
34
|
/** The default 2d context to use for drawing, usually mainContext
|
|
51
35
|
* @type {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D}
|
|
52
36
|
* @memberof Draw */
|
|
@@ -62,6 +46,16 @@ let workCanvas;
|
|
|
62
46
|
* @memberof Draw */
|
|
63
47
|
let workContext;
|
|
64
48
|
|
|
49
|
+
/** Offscreen canvas with willReadFrequently that can be used for image processing
|
|
50
|
+
* @type {OffscreenCanvas}
|
|
51
|
+
* @memberof Draw */
|
|
52
|
+
let workReadCanvas;
|
|
53
|
+
|
|
54
|
+
/** Offscreen canvas with willReadFrequently that can be used for image processing
|
|
55
|
+
* @type {OffscreenCanvasRenderingContext2D}
|
|
56
|
+
* @memberof Draw */
|
|
57
|
+
let workReadContext;
|
|
58
|
+
|
|
65
59
|
/** The size of the main canvas (and other secondary canvases)
|
|
66
60
|
* @type {Vector2}
|
|
67
61
|
* @memberof Draw */
|
|
@@ -84,7 +78,7 @@ let drawCount;
|
|
|
84
78
|
* - This can take vecs or floats for easier use and conversion
|
|
85
79
|
* - If an index is passed in, the tile size and index will determine the position
|
|
86
80
|
* @param {Vector2|number} [pos=0] - Position of the tile in pixels, or tile index
|
|
87
|
-
* @param {Vector2|number} [size
|
|
81
|
+
* @param {Vector2|number} [size] - Size of tile in pixels
|
|
88
82
|
* @param {number} [textureIndex] - Texture index to use
|
|
89
83
|
* @param {number} [padding] - How many pixels padding around tiles
|
|
90
84
|
* @return {TileInfo}
|
|
@@ -94,7 +88,7 @@ let drawCount;
|
|
|
94
88
|
* tile(1, 16, 3) // a tile at index 1 of size 16 on texture 3
|
|
95
89
|
* tile(vec2(4,8), vec2(30,10)) // a tile at index (4,8) with a size of (30,10)
|
|
96
90
|
* @memberof Draw */
|
|
97
|
-
function tile(pos=new Vector2, size=
|
|
91
|
+
function tile(pos=new Vector2, size=tileDefaultSize, textureIndex=0, padding=tileDefaultPadding)
|
|
98
92
|
{
|
|
99
93
|
if (headlessMode)
|
|
100
94
|
return new TileInfo;
|
|
@@ -133,13 +127,13 @@ function tile(pos=new Vector2, size=tileSizeDefault, textureIndex=0, padding=0)
|
|
|
133
127
|
class TileInfo
|
|
134
128
|
{
|
|
135
129
|
/** Create a tile info object
|
|
136
|
-
* @param {Vector2} [pos=(0,0)]
|
|
137
|
-
* @param {Vector2} [size
|
|
138
|
-
* @param {number} [textureIndex]
|
|
139
|
-
* @param {number} [padding]
|
|
140
|
-
* @param {number} [
|
|
130
|
+
* @param {Vector2} [pos=(0,0)] - Top left corner of tile in pixels
|
|
131
|
+
* @param {Vector2} [size] - Size of tile in pixels
|
|
132
|
+
* @param {number} [textureIndex] - Texture index to use
|
|
133
|
+
* @param {number} [padding] - How many pixels padding around tiles
|
|
134
|
+
* @param {number} [bleed] - How many pixels smaller to draw tiles
|
|
141
135
|
*/
|
|
142
|
-
constructor(pos=vec2(), size=
|
|
136
|
+
constructor(pos=vec2(), size=tileDefaultSize, textureIndex=0, padding=tileDefaultPadding, bleed=tileDefaultBleed)
|
|
143
137
|
{
|
|
144
138
|
/** @property {Vector2} - Top left corner of tile in pixels */
|
|
145
139
|
this.pos = pos.copy();
|
|
@@ -152,7 +146,7 @@ class TileInfo
|
|
|
152
146
|
/** @property {TextureInfo} - The texture info for this tile */
|
|
153
147
|
this.textureInfo = textureInfos[this.textureIndex];
|
|
154
148
|
/** @property {number} - Shrinks tile by this many pixels to prevent neighbors bleeding */
|
|
155
|
-
this.
|
|
149
|
+
this.bleed = bleed;
|
|
156
150
|
}
|
|
157
151
|
|
|
158
152
|
/** Returns a copy of this tile offset by a vector
|
|
@@ -160,7 +154,7 @@ class TileInfo
|
|
|
160
154
|
* @return {TileInfo}
|
|
161
155
|
*/
|
|
162
156
|
offset(offset)
|
|
163
|
-
{ return new TileInfo(this.pos.add(offset), this.size, this.textureIndex, this.padding, this.
|
|
157
|
+
{ return new TileInfo(this.pos.add(offset), this.size, this.textureIndex, this.padding, this.bleed); }
|
|
164
158
|
|
|
165
159
|
/** Returns a copy of this tile offset by a number of animation frames
|
|
166
160
|
* @param {number} frame - Offset to apply in animation frames
|
|
@@ -183,7 +177,7 @@ class TileInfo
|
|
|
183
177
|
this.size = textureInfo.size.copy();
|
|
184
178
|
this.textureInfo = textureInfo;
|
|
185
179
|
// do not use padding or bleed
|
|
186
|
-
this.
|
|
180
|
+
this.bleed = this.padding = 0;
|
|
187
181
|
return this;
|
|
188
182
|
}
|
|
189
183
|
}
|
|
@@ -249,7 +243,7 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
|
|
|
249
243
|
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
250
244
|
|
|
251
245
|
const textureInfo = tileInfo && tileInfo.textureInfo;
|
|
252
|
-
const
|
|
246
|
+
const bleed = tileInfo?.bleed ?? 0;
|
|
253
247
|
if (useWebGL && glEnable)
|
|
254
248
|
{
|
|
255
249
|
ASSERT(!!glContext, 'WebGL is not enabled!');
|
|
@@ -264,13 +258,13 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
|
|
|
264
258
|
const w = tileInfo.size.x * sizeInverse.x;
|
|
265
259
|
const h = tileInfo.size.y * sizeInverse.y;
|
|
266
260
|
glSetTexture(textureInfo.glTexture);
|
|
267
|
-
if (
|
|
261
|
+
if (bleed)
|
|
268
262
|
{
|
|
269
|
-
const
|
|
270
|
-
const
|
|
263
|
+
const bleedX = sizeInverse.x*bleed;
|
|
264
|
+
const bleedY = sizeInverse.y*bleed;
|
|
271
265
|
glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
|
|
272
|
-
x +
|
|
273
|
-
x -
|
|
266
|
+
x + bleedX, y + bleedY,
|
|
267
|
+
x - bleedX + w, y - bleedY + h,
|
|
274
268
|
color.rgbaInt(), additiveColor && additiveColor.rgbaInt());
|
|
275
269
|
}
|
|
276
270
|
else
|
|
@@ -298,7 +292,7 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
|
|
|
298
292
|
// calculate uvs and render
|
|
299
293
|
const x = tileInfo.pos.x, y = tileInfo.pos.y;
|
|
300
294
|
const w = tileInfo.size.x, h = tileInfo.size.y;
|
|
301
|
-
drawImageColor(context, textureInfo.image, x, y, w, h, -.5, -.5, 1, 1, color, additiveColor,
|
|
295
|
+
drawImageColor(context, textureInfo.image, x, y, w, h, -.5, -.5, 1, 1, color, additiveColor, bleed);
|
|
302
296
|
}
|
|
303
297
|
else
|
|
304
298
|
{
|
|
@@ -624,7 +618,11 @@ function drawCanvas2D(pos, size, angle=0, mirror=false, drawFunction, screenSpac
|
|
|
624
618
|
ASSERT(typeof drawFunction === 'function', 'drawFunction must be a function');
|
|
625
619
|
|
|
626
620
|
if (!screenSpace)
|
|
627
|
-
|
|
621
|
+
{
|
|
622
|
+
pos = worldToScreen(pos);
|
|
623
|
+
size = size.scale(cameraScale);
|
|
624
|
+
angle -= cameraAngle;
|
|
625
|
+
}
|
|
628
626
|
context.save();
|
|
629
627
|
context.translate(pos.x+.5, pos.y+.5);
|
|
630
628
|
context.rotate(angle);
|
|
@@ -663,26 +661,7 @@ function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, f
|
|
|
663
661
|
drawTextScreen(text, pos, size, color, lineWidth, lineColor, textAlign, font, fontStyle, maxWidth, angle, context);
|
|
664
662
|
}
|
|
665
663
|
|
|
666
|
-
/** Draw text
|
|
667
|
-
* Automatically splits new lines into rows
|
|
668
|
-
* @param {string|number} text
|
|
669
|
-
* @param {Vector2} pos
|
|
670
|
-
* @param {number} [size]
|
|
671
|
-
* @param {Color} [color=(1,1,1,1)]
|
|
672
|
-
* @param {number} [lineWidth]
|
|
673
|
-
* @param {Color} [lineColor=(0,0,0,1)]
|
|
674
|
-
* @param {CanvasTextAlign} [textAlign='center']
|
|
675
|
-
* @param {string} [font=fontDefault]
|
|
676
|
-
* @param {string} [fontStyle]
|
|
677
|
-
* @param {number} [maxWidth]
|
|
678
|
-
* @param {number} [angle]
|
|
679
|
-
* @memberof Draw */
|
|
680
|
-
function drawTextOverlay(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, font, fontStyle, maxWidth, angle=0)
|
|
681
|
-
{
|
|
682
|
-
drawText(text, pos, size, color, lineWidth, lineColor, textAlign, font, fontStyle, maxWidth, angle, overlayContext);
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
/** Draw text on overlay canvas in screen space
|
|
664
|
+
/** Draw text in screen space
|
|
686
665
|
* Automatically splits new lines into rows
|
|
687
666
|
* @param {string|number} text
|
|
688
667
|
* @param {Vector2} pos
|
|
@@ -695,9 +674,9 @@ function drawTextOverlay(text, pos, size=1, color, lineWidth=0, lineColor, textA
|
|
|
695
674
|
* @param {string} [fontStyle]
|
|
696
675
|
* @param {number} [maxWidth]
|
|
697
676
|
* @param {number} [angle]
|
|
698
|
-
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=
|
|
677
|
+
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
|
|
699
678
|
* @memberof Draw */
|
|
700
|
-
function drawTextScreen(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=BLACK, textAlign='center', font=fontDefault, fontStyle='', maxWidth, angle=0, context=
|
|
679
|
+
function drawTextScreen(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=BLACK, textAlign='center', font=fontDefault, fontStyle='', maxWidth, angle=0, context=drawContext)
|
|
701
680
|
{
|
|
702
681
|
ASSERT(isString(text), 'text must be a string');
|
|
703
682
|
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
@@ -741,16 +720,16 @@ function drawTextScreen(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=B
|
|
|
741
720
|
* @memberof Draw */
|
|
742
721
|
function screenToWorld(screenPos)
|
|
743
722
|
{
|
|
723
|
+
ASSERT(isVector2(screenPos), 'screenPos must be a vec2');
|
|
724
|
+
|
|
744
725
|
let x = (screenPos.x - mainCanvasSize.x/2 + .5) / cameraScale;
|
|
745
726
|
let y = (screenPos.y - mainCanvasSize.y/2 + .5) / -cameraScale;
|
|
746
727
|
if (cameraAngle)
|
|
747
728
|
{
|
|
748
729
|
// apply camera rotation
|
|
749
730
|
const c = cos(-cameraAngle), s = sin(-cameraAngle);
|
|
750
|
-
const
|
|
751
|
-
|
|
752
|
-
x = rotatedX;
|
|
753
|
-
y = rotatedY;
|
|
731
|
+
const xr = x * c - y * s, yr = x * s + y * c;
|
|
732
|
+
x = xr; y = yr;
|
|
754
733
|
}
|
|
755
734
|
return new Vector2(x + cameraPos.x, y + cameraPos.y);
|
|
756
735
|
}
|
|
@@ -761,16 +740,16 @@ function screenToWorld(screenPos)
|
|
|
761
740
|
* @memberof Draw */
|
|
762
741
|
function worldToScreen(worldPos)
|
|
763
742
|
{
|
|
743
|
+
ASSERT(isVector2(worldPos), 'worldPos must be a vec2');
|
|
744
|
+
|
|
764
745
|
let x = worldPos.x - cameraPos.x;
|
|
765
746
|
let y = worldPos.y - cameraPos.y;
|
|
766
747
|
if (cameraAngle)
|
|
767
748
|
{
|
|
768
749
|
// apply inverse camera rotation
|
|
769
750
|
const c = cos(cameraAngle), s = sin(cameraAngle);
|
|
770
|
-
const
|
|
771
|
-
|
|
772
|
-
x = rotatedX;
|
|
773
|
-
y = rotatedY;
|
|
751
|
+
const xr = x * c - y * s, yr = x * s + y * c;
|
|
752
|
+
x = xr; y = yr;
|
|
774
753
|
}
|
|
775
754
|
return new Vector2
|
|
776
755
|
(
|
|
@@ -785,16 +764,16 @@ function worldToScreen(worldPos)
|
|
|
785
764
|
* @memberof Draw */
|
|
786
765
|
function screenToWorldDelta(screenDelta)
|
|
787
766
|
{
|
|
767
|
+
ASSERT(isVector2(screenDelta), 'screenDelta must be a vec2');
|
|
768
|
+
|
|
788
769
|
let x = screenDelta.x / cameraScale;
|
|
789
770
|
let y = screenDelta.y / -cameraScale;
|
|
790
771
|
if (cameraAngle)
|
|
791
772
|
{
|
|
792
773
|
// apply camera rotation
|
|
793
774
|
const c = cos(-cameraAngle), s = sin(-cameraAngle);
|
|
794
|
-
const
|
|
795
|
-
|
|
796
|
-
x = rotatedX;
|
|
797
|
-
y = rotatedY;
|
|
775
|
+
const xr = x * c - y * s, yr = x * s + y * c;
|
|
776
|
+
x = xr; y = yr;
|
|
798
777
|
}
|
|
799
778
|
return new Vector2(x, y);
|
|
800
779
|
}
|
|
@@ -805,16 +784,16 @@ function screenToWorldDelta(screenDelta)
|
|
|
805
784
|
* @memberof Draw */
|
|
806
785
|
function worldToScreenDelta(worldDelta)
|
|
807
786
|
{
|
|
787
|
+
ASSERT(isVector2(worldDelta), 'worldDelta must be a vec2');
|
|
788
|
+
|
|
808
789
|
let x = worldDelta.x;
|
|
809
790
|
let y = worldDelta.y;
|
|
810
791
|
if (cameraAngle)
|
|
811
792
|
{
|
|
812
793
|
// apply inverse camera rotation
|
|
813
794
|
const c = cos(cameraAngle), s = sin(cameraAngle);
|
|
814
|
-
const
|
|
815
|
-
|
|
816
|
-
x = rotatedX;
|
|
817
|
-
y = rotatedY;
|
|
795
|
+
const xr = x * c - y * s, yr = x * s + y * c;
|
|
796
|
+
x = xr; y = yr;
|
|
818
797
|
}
|
|
819
798
|
return new Vector2(x * cameraScale, y * -cameraScale);
|
|
820
799
|
}
|
|
@@ -827,6 +806,10 @@ function worldToScreenDelta(worldDelta)
|
|
|
827
806
|
* @memberof Draw */
|
|
828
807
|
function screenToWorldTransform(screenPos, screenSize, screenAngle=0)
|
|
829
808
|
{
|
|
809
|
+
ASSERT(isVector2(screenPos), 'screenPos must be a vec2');
|
|
810
|
+
ASSERT(isVector2(screenSize), 'screenSize must be a vec2');
|
|
811
|
+
ASSERT(isNumber(screenAngle), 'screenAngle must be a number');
|
|
812
|
+
|
|
830
813
|
return [
|
|
831
814
|
screenToWorld(screenPos),
|
|
832
815
|
screenSize.scale(1/cameraScale),
|
|
@@ -834,28 +817,13 @@ function screenToWorldTransform(screenPos, screenSize, screenAngle=0)
|
|
|
834
817
|
];
|
|
835
818
|
}
|
|
836
819
|
|
|
837
|
-
/** Convert world space transform to screen space
|
|
838
|
-
* @param {Vector2} worldPos
|
|
839
|
-
* @param {Vector2} worldSize
|
|
840
|
-
* @param {number} [worldAngle]
|
|
841
|
-
* @return {[Vector2, Vector2, number]} - [pos, size, angle]
|
|
842
|
-
* @memberof Draw */
|
|
843
|
-
function worldToScreenTransform(worldPos, worldSize, worldAngle=0)
|
|
844
|
-
{
|
|
845
|
-
return [
|
|
846
|
-
worldToScreen(worldPos),
|
|
847
|
-
worldSize.scale(cameraScale),
|
|
848
|
-
worldAngle - cameraAngle
|
|
849
|
-
];
|
|
850
|
-
}
|
|
851
|
-
|
|
852
820
|
/** Get the size of the camera window in world space
|
|
853
821
|
* @return {Vector2}
|
|
854
822
|
* @memberof Draw */
|
|
855
823
|
function getCameraSize() { return mainCanvasSize.scale(1/cameraScale); }
|
|
856
824
|
|
|
857
|
-
/** Check if a point or circle is on screen
|
|
858
|
-
* If size is a Vector2, uses the
|
|
825
|
+
/** Check if a box, point, or circle is on screen with a circle test
|
|
826
|
+
* If size is a Vector2, uses the length as diameter
|
|
859
827
|
* This can be used to cull offscreen objects from render or update
|
|
860
828
|
* @param {Vector2} pos - world space position
|
|
861
829
|
* @param {Vector2|number} size - world space size or diameter
|
|
@@ -863,12 +831,30 @@ function getCameraSize() { return mainCanvasSize.scale(1/cameraScale); }
|
|
|
863
831
|
* @memberof Draw */
|
|
864
832
|
function isOnScreen(pos, size=0)
|
|
865
833
|
{
|
|
866
|
-
pos
|
|
834
|
+
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
835
|
+
ASSERT(isVector2(size) || isNumber(size), 'size must be a vec2 or number');
|
|
836
|
+
|
|
837
|
+
// optimized circle on screen test
|
|
838
|
+
// pos = worldToScreen(pos);
|
|
839
|
+
let x = pos.x - cameraPos.x;
|
|
840
|
+
let y = pos.y - cameraPos.y;
|
|
841
|
+
if (cameraAngle)
|
|
842
|
+
{
|
|
843
|
+
// apply inverse camera rotation
|
|
844
|
+
const c = cos(cameraAngle), s = sin(cameraAngle);
|
|
845
|
+
const xr = x * c - y * s, yr = x * s + y * c;
|
|
846
|
+
x = xr; y = yr;
|
|
847
|
+
}
|
|
848
|
+
x *= cameraScale*2; y *= -cameraScale*2;
|
|
849
|
+
|
|
867
850
|
if (size instanceof Vector2)
|
|
868
|
-
size =
|
|
869
|
-
size *= cameraScale
|
|
870
|
-
|
|
871
|
-
|
|
851
|
+
size = size.length(); // use length of vector as diameter
|
|
852
|
+
size *= cameraScale;
|
|
853
|
+
|
|
854
|
+
// check against screen bounds
|
|
855
|
+
const w = mainCanvasSize.x, h = mainCanvasSize.y;
|
|
856
|
+
return x + size > -w && x - size < w &&
|
|
857
|
+
y + size > -h && y - size < h;
|
|
872
858
|
}
|
|
873
859
|
|
|
874
860
|
/** Enable normal or additive blend mode
|
|
@@ -882,18 +868,19 @@ function setBlendMode(additive=false, context)
|
|
|
882
868
|
context.globalCompositeOperation = additive ? 'lighter' : 'source-over';
|
|
883
869
|
}
|
|
884
870
|
|
|
885
|
-
/** Combines
|
|
886
|
-
* This is necessary for things like
|
|
871
|
+
/** Combines LittleJS canvases onto the main canvas
|
|
872
|
+
* This is necessary for things like screenshots and video
|
|
887
873
|
* @memberof Draw */
|
|
888
874
|
function combineCanvases()
|
|
889
875
|
{
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
876
|
+
const w = mainCanvasSize.x, h = mainCanvasSize.y;
|
|
877
|
+
workCanvas.width = w;
|
|
878
|
+
workCanvas.height = h;
|
|
879
|
+
workContext.fillRect(0,0,w,h); // remove background alpha
|
|
880
|
+
glCopyToContext(workContext);
|
|
881
|
+
workContext.drawImage(mainCanvas, 0, 0);
|
|
882
|
+
mainCanvas.width |= 0;
|
|
883
|
+
mainContext.drawImage(workCanvas, 0, 0);
|
|
897
884
|
}
|
|
898
885
|
|
|
899
886
|
/** Helper function to draw an image with color and additive color applied
|
|
@@ -910,18 +897,18 @@ function combineCanvases()
|
|
|
910
897
|
* @param {number} dHeight
|
|
911
898
|
* @param {Color} color
|
|
912
899
|
* @param {Color} [additiveColor]
|
|
913
|
-
* @param {number} [
|
|
900
|
+
* @param {number} [bleed] - How many pixels to shrink the source, used to fix bleeding
|
|
914
901
|
* @memberof Draw */
|
|
915
|
-
function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, color, additiveColor,
|
|
902
|
+
function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, color, additiveColor, bleed=0)
|
|
916
903
|
{
|
|
917
904
|
function isWhite(c) { return c.r >= 1 && c.g >= 1 && c.b >= 1; }
|
|
918
905
|
function isBlack(c) { return c.r <= 0 && c.g <= 0 && c.b <= 0 && c.a <= 0; }
|
|
919
|
-
const sx2 =
|
|
920
|
-
const sy2 =
|
|
906
|
+
const sx2 = bleed;
|
|
907
|
+
const sy2 = bleed;
|
|
921
908
|
sWidth = max(1,sWidth|0);
|
|
922
909
|
sHeight = max(1,sHeight|0);
|
|
923
|
-
const sWidth2 = sWidth - 2*
|
|
924
|
-
const sHeight2 = sHeight - 2*
|
|
910
|
+
const sWidth2 = sWidth - 2*bleed;
|
|
911
|
+
const sHeight2 = sHeight - 2*bleed;
|
|
925
912
|
if (!canvasColorTiles || (additiveColor ? isWhite(color.add(additiveColor)) && additiveColor.a <= 0 : isWhite(color)))
|
|
926
913
|
{
|
|
927
914
|
// white texture with no additive alpha, no need to tint
|
|
@@ -932,12 +919,12 @@ function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth,
|
|
|
932
919
|
else
|
|
933
920
|
{
|
|
934
921
|
// copy to offscreen canvas
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
922
|
+
workReadCanvas.width = sWidth;
|
|
923
|
+
workReadCanvas.height = sHeight;
|
|
924
|
+
workReadContext.drawImage(image, sx|0, sy|0, sWidth, sHeight, 0, 0, sWidth, sHeight);
|
|
938
925
|
|
|
939
926
|
// tint image using offscreen work context
|
|
940
|
-
const imageData =
|
|
927
|
+
const imageData = workReadContext.getImageData(0, 0, sWidth, sHeight);
|
|
941
928
|
const data = imageData.data;
|
|
942
929
|
if (additiveColor && !isBlack(additiveColor))
|
|
943
930
|
{
|
|
@@ -946,8 +933,8 @@ function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth,
|
|
|
946
933
|
const colorAdd = [additiveColor.r * 255, additiveColor.g * 255, additiveColor.b * 255, additiveColor.a * 255];
|
|
947
934
|
for (let i = 0; i < data.length; ++i)
|
|
948
935
|
data[i] = data[i] * colorMultiply[i&3] + colorAdd[i&3] |0;
|
|
949
|
-
|
|
950
|
-
context.drawImage(
|
|
936
|
+
workReadContext.putImageData(imageData, 0, 0);
|
|
937
|
+
context.drawImage(workReadCanvas, sx2, sy2, sWidth2, sHeight2, dx, dy, dWidth, dHeight);
|
|
951
938
|
}
|
|
952
939
|
else
|
|
953
940
|
{
|
|
@@ -958,9 +945,9 @@ function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth,
|
|
|
958
945
|
data[i+1] *= color.g;
|
|
959
946
|
data[i+2] *= color.b;
|
|
960
947
|
}
|
|
961
|
-
|
|
948
|
+
workReadContext.putImageData(imageData, 0, 0);
|
|
962
949
|
context.globalAlpha = color.a;
|
|
963
|
-
context.drawImage(
|
|
950
|
+
context.drawImage(workReadCanvas, sx2, sy2, sWidth2, sHeight2, dx, dy, dWidth, dHeight);
|
|
964
951
|
context.globalAlpha = 1;
|
|
965
952
|
}
|
|
966
953
|
}
|
|
@@ -1022,7 +1009,7 @@ class FontImage
|
|
|
1022
1009
|
constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1))
|
|
1023
1010
|
{
|
|
1024
1011
|
// load default font image
|
|
1025
|
-
if (!engineFontImage)
|
|
1012
|
+
if (!image && !engineFontImage)
|
|
1026
1013
|
{
|
|
1027
1014
|
engineFontImage = new Image;
|
|
1028
1015
|
engineFontImage.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6ECLBdFY+Q0PMNgf0yCgsSAGZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWwtROWpVQEyWh2npdpBmTUFVhb29RINgLIukoXr5LIAvYQ5ve+1FqWEMqNKTX3FAJHyQDRZvmKWubAACcv5z5Gtg2oyCWE+Yk/8JZQX1jTTCpKAFGIgza+dJCNBF2UskRlsgwitHbSV0QLgt9sTPtsRlvJjEr8C/FARWA2bJ/TtJ7lko34dNDn6usJUMzuErP89UUBJbWeozrwLLncXczd508deAjLWipLO4Q5XGPcJvPu92cNDaN0P5G1FL0nSOzddZOrJ6rNhbXGmeDvO3TF7DeJWl4bvaYQTNHCTeuqKZmbjHaSOFes+IX/+IhHrnAkXOAsfn24EM68XieIECoccD4KZLk/odiwzeo2rovYdhvb2HYFgyznJyDpYJdYOmfXgVdJTaUi4xA2uWYNYec9BLeqdl9EsoTw582mSFDX2DxVLbNt9U3YYoeatBad1c2Tj8t2akrjaIGJNywKB/7h75/gN3vCMSaadIUTAAAAAElFTkSuQmCC';
|
|
@@ -1045,23 +1032,14 @@ class FontImage
|
|
|
1045
1032
|
this.drawTextScreen(text, worldToScreen(pos).floor(), scale*cameraScale|0, center, context);
|
|
1046
1033
|
}
|
|
1047
1034
|
|
|
1048
|
-
/** Draw text
|
|
1049
|
-
* @param {string|number} text
|
|
1050
|
-
* @param {Vector2} pos
|
|
1051
|
-
* @param {number} [scale]
|
|
1052
|
-
* @param {boolean} [center]
|
|
1053
|
-
*/
|
|
1054
|
-
drawTextOverlay(text, pos, scale=4, center)
|
|
1055
|
-
{ this.drawText(text, pos, scale, center, overlayContext); }
|
|
1056
|
-
|
|
1057
|
-
/** Draw text on overlay canvas in screen space using the image font
|
|
1035
|
+
/** Draw text in screen space using the image font
|
|
1058
1036
|
* @param {string|number} text
|
|
1059
1037
|
* @param {Vector2} pos
|
|
1060
1038
|
* @param {number} [scale]
|
|
1061
1039
|
* @param {boolean} [center]
|
|
1062
1040
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
|
|
1063
1041
|
*/
|
|
1064
|
-
drawTextScreen(text, pos, scale=4, center=true, context=
|
|
1042
|
+
drawTextScreen(text, pos, scale=4, center=true, context=drawContext)
|
|
1065
1043
|
{
|
|
1066
1044
|
context.save();
|
|
1067
1045
|
const size = this.tileSize;
|
package/src/engineExport.js
CHANGED
|
@@ -27,7 +27,7 @@ export
|
|
|
27
27
|
// Globals
|
|
28
28
|
debug,
|
|
29
29
|
debugOverlay,
|
|
30
|
-
|
|
30
|
+
debugWatermark,
|
|
31
31
|
|
|
32
32
|
// Debug
|
|
33
33
|
ASSERT,
|
|
@@ -41,13 +41,10 @@ export
|
|
|
41
41
|
debugText,
|
|
42
42
|
debugClear,
|
|
43
43
|
debugScreenshot,
|
|
44
|
-
debugSaveCanvas,
|
|
45
|
-
debugSaveText,
|
|
46
|
-
debugSaveDataURL,
|
|
47
44
|
debugShowErrors,
|
|
48
|
-
debugVideoCaptureIsActive,
|
|
49
45
|
debugVideoCaptureStart,
|
|
50
46
|
debugVideoCaptureStop,
|
|
47
|
+
debugVideoCaptureIsActive,
|
|
51
48
|
|
|
52
49
|
// Settings
|
|
53
50
|
cameraPos,
|
|
@@ -60,13 +57,13 @@ export
|
|
|
60
57
|
canvasMaxAspect,
|
|
61
58
|
canvasFixedSize,
|
|
62
59
|
canvasPixelated,
|
|
63
|
-
overlayCanvasPixelated,
|
|
64
60
|
tilesPixelated,
|
|
65
61
|
fontDefault,
|
|
66
62
|
showSplashScreen,
|
|
67
63
|
headlessMode,
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
tileDefaultSize,
|
|
65
|
+
tileDefaultPadding,
|
|
66
|
+
tileDefaultBleed,
|
|
70
67
|
enablePhysicsSolver,
|
|
71
68
|
objectDefaultMass,
|
|
72
69
|
objectDefaultDamping,
|
|
@@ -105,14 +102,14 @@ export
|
|
|
105
102
|
setCanvasMaxAspect,
|
|
106
103
|
setCanvasFixedSize,
|
|
107
104
|
setCanvasPixelated,
|
|
108
|
-
setOverlayCanvasPixelated,
|
|
109
105
|
setTilesPixelated,
|
|
110
106
|
setFontDefault,
|
|
111
107
|
setShowSplashScreen,
|
|
112
108
|
setHeadlessMode,
|
|
113
109
|
setGLEnable,
|
|
114
|
-
|
|
115
|
-
|
|
110
|
+
setTileDefaultSize,
|
|
111
|
+
setTileDefaultPadding,
|
|
112
|
+
setTileDefaultBleed,
|
|
116
113
|
setEnablePhysicsSolver,
|
|
117
114
|
setObjectDefaultMass,
|
|
118
115
|
setObjectDefaultDamping,
|
|
@@ -141,10 +138,10 @@ export
|
|
|
141
138
|
setMedalDisplaySlideTime,
|
|
142
139
|
setMedalDisplaySize,
|
|
143
140
|
setMedalsPreventUnlock,
|
|
144
|
-
|
|
141
|
+
setDebugWatermark,
|
|
145
142
|
setDebugKey,
|
|
146
143
|
|
|
147
|
-
//
|
|
144
|
+
// Math
|
|
148
145
|
PI,
|
|
149
146
|
abs,
|
|
150
147
|
floor,
|
|
@@ -172,8 +169,13 @@ export
|
|
|
172
169
|
isOverlapping,
|
|
173
170
|
isIntersecting,
|
|
174
171
|
wave,
|
|
172
|
+
|
|
173
|
+
// Utilities
|
|
175
174
|
formatTime,
|
|
176
175
|
fetchJSON,
|
|
176
|
+
saveText,
|
|
177
|
+
saveCanvas,
|
|
178
|
+
saveDataURL,
|
|
177
179
|
|
|
178
180
|
// Random
|
|
179
181
|
rand,
|
|
@@ -219,10 +221,11 @@ export
|
|
|
219
221
|
TextureInfo,
|
|
220
222
|
mainCanvas,
|
|
221
223
|
mainContext,
|
|
222
|
-
drawCanvas,
|
|
223
224
|
drawContext,
|
|
224
|
-
|
|
225
|
-
|
|
225
|
+
workCanvas,
|
|
226
|
+
workContext,
|
|
227
|
+
workReadCanvas,
|
|
228
|
+
workReadContext,
|
|
226
229
|
mainCanvasSize,
|
|
227
230
|
textureInfos,
|
|
228
231
|
drawCount,
|
|
@@ -230,6 +233,7 @@ export
|
|
|
230
233
|
worldToScreen,
|
|
231
234
|
screenToWorldDelta,
|
|
232
235
|
worldToScreenDelta,
|
|
236
|
+
screenToWorldTransform,
|
|
233
237
|
drawTile,
|
|
234
238
|
drawRect,
|
|
235
239
|
drawRectGradient,
|
|
@@ -240,7 +244,6 @@ export
|
|
|
240
244
|
drawCircle,
|
|
241
245
|
drawCanvas2D,
|
|
242
246
|
drawText,
|
|
243
|
-
drawTextOverlay,
|
|
244
247
|
drawTextScreen,
|
|
245
248
|
setBlendMode,
|
|
246
249
|
combineCanvases,
|
package/src/engineInput.js
CHANGED
|
@@ -365,8 +365,7 @@ function inputInit()
|
|
|
365
365
|
}
|
|
366
366
|
function onMouseDown(e)
|
|
367
367
|
{
|
|
368
|
-
if (isTouchDevice && touchInputEnable)
|
|
369
|
-
return;
|
|
368
|
+
if (isTouchDevice && touchInputEnable) return;
|
|
370
369
|
|
|
371
370
|
// fix stalled audio requiring user interaction
|
|
372
371
|
if (soundEnable && !headlessMode && audioContext && !audioIsRunning())
|
|
@@ -417,8 +416,7 @@ function inputInit()
|
|
|
417
416
|
let wasTouching;
|
|
418
417
|
function handleTouch(e)
|
|
419
418
|
{
|
|
420
|
-
if (!touchInputEnable)
|
|
421
|
-
return;
|
|
419
|
+
if (!touchInputEnable) return;
|
|
422
420
|
|
|
423
421
|
// route touch to gamepad
|
|
424
422
|
if (touchGamepadEnable)
|
|
@@ -482,8 +480,7 @@ function inputInit()
|
|
|
482
480
|
}
|
|
483
481
|
|
|
484
482
|
// don't process touch gamepad if paused
|
|
485
|
-
if (paused)
|
|
486
|
-
return;
|
|
483
|
+
if (paused) return;
|
|
487
484
|
|
|
488
485
|
// get center of left and right sides
|
|
489
486
|
const stickCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
@@ -722,7 +719,7 @@ function inputRender()
|
|
|
722
719
|
return;
|
|
723
720
|
|
|
724
721
|
// setup the canvas
|
|
725
|
-
const context =
|
|
722
|
+
const context = mainContext;
|
|
726
723
|
context.save();
|
|
727
724
|
context.globalAlpha = alpha*touchGamepadAlpha;
|
|
728
725
|
context.strokeStyle = '#fff';
|