littlejsengine 1.15.9 → 1.16.1
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 +66 -83
- package/dist/littlejs.esm.js +318 -330
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +306 -319
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +229 -242
- package/examples/box2d/game.js +1 -1
- 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/module/game.js +1 -2
- package/examples/particles/index.html +1 -1
- package/examples/platformer/game.js +4 -4
- package/examples/puzzle/game.js +2 -2
- package/examples/shorts/base.html +3 -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 +2 -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 +15 -3
- package/reference.md +4 -6
- package/src/engine.js +35 -37
- package/src/engineAudio.js +3 -3
- package/src/engineDebug.js +78 -78
- package/src/engineDraw.js +107 -109
- package/src/engineExport.js +12 -11
- package/src/engineInput.js +1 -1
- package/src/engineMedals.js +3 -3
- package/src/engineObject.js +4 -2
- package/src/engineRelease.js +1 -1
- package/src/engineSettings.js +20 -30
- package/src/engineTileLayer.js +5 -4
- package/src/engineUtilities.js +2 -10
- package/src/engineWebGL.js +6 -5
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,16 +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
34
|
/** The default canvas to use for drawing, usually mainCanvas
|
|
46
35
|
* @type {HTMLCanvasElement|OffscreenCanvas}
|
|
47
36
|
* @memberof Draw */
|
|
@@ -62,6 +51,16 @@ let workCanvas;
|
|
|
62
51
|
* @memberof Draw */
|
|
63
52
|
let workContext;
|
|
64
53
|
|
|
54
|
+
/** Offscreen canvas with willReadFrequently that can be used for image processing
|
|
55
|
+
* @type {OffscreenCanvas}
|
|
56
|
+
* @memberof Draw */
|
|
57
|
+
let workReadCanvas;
|
|
58
|
+
|
|
59
|
+
/** Offscreen canvas with willReadFrequently that can be used for image processing
|
|
60
|
+
* @type {OffscreenCanvasRenderingContext2D}
|
|
61
|
+
* @memberof Draw */
|
|
62
|
+
let workReadContext;
|
|
63
|
+
|
|
65
64
|
/** The size of the main canvas (and other secondary canvases)
|
|
66
65
|
* @type {Vector2}
|
|
67
66
|
* @memberof Draw */
|
|
@@ -84,7 +83,7 @@ let drawCount;
|
|
|
84
83
|
* - This can take vecs or floats for easier use and conversion
|
|
85
84
|
* - If an index is passed in, the tile size and index will determine the position
|
|
86
85
|
* @param {Vector2|number} [pos=0] - Position of the tile in pixels, or tile index
|
|
87
|
-
* @param {Vector2|number} [size
|
|
86
|
+
* @param {Vector2|number} [size] - Size of tile in pixels
|
|
88
87
|
* @param {number} [textureIndex] - Texture index to use
|
|
89
88
|
* @param {number} [padding] - How many pixels padding around tiles
|
|
90
89
|
* @return {TileInfo}
|
|
@@ -94,7 +93,7 @@ let drawCount;
|
|
|
94
93
|
* tile(1, 16, 3) // a tile at index 1 of size 16 on texture 3
|
|
95
94
|
* tile(vec2(4,8), vec2(30,10)) // a tile at index (4,8) with a size of (30,10)
|
|
96
95
|
* @memberof Draw */
|
|
97
|
-
function tile(pos=new Vector2, size=
|
|
96
|
+
function tile(pos=new Vector2, size=tileDefaultSize, textureIndex=0, padding=tileDefaultPadding)
|
|
98
97
|
{
|
|
99
98
|
if (headlessMode)
|
|
100
99
|
return new TileInfo;
|
|
@@ -133,13 +132,13 @@ function tile(pos=new Vector2, size=tileSizeDefault, textureIndex=0, padding=0)
|
|
|
133
132
|
class TileInfo
|
|
134
133
|
{
|
|
135
134
|
/** 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} [
|
|
135
|
+
* @param {Vector2} [pos=(0,0)] - Top left corner of tile in pixels
|
|
136
|
+
* @param {Vector2} [size] - Size of tile in pixels
|
|
137
|
+
* @param {number} [textureIndex] - Texture index to use
|
|
138
|
+
* @param {number} [padding] - How many pixels padding around tiles
|
|
139
|
+
* @param {number} [bleed] - How many pixels smaller to draw tiles
|
|
141
140
|
*/
|
|
142
|
-
constructor(pos=vec2(), size=
|
|
141
|
+
constructor(pos=vec2(), size=tileDefaultSize, textureIndex=0, padding=tileDefaultPadding, bleed=tileDefaultBleed)
|
|
143
142
|
{
|
|
144
143
|
/** @property {Vector2} - Top left corner of tile in pixels */
|
|
145
144
|
this.pos = pos.copy();
|
|
@@ -152,7 +151,7 @@ class TileInfo
|
|
|
152
151
|
/** @property {TextureInfo} - The texture info for this tile */
|
|
153
152
|
this.textureInfo = textureInfos[this.textureIndex];
|
|
154
153
|
/** @property {number} - Shrinks tile by this many pixels to prevent neighbors bleeding */
|
|
155
|
-
this.
|
|
154
|
+
this.bleed = bleed;
|
|
156
155
|
}
|
|
157
156
|
|
|
158
157
|
/** Returns a copy of this tile offset by a vector
|
|
@@ -160,7 +159,7 @@ class TileInfo
|
|
|
160
159
|
* @return {TileInfo}
|
|
161
160
|
*/
|
|
162
161
|
offset(offset)
|
|
163
|
-
{ return new TileInfo(this.pos.add(offset), this.size, this.textureIndex, this.padding, this.
|
|
162
|
+
{ return new TileInfo(this.pos.add(offset), this.size, this.textureIndex, this.padding, this.bleed); }
|
|
164
163
|
|
|
165
164
|
/** Returns a copy of this tile offset by a number of animation frames
|
|
166
165
|
* @param {number} frame - Offset to apply in animation frames
|
|
@@ -183,7 +182,7 @@ class TileInfo
|
|
|
183
182
|
this.size = textureInfo.size.copy();
|
|
184
183
|
this.textureInfo = textureInfo;
|
|
185
184
|
// do not use padding or bleed
|
|
186
|
-
this.
|
|
185
|
+
this.bleed = this.padding = 0;
|
|
187
186
|
return this;
|
|
188
187
|
}
|
|
189
188
|
}
|
|
@@ -249,7 +248,7 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
|
|
|
249
248
|
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
250
249
|
|
|
251
250
|
const textureInfo = tileInfo && tileInfo.textureInfo;
|
|
252
|
-
const
|
|
251
|
+
const bleed = tileInfo?.bleed ?? 0;
|
|
253
252
|
if (useWebGL && glEnable)
|
|
254
253
|
{
|
|
255
254
|
ASSERT(!!glContext, 'WebGL is not enabled!');
|
|
@@ -264,13 +263,13 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
|
|
|
264
263
|
const w = tileInfo.size.x * sizeInverse.x;
|
|
265
264
|
const h = tileInfo.size.y * sizeInverse.y;
|
|
266
265
|
glSetTexture(textureInfo.glTexture);
|
|
267
|
-
if (
|
|
266
|
+
if (bleed)
|
|
268
267
|
{
|
|
269
|
-
const
|
|
270
|
-
const
|
|
268
|
+
const bleedX = sizeInverse.x*bleed;
|
|
269
|
+
const bleedY = sizeInverse.y*bleed;
|
|
271
270
|
glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
|
|
272
|
-
x +
|
|
273
|
-
x -
|
|
271
|
+
x + bleedX, y + bleedY,
|
|
272
|
+
x - bleedX + w, y - bleedY + h,
|
|
274
273
|
color.rgbaInt(), additiveColor && additiveColor.rgbaInt());
|
|
275
274
|
}
|
|
276
275
|
else
|
|
@@ -298,7 +297,7 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
|
|
|
298
297
|
// calculate uvs and render
|
|
299
298
|
const x = tileInfo.pos.x, y = tileInfo.pos.y;
|
|
300
299
|
const w = tileInfo.size.x, h = tileInfo.size.y;
|
|
301
|
-
drawImageColor(context, textureInfo.image, x, y, w, h, -.5, -.5, 1, 1, color, additiveColor,
|
|
300
|
+
drawImageColor(context, textureInfo.image, x, y, w, h, -.5, -.5, 1, 1, color, additiveColor, bleed);
|
|
302
301
|
}
|
|
303
302
|
else
|
|
304
303
|
{
|
|
@@ -663,26 +662,7 @@ function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, f
|
|
|
663
662
|
drawTextScreen(text, pos, size, color, lineWidth, lineColor, textAlign, font, fontStyle, maxWidth, angle, context);
|
|
664
663
|
}
|
|
665
664
|
|
|
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
|
|
665
|
+
/** Draw text in screen space
|
|
686
666
|
* Automatically splits new lines into rows
|
|
687
667
|
* @param {string|number} text
|
|
688
668
|
* @param {Vector2} pos
|
|
@@ -695,9 +675,9 @@ function drawTextOverlay(text, pos, size=1, color, lineWidth=0, lineColor, textA
|
|
|
695
675
|
* @param {string} [fontStyle]
|
|
696
676
|
* @param {number} [maxWidth]
|
|
697
677
|
* @param {number} [angle]
|
|
698
|
-
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=
|
|
678
|
+
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=mainContext]
|
|
699
679
|
* @memberof Draw */
|
|
700
|
-
function drawTextScreen(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=BLACK, textAlign='center', font=fontDefault, fontStyle='', maxWidth, angle=0, context=
|
|
680
|
+
function drawTextScreen(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=BLACK, textAlign='center', font=fontDefault, fontStyle='', maxWidth, angle=0, context=mainContext)
|
|
701
681
|
{
|
|
702
682
|
ASSERT(isString(text), 'text must be a string');
|
|
703
683
|
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
@@ -741,16 +721,16 @@ function drawTextScreen(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=B
|
|
|
741
721
|
* @memberof Draw */
|
|
742
722
|
function screenToWorld(screenPos)
|
|
743
723
|
{
|
|
724
|
+
ASSERT(isVector2(screenPos), 'screenPos must be a vec2');
|
|
725
|
+
|
|
744
726
|
let x = (screenPos.x - mainCanvasSize.x/2 + .5) / cameraScale;
|
|
745
727
|
let y = (screenPos.y - mainCanvasSize.y/2 + .5) / -cameraScale;
|
|
746
728
|
if (cameraAngle)
|
|
747
729
|
{
|
|
748
730
|
// apply camera rotation
|
|
749
731
|
const c = cos(-cameraAngle), s = sin(-cameraAngle);
|
|
750
|
-
const
|
|
751
|
-
|
|
752
|
-
x = rotatedX;
|
|
753
|
-
y = rotatedY;
|
|
732
|
+
const xr = x * c - y * s, yr = x * s + y * c;
|
|
733
|
+
x = xr; y = yr;
|
|
754
734
|
}
|
|
755
735
|
return new Vector2(x + cameraPos.x, y + cameraPos.y);
|
|
756
736
|
}
|
|
@@ -761,16 +741,16 @@ function screenToWorld(screenPos)
|
|
|
761
741
|
* @memberof Draw */
|
|
762
742
|
function worldToScreen(worldPos)
|
|
763
743
|
{
|
|
744
|
+
ASSERT(isVector2(worldPos), 'worldPos must be a vec2');
|
|
745
|
+
|
|
764
746
|
let x = worldPos.x - cameraPos.x;
|
|
765
747
|
let y = worldPos.y - cameraPos.y;
|
|
766
748
|
if (cameraAngle)
|
|
767
749
|
{
|
|
768
750
|
// apply inverse camera rotation
|
|
769
751
|
const c = cos(cameraAngle), s = sin(cameraAngle);
|
|
770
|
-
const
|
|
771
|
-
|
|
772
|
-
x = rotatedX;
|
|
773
|
-
y = rotatedY;
|
|
752
|
+
const xr = x * c - y * s, yr = x * s + y * c;
|
|
753
|
+
x = xr; y = yr;
|
|
774
754
|
}
|
|
775
755
|
return new Vector2
|
|
776
756
|
(
|
|
@@ -785,16 +765,16 @@ function worldToScreen(worldPos)
|
|
|
785
765
|
* @memberof Draw */
|
|
786
766
|
function screenToWorldDelta(screenDelta)
|
|
787
767
|
{
|
|
768
|
+
ASSERT(isVector2(screenDelta), 'screenDelta must be a vec2');
|
|
769
|
+
|
|
788
770
|
let x = screenDelta.x / cameraScale;
|
|
789
771
|
let y = screenDelta.y / -cameraScale;
|
|
790
772
|
if (cameraAngle)
|
|
791
773
|
{
|
|
792
774
|
// apply camera rotation
|
|
793
775
|
const c = cos(-cameraAngle), s = sin(-cameraAngle);
|
|
794
|
-
const
|
|
795
|
-
|
|
796
|
-
x = rotatedX;
|
|
797
|
-
y = rotatedY;
|
|
776
|
+
const xr = x * c - y * s, yr = x * s + y * c;
|
|
777
|
+
x = xr; y = yr;
|
|
798
778
|
}
|
|
799
779
|
return new Vector2(x, y);
|
|
800
780
|
}
|
|
@@ -805,16 +785,16 @@ function screenToWorldDelta(screenDelta)
|
|
|
805
785
|
* @memberof Draw */
|
|
806
786
|
function worldToScreenDelta(worldDelta)
|
|
807
787
|
{
|
|
788
|
+
ASSERT(isVector2(worldDelta), 'worldDelta must be a vec2');
|
|
789
|
+
|
|
808
790
|
let x = worldDelta.x;
|
|
809
791
|
let y = worldDelta.y;
|
|
810
792
|
if (cameraAngle)
|
|
811
793
|
{
|
|
812
794
|
// apply inverse camera rotation
|
|
813
795
|
const c = cos(cameraAngle), s = sin(cameraAngle);
|
|
814
|
-
const
|
|
815
|
-
|
|
816
|
-
x = rotatedX;
|
|
817
|
-
y = rotatedY;
|
|
796
|
+
const xr = x * c - y * s, yr = x * s + y * c;
|
|
797
|
+
x = xr; y = yr;
|
|
818
798
|
}
|
|
819
799
|
return new Vector2(x * cameraScale, y * -cameraScale);
|
|
820
800
|
}
|
|
@@ -827,6 +807,10 @@ function worldToScreenDelta(worldDelta)
|
|
|
827
807
|
* @memberof Draw */
|
|
828
808
|
function screenToWorldTransform(screenPos, screenSize, screenAngle=0)
|
|
829
809
|
{
|
|
810
|
+
ASSERT(isVector2(screenPos), 'screenPos must be a vec2');
|
|
811
|
+
ASSERT(isVector2(screenSize), 'screenSize must be a vec2');
|
|
812
|
+
ASSERT(isNumber(screenAngle), 'screenAngle must be a number');
|
|
813
|
+
|
|
830
814
|
return [
|
|
831
815
|
screenToWorld(screenPos),
|
|
832
816
|
screenSize.scale(1/cameraScale),
|
|
@@ -842,6 +826,10 @@ function screenToWorldTransform(screenPos, screenSize, screenAngle=0)
|
|
|
842
826
|
* @memberof Draw */
|
|
843
827
|
function worldToScreenTransform(worldPos, worldSize, worldAngle=0)
|
|
844
828
|
{
|
|
829
|
+
ASSERT(isVector2(worldPos), 'worldPos must be a vec2');
|
|
830
|
+
ASSERT(isVector2(worldSize), 'worldSize must be a vec2');
|
|
831
|
+
ASSERT(isNumber(worldAngle), 'worldAngle must be a number');
|
|
832
|
+
|
|
845
833
|
return [
|
|
846
834
|
worldToScreen(worldPos),
|
|
847
835
|
worldSize.scale(cameraScale),
|
|
@@ -854,8 +842,8 @@ function worldToScreenTransform(worldPos, worldSize, worldAngle=0)
|
|
|
854
842
|
* @memberof Draw */
|
|
855
843
|
function getCameraSize() { return mainCanvasSize.scale(1/cameraScale); }
|
|
856
844
|
|
|
857
|
-
/** Check if a point or circle is on screen
|
|
858
|
-
* If size is a Vector2, uses the
|
|
845
|
+
/** Check if a box, point, or circle is on screen with a circle test
|
|
846
|
+
* If size is a Vector2, uses the length as diameter
|
|
859
847
|
* This can be used to cull offscreen objects from render or update
|
|
860
848
|
* @param {Vector2} pos - world space position
|
|
861
849
|
* @param {Vector2|number} size - world space size or diameter
|
|
@@ -863,12 +851,30 @@ function getCameraSize() { return mainCanvasSize.scale(1/cameraScale); }
|
|
|
863
851
|
* @memberof Draw */
|
|
864
852
|
function isOnScreen(pos, size=0)
|
|
865
853
|
{
|
|
866
|
-
pos
|
|
854
|
+
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
855
|
+
ASSERT(isVector2(size) || isNumber(size), 'size must be a vec2 or number');
|
|
856
|
+
|
|
857
|
+
// optimized circle on screen test
|
|
858
|
+
// pos = worldToScreen(pos);
|
|
859
|
+
let x = pos.x - cameraPos.x;
|
|
860
|
+
let y = pos.y - cameraPos.y;
|
|
861
|
+
if (cameraAngle)
|
|
862
|
+
{
|
|
863
|
+
// apply inverse camera rotation
|
|
864
|
+
const c = cos(cameraAngle), s = sin(cameraAngle);
|
|
865
|
+
const xr = x * c - y * s, yr = x * s + y * c;
|
|
866
|
+
x = xr; y = yr;
|
|
867
|
+
}
|
|
868
|
+
x *= cameraScale*2; y *= -cameraScale*2;
|
|
869
|
+
|
|
867
870
|
if (size instanceof Vector2)
|
|
868
|
-
size =
|
|
869
|
-
size *= cameraScale
|
|
870
|
-
|
|
871
|
-
|
|
871
|
+
size = size.length(); // use length of vector as diameter
|
|
872
|
+
size *= cameraScale;
|
|
873
|
+
|
|
874
|
+
// check against screen bounds
|
|
875
|
+
const w = mainCanvasSize.x, h = mainCanvasSize.y;
|
|
876
|
+
return x + size > -w && x - size < w &&
|
|
877
|
+
y + size > -h && y - size < h;
|
|
872
878
|
}
|
|
873
879
|
|
|
874
880
|
/** Enable normal or additive blend mode
|
|
@@ -882,18 +888,19 @@ function setBlendMode(additive=false, context)
|
|
|
882
888
|
context.globalCompositeOperation = additive ? 'lighter' : 'source-over';
|
|
883
889
|
}
|
|
884
890
|
|
|
885
|
-
/** Combines
|
|
886
|
-
* This is necessary for things like
|
|
891
|
+
/** Combines LittleJS canvases onto the main canvas
|
|
892
|
+
* This is necessary for things like screenshots and video
|
|
887
893
|
* @memberof Draw */
|
|
888
894
|
function combineCanvases()
|
|
889
895
|
{
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
896
|
+
const w = mainCanvasSize.x, h = mainCanvasSize.y;
|
|
897
|
+
workCanvas.width = w;
|
|
898
|
+
workCanvas.height = h;
|
|
899
|
+
workContext.fillRect(0,0,w,h); // remove background alpha
|
|
900
|
+
glCopyToContext(workContext);
|
|
901
|
+
workContext.drawImage(mainCanvas, 0, 0);
|
|
902
|
+
mainCanvas.width |= 0;
|
|
903
|
+
mainContext.drawImage(workCanvas, 0, 0);
|
|
897
904
|
}
|
|
898
905
|
|
|
899
906
|
/** Helper function to draw an image with color and additive color applied
|
|
@@ -910,18 +917,18 @@ function combineCanvases()
|
|
|
910
917
|
* @param {number} dHeight
|
|
911
918
|
* @param {Color} color
|
|
912
919
|
* @param {Color} [additiveColor]
|
|
913
|
-
* @param {number} [
|
|
920
|
+
* @param {number} [bleed] - How many pixels to shrink the source, used to fix bleeding
|
|
914
921
|
* @memberof Draw */
|
|
915
|
-
function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, color, additiveColor,
|
|
922
|
+
function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, color, additiveColor, bleed=0)
|
|
916
923
|
{
|
|
917
924
|
function isWhite(c) { return c.r >= 1 && c.g >= 1 && c.b >= 1; }
|
|
918
925
|
function isBlack(c) { return c.r <= 0 && c.g <= 0 && c.b <= 0 && c.a <= 0; }
|
|
919
|
-
const sx2 =
|
|
920
|
-
const sy2 =
|
|
926
|
+
const sx2 = bleed;
|
|
927
|
+
const sy2 = bleed;
|
|
921
928
|
sWidth = max(1,sWidth|0);
|
|
922
929
|
sHeight = max(1,sHeight|0);
|
|
923
|
-
const sWidth2 = sWidth - 2*
|
|
924
|
-
const sHeight2 = sHeight - 2*
|
|
930
|
+
const sWidth2 = sWidth - 2*bleed;
|
|
931
|
+
const sHeight2 = sHeight - 2*bleed;
|
|
925
932
|
if (!canvasColorTiles || (additiveColor ? isWhite(color.add(additiveColor)) && additiveColor.a <= 0 : isWhite(color)))
|
|
926
933
|
{
|
|
927
934
|
// white texture with no additive alpha, no need to tint
|
|
@@ -932,12 +939,12 @@ function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth,
|
|
|
932
939
|
else
|
|
933
940
|
{
|
|
934
941
|
// copy to offscreen canvas
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
942
|
+
workReadCanvas.width = sWidth;
|
|
943
|
+
workReadCanvas.height = sHeight;
|
|
944
|
+
workReadContext.drawImage(image, sx|0, sy|0, sWidth, sHeight, 0, 0, sWidth, sHeight);
|
|
938
945
|
|
|
939
946
|
// tint image using offscreen work context
|
|
940
|
-
const imageData =
|
|
947
|
+
const imageData = workReadContext.getImageData(0, 0, sWidth, sHeight);
|
|
941
948
|
const data = imageData.data;
|
|
942
949
|
if (additiveColor && !isBlack(additiveColor))
|
|
943
950
|
{
|
|
@@ -946,8 +953,8 @@ function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth,
|
|
|
946
953
|
const colorAdd = [additiveColor.r * 255, additiveColor.g * 255, additiveColor.b * 255, additiveColor.a * 255];
|
|
947
954
|
for (let i = 0; i < data.length; ++i)
|
|
948
955
|
data[i] = data[i] * colorMultiply[i&3] + colorAdd[i&3] |0;
|
|
949
|
-
|
|
950
|
-
context.drawImage(
|
|
956
|
+
workReadContext.putImageData(imageData, 0, 0);
|
|
957
|
+
context.drawImage(workReadCanvas, sx2, sy2, sWidth2, sHeight2, dx, dy, dWidth, dHeight);
|
|
951
958
|
}
|
|
952
959
|
else
|
|
953
960
|
{
|
|
@@ -958,9 +965,9 @@ function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth,
|
|
|
958
965
|
data[i+1] *= color.g;
|
|
959
966
|
data[i+2] *= color.b;
|
|
960
967
|
}
|
|
961
|
-
|
|
968
|
+
workReadContext.putImageData(imageData, 0, 0);
|
|
962
969
|
context.globalAlpha = color.a;
|
|
963
|
-
context.drawImage(
|
|
970
|
+
context.drawImage(workReadCanvas, sx2, sy2, sWidth2, sHeight2, dx, dy, dWidth, dHeight);
|
|
964
971
|
context.globalAlpha = 1;
|
|
965
972
|
}
|
|
966
973
|
}
|
|
@@ -1022,7 +1029,7 @@ class FontImage
|
|
|
1022
1029
|
constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1))
|
|
1023
1030
|
{
|
|
1024
1031
|
// load default font image
|
|
1025
|
-
if (!engineFontImage)
|
|
1032
|
+
if (!image && !engineFontImage)
|
|
1026
1033
|
{
|
|
1027
1034
|
engineFontImage = new Image;
|
|
1028
1035
|
engineFontImage.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6ECLBdFY+Q0PMNgf0yCgsSAGZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWwtROWpVQEyWh2npdpBmTUFVhb29RINgLIukoXr5LIAvYQ5ve+1FqWEMqNKTX3FAJHyQDRZvmKWubAACcv5z5Gtg2oyCWE+Yk/8JZQX1jTTCpKAFGIgza+dJCNBF2UskRlsgwitHbSV0QLgt9sTPtsRlvJjEr8C/FARWA2bJ/TtJ7lko34dNDn6usJUMzuErP89UUBJbWeozrwLLncXczd508deAjLWipLO4Q5XGPcJvPu92cNDaN0P5G1FL0nSOzddZOrJ6rNhbXGmeDvO3TF7DeJWl4bvaYQTNHCTeuqKZmbjHaSOFes+IX/+IhHrnAkXOAsfn24EM68XieIECoccD4KZLk/odiwzeo2rovYdhvb2HYFgyznJyDpYJdYOmfXgVdJTaUi4xA2uWYNYec9BLeqdl9EsoTw582mSFDX2DxVLbNt9U3YYoeatBad1c2Tj8t2akrjaIGJNywKB/7h75/gN3vCMSaadIUTAAAAAElFTkSuQmCC';
|
|
@@ -1045,23 +1052,14 @@ class FontImage
|
|
|
1045
1052
|
this.drawTextScreen(text, worldToScreen(pos).floor(), scale*cameraScale|0, center, context);
|
|
1046
1053
|
}
|
|
1047
1054
|
|
|
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
|
|
1055
|
+
/** Draw text in screen space using the image font
|
|
1058
1056
|
* @param {string|number} text
|
|
1059
1057
|
* @param {Vector2} pos
|
|
1060
1058
|
* @param {number} [scale]
|
|
1061
1059
|
* @param {boolean} [center]
|
|
1062
1060
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
|
|
1063
1061
|
*/
|
|
1064
|
-
drawTextScreen(text, pos, scale=4, center=true, context=
|
|
1062
|
+
drawTextScreen(text, pos, scale=4, center=true, context=mainContext)
|
|
1065
1063
|
{
|
|
1066
1064
|
context.save();
|
|
1067
1065
|
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,
|
|
@@ -60,13 +60,13 @@ export
|
|
|
60
60
|
canvasMaxAspect,
|
|
61
61
|
canvasFixedSize,
|
|
62
62
|
canvasPixelated,
|
|
63
|
-
overlayCanvasPixelated,
|
|
64
63
|
tilesPixelated,
|
|
65
64
|
fontDefault,
|
|
66
65
|
showSplashScreen,
|
|
67
66
|
headlessMode,
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
tileDefaultSize,
|
|
68
|
+
tileDefaultPadding,
|
|
69
|
+
tileDefaultBleed,
|
|
70
70
|
enablePhysicsSolver,
|
|
71
71
|
objectDefaultMass,
|
|
72
72
|
objectDefaultDamping,
|
|
@@ -105,14 +105,14 @@ export
|
|
|
105
105
|
setCanvasMaxAspect,
|
|
106
106
|
setCanvasFixedSize,
|
|
107
107
|
setCanvasPixelated,
|
|
108
|
-
setOverlayCanvasPixelated,
|
|
109
108
|
setTilesPixelated,
|
|
110
109
|
setFontDefault,
|
|
111
110
|
setShowSplashScreen,
|
|
112
111
|
setHeadlessMode,
|
|
113
112
|
setGLEnable,
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
setTileDefaultSize,
|
|
114
|
+
setTileDefaultPadding,
|
|
115
|
+
setTileDefaultBleed,
|
|
116
116
|
setEnablePhysicsSolver,
|
|
117
117
|
setObjectDefaultMass,
|
|
118
118
|
setObjectDefaultDamping,
|
|
@@ -141,7 +141,7 @@ export
|
|
|
141
141
|
setMedalDisplaySlideTime,
|
|
142
142
|
setMedalDisplaySize,
|
|
143
143
|
setMedalsPreventUnlock,
|
|
144
|
-
|
|
144
|
+
setDebugWatermark,
|
|
145
145
|
setDebugKey,
|
|
146
146
|
|
|
147
147
|
// Utilities
|
|
@@ -221,8 +221,10 @@ export
|
|
|
221
221
|
mainContext,
|
|
222
222
|
drawCanvas,
|
|
223
223
|
drawContext,
|
|
224
|
-
|
|
225
|
-
|
|
224
|
+
workCanvas,
|
|
225
|
+
workContext,
|
|
226
|
+
workReadCanvas,
|
|
227
|
+
workReadContext,
|
|
226
228
|
mainCanvasSize,
|
|
227
229
|
textureInfos,
|
|
228
230
|
drawCount,
|
|
@@ -240,7 +242,6 @@ export
|
|
|
240
242
|
drawCircle,
|
|
241
243
|
drawCanvas2D,
|
|
242
244
|
drawText,
|
|
243
|
-
drawTextOverlay,
|
|
244
245
|
drawTextScreen,
|
|
245
246
|
setBlendMode,
|
|
246
247
|
combineCanvases,
|
package/src/engineInput.js
CHANGED
package/src/engineMedals.js
CHANGED
|
@@ -139,10 +139,10 @@ class Medal
|
|
|
139
139
|
*/
|
|
140
140
|
render(hidePercent=0)
|
|
141
141
|
{
|
|
142
|
-
const context =
|
|
142
|
+
const context = mainContext;
|
|
143
143
|
const width = min(medalDisplaySize.x, mainCanvas.width);
|
|
144
144
|
const height = medalDisplaySize.y;
|
|
145
|
-
const x =
|
|
145
|
+
const x = mainCanvas.width - width;
|
|
146
146
|
const y = -height*hidePercent;
|
|
147
147
|
const backgroundColor = hsl(0,0,.9);
|
|
148
148
|
|
|
@@ -183,7 +183,7 @@ class Medal
|
|
|
183
183
|
{
|
|
184
184
|
// draw the image or icon
|
|
185
185
|
if (this.image)
|
|
186
|
-
|
|
186
|
+
mainContext.drawImage(this.image, pos.x-size/2, pos.y-size/2, size, size);
|
|
187
187
|
else
|
|
188
188
|
drawTextScreen(this.icon, pos, size*.7, BLACK);
|
|
189
189
|
}
|
package/src/engineObject.js
CHANGED
|
@@ -430,10 +430,11 @@ class EngineObject
|
|
|
430
430
|
* @return {number} -1 if this.mirror is true, or 1 if not mirrored */
|
|
431
431
|
getMirrorSign() { return this.mirror ? -1 : 1; }
|
|
432
432
|
|
|
433
|
-
/** Attaches a child to this with a
|
|
433
|
+
/** Attaches a child to this with a local transform, returns child for chaining
|
|
434
434
|
* @param {EngineObject} child
|
|
435
435
|
* @param {Vector2} [localPos=(0,0)]
|
|
436
|
-
* @param {number} [localAngle]
|
|
436
|
+
* @param {number} [localAngle]
|
|
437
|
+
* @return {EngineObject} The child object added */
|
|
437
438
|
addChild(child, localPos=vec2(), localAngle=0)
|
|
438
439
|
{
|
|
439
440
|
ASSERT(!child.parent && !this.children.includes(child));
|
|
@@ -443,6 +444,7 @@ class EngineObject
|
|
|
443
444
|
child.parent = this;
|
|
444
445
|
child.localPos = localPos.copy();
|
|
445
446
|
child.localAngle = localAngle;
|
|
447
|
+
return child;
|
|
446
448
|
}
|
|
447
449
|
|
|
448
450
|
/** Removes a child from this one
|