littlejsengine 1.15.2 → 1.15.3

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.
@@ -33,7 +33,7 @@ const engineName = 'LittleJS';
33
33
  * @type {string}
34
34
  * @default
35
35
  * @memberof Engine */
36
- const engineVersion = '1.15.2';
36
+ const engineVersion = '1.15.3';
37
37
 
38
38
  /** Frames per second to update
39
39
  * @type {number}
@@ -2997,7 +2997,9 @@ class EngineObject
2997
2997
  {
2998
2998
  ASSERT(child.parent === this && this.children.includes(child));
2999
2999
  ASSERT(child instanceof EngineObject, 'child must be an EngineObject');
3000
- this.children.splice(this.children.indexOf(child), 1);
3000
+ const index = this.children.indexOf(child);
3001
+ ASSERT(index >= 0, 'child not found in children array');
3002
+ index >= 0 && this.children.splice(index, 1);
3001
3003
  child.parent = 0;
3002
3004
  }
3003
3005
 
@@ -3316,15 +3318,11 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
3316
3318
 
3317
3319
  const textureInfo = tileInfo && tileInfo.textureInfo;
3318
3320
  const bleedScale = tileInfo ? tileInfo.bleedScale : 0;
3319
- if (useWebGL)
3321
+ if (useWebGL && glEnable)
3320
3322
  {
3321
3323
  ASSERT(!!glContext, 'WebGL is not enabled!');
3322
3324
  if (screenSpace)
3323
- {
3324
- // convert to world space
3325
- pos = screenToWorld(pos);
3326
- size = size.scale(1/cameraScale);
3327
- }
3325
+ [pos, size, angle] = screenToWorldTransform(pos, size, angle);
3328
3326
  if (textureInfo)
3329
3327
  {
3330
3328
  // calculate uvs and render
@@ -3412,7 +3410,8 @@ function drawRectGradient(pos, size, colorTop=WHITE, colorBottom=BLACK, angle=0,
3412
3410
  ASSERT(isColor(colorTop) && isColor(colorBottom), 'color is invalid');
3413
3411
  ASSERT(isNumber(angle), 'angle must be a number');
3414
3412
  ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
3415
- if (useWebGL)
3413
+
3414
+ if (useWebGL && glEnable)
3416
3415
  {
3417
3416
  ASSERT(!!glContext, 'WebGL is not enabled!');
3418
3417
  if (screenSpace)
@@ -3420,6 +3419,7 @@ function drawRectGradient(pos, size, colorTop=WHITE, colorBottom=BLACK, angle=0,
3420
3419
  // convert to world space
3421
3420
  pos = screenToWorld(pos);
3422
3421
  size = size.scale(1/cameraScale);
3422
+ angle += cameraAngle;
3423
3423
  }
3424
3424
  // build 4 corner points for the rectangle
3425
3425
  const points = [], colors = [];
@@ -3475,17 +3475,14 @@ function drawLineList(points, width=.1, color, wrap=false, pos=vec2(), angle=0,
3475
3475
  ASSERT(isVector2(pos), 'pos must be a vec2');
3476
3476
  ASSERT(isNumber(angle), 'angle must be a number');
3477
3477
  ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
3478
- if (useWebGL)
3478
+
3479
+ if (useWebGL && glEnable)
3479
3480
  {
3480
3481
  ASSERT(!!glContext, 'WebGL is not enabled!');
3481
- let scale = 1;
3482
+ let size = vec2(1);
3482
3483
  if (screenSpace)
3483
- {
3484
- // convert to world space
3485
- pos = screenToWorld(pos);
3486
- scale = 1/cameraScale;
3487
- }
3488
- glDrawOutlineTransform(points, color.rgbaInt(), width, pos.x, pos.y, scale, scale, angle, wrap);
3484
+ [pos, size, angle] = screenToWorldTransform(pos, size, angle);
3485
+ glDrawOutlineTransform(points, color.rgbaInt(), width, pos.x, pos.y, size.x, size.y, angle, wrap);
3489
3486
  }
3490
3487
  else
3491
3488
  {
@@ -3581,19 +3578,15 @@ function drawPoly(points, color=WHITE, lineWidth=0, lineColor=BLACK, pos=vec2(),
3581
3578
  ASSERT(isNumber(angle), 'angle must be a number');
3582
3579
  ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
3583
3580
 
3584
- if (useWebGL)
3581
+ if (useWebGL && glEnable)
3585
3582
  {
3586
3583
  ASSERT(!!glContext, 'WebGL is not enabled!');
3587
- let scale = 1;
3584
+ let size = vec2(1);
3588
3585
  if (screenSpace)
3589
- {
3590
- // convert to world space
3591
- pos = screenToWorld(pos);
3592
- scale = 1/cameraScale;
3593
- }
3594
- glDrawPointsTransform(points, color.rgbaInt(), pos.x, pos.y, scale, scale, angle);
3586
+ [pos, size, angle] = screenToWorldTransform(pos, size, angle);
3587
+ glDrawPointsTransform(points, color.rgbaInt(), pos.x, pos.y, size.x, size.y, angle);
3595
3588
  if (lineWidth > 0)
3596
- glDrawOutlineTransform(points, lineColor.rgbaInt(), lineWidth, pos.x, pos.y, scale, scale, angle);
3589
+ glDrawOutlineTransform(points, lineColor.rgbaInt(), lineWidth, pos.x, pos.y, size.x, size.y, angle);
3597
3590
  }
3598
3591
  else
3599
3592
  {
@@ -3636,7 +3629,7 @@ function drawEllipse(pos, size=vec2(1), color=WHITE, angle=0, lineWidth=0, lineC
3636
3629
  ASSERT(lineWidth >= 0 && lineWidth < size.x && lineWidth < size.y, 'invalid lineWidth');
3637
3630
  ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
3638
3631
 
3639
- if (useWebGL)
3632
+ if (useWebGL && glEnable)
3640
3633
  {
3641
3634
  // draw as a regular polygon
3642
3635
  const sides = glCircleSides;
@@ -3699,14 +3692,10 @@ function drawCanvas2D(pos, size, angle=0, mirror=false, drawFunction, screenSpac
3699
3692
  ASSERT(typeof drawFunction === 'function', 'drawFunction must be a function');
3700
3693
 
3701
3694
  if (!screenSpace)
3702
- {
3703
- // transform from world space to screen space
3704
- pos = worldToScreen(pos);
3705
- size = size.scale(cameraScale);
3706
- }
3695
+ [pos, size, angle] = worldToScreenTransform(pos, size, angle);
3707
3696
  context.save();
3708
3697
  context.translate(pos.x+.5, pos.y+.5);
3709
- context.rotate(angle-cameraAngle);
3698
+ context.rotate(angle);
3710
3699
  context.scale(mirror ? -size.x : size.x, -size.y);
3711
3700
  drawFunction(context);
3712
3701
  context.restore();
@@ -3732,7 +3721,14 @@ function drawCanvas2D(pos, size, angle=0, mirror=false, drawFunction, screenSpac
3732
3721
  * @memberof Draw */
3733
3722
  function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, font, fontStyle, maxWidth, angle=0, context=drawContext)
3734
3723
  {
3735
- drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font, fontStyle, maxWidth, angle, context);
3724
+ // convert to screen space
3725
+ pos = worldToScreen(pos);
3726
+ size *= cameraScale;
3727
+ lineWidth *= cameraScale;
3728
+ angle -= cameraAngle;
3729
+ angle *= -1;
3730
+
3731
+ drawTextScreen(text, pos, size, color, lineWidth, lineColor, textAlign, font, fontStyle, maxWidth, angle, context);
3736
3732
  }
3737
3733
 
3738
3734
  /** Draw text on overlay canvas in world space
@@ -3891,6 +3887,36 @@ function worldToScreenDelta(worldDelta)
3891
3887
  return new Vector2(x * cameraScale, y * -cameraScale);
3892
3888
  }
3893
3889
 
3890
+ /** Convert screen space transform to world space
3891
+ * @param {Vector2} screenPos
3892
+ * @param {Vector2} screenSize
3893
+ * @param {number} [screenAngle]
3894
+ * @return {[Vector2, Vector2, number]} - [pos, size, angle]
3895
+ * @memberof Draw */
3896
+ function screenToWorldTransform(screenPos, screenSize, screenAngle=0)
3897
+ {
3898
+ return [
3899
+ screenToWorld(screenPos),
3900
+ screenSize.scale(1/cameraScale),
3901
+ screenAngle + cameraAngle
3902
+ ];
3903
+ }
3904
+
3905
+ /** Convert world space transform to screen space
3906
+ * @param {Vector2} worldPos
3907
+ * @param {Vector2} worldSize
3908
+ * @param {number} [worldAngle]
3909
+ * @return {[Vector2, Vector2, number]} - [pos, size, angle]
3910
+ * @memberof Draw */
3911
+ function worldToScreenTransform(worldPos, worldSize, worldAngle=0)
3912
+ {
3913
+ return [
3914
+ worldToScreen(worldPos),
3915
+ worldSize.scale(cameraScale),
3916
+ worldAngle - cameraAngle
3917
+ ];
3918
+ }
3919
+
3894
3920
  /** Get the camera's visible area in world space
3895
3921
  * @return {Vector2}
3896
3922
  * @memberof Draw */
@@ -4298,7 +4324,7 @@ function inputUpdate()
4298
4324
  if (headlessMode) return;
4299
4325
 
4300
4326
  // clear input when lost focus (prevent stuck keys)
4301
- if(!(touchInputEnable && isTouchDevice) && !document.hasFocus())
4327
+ if (!(touchInputEnable && isTouchDevice) && !document.hasFocus())
4302
4328
  inputClear();
4303
4329
 
4304
4330
  // update mouse world space position and delta
@@ -4856,7 +4882,6 @@ class Sound
4856
4882
  ASSERT(isNumber(pitch), 'pitch must be a number');
4857
4883
  ASSERT(isNumber(randomnessScale), 'randomnessScale must be a number');
4858
4884
 
4859
-
4860
4885
  if (!soundEnable || headlessMode) return;
4861
4886
  if (!this.sampleChannels) return;
4862
4887
 
@@ -5989,7 +6014,7 @@ class TileCollisionLayer extends TileLayer
5989
6014
  // remove from collision layers array and destroy
5990
6015
  const index = tileCollisionLayers.indexOf(this);
5991
6016
  ASSERT(index >= 0, 'tile collision layer not found in array');
5992
- tileCollisionLayers.splice(index, 1);
6017
+ index >= 0 && tileCollisionLayers.splice(index, 1);
5993
6018
  super.destroy();
5994
6019
  }
5995
6020
 
@@ -8035,6 +8060,7 @@ class UISystemPlugin
8035
8060
  ASSERT(!uiSystem, 'UI system already initialized');
8036
8061
  uiSystem = this;
8037
8062
 
8063
+ // default settings
8038
8064
  /** @property {Color} - Default fill color for UI elements */
8039
8065
  this.defaultColor = WHITE;
8040
8066
  /** @property {Color} - Default outline color for UI elements */
@@ -8063,6 +8089,13 @@ class UISystemPlugin
8063
8089
  this.defaultSoundRelease = undefined;
8064
8090
  /** @property {Sound} - Default sound when interactive UI element is clicked */
8065
8091
  this.defaultSoundClick = undefined;
8092
+ /** @property {Color} - Color for shadow */
8093
+ this.defaultShadowColor = CLEAR_BLACK;
8094
+ /** @property {number} - Size of shadow blur */
8095
+ this.defaultShadowBlur = 5;
8096
+ /** @property {Vector2} - Offset of shadow blur */
8097
+ this.defaultShadowOffset = vec2(5);
8098
+ // system state
8066
8099
  /** @property {Array<UIObject>} - List of all UI elements */
8067
8100
  this.uiObjects = [];
8068
8101
  /** @property {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} - Context to render UI elements to */
@@ -8153,8 +8186,11 @@ class UISystemPlugin
8153
8186
  * @param {number} [lineWidth]
8154
8187
  * @param {Color} [lineColor]
8155
8188
  * @param {number} [cornerRadius]
8156
- * @param {Color} [gradientColor] */
8157
- drawRect(pos, size, color=WHITE, lineWidth=0, lineColor=BLACK, cornerRadius=0, gradientColor)
8189
+ * @param {Color} [gradientColor]
8190
+ * @param {Color} [shadowColor]
8191
+ * @param {number} [shadowBlur]
8192
+ * @param {Color} [shadowOffset] */
8193
+ drawRect(pos, size, color=WHITE, lineWidth=0, lineColor=BLACK, cornerRadius=0, gradientColor, shadowColor=BLACK, shadowBlur=0, shadowOffset=vec2())
8158
8194
  {
8159
8195
  ASSERT(isVector2(pos), 'pos must be a vec2');
8160
8196
  ASSERT(isVector2(size), 'size must be a vec2');
@@ -8176,12 +8212,22 @@ class UISystemPlugin
8176
8212
  }
8177
8213
  else
8178
8214
  context.fillStyle = color.toString();
8215
+ if (shadowBlur || shadowOffset.x || shadowOffset.y)
8216
+ if (shadowColor.a > 0)
8217
+ {
8218
+ // setup shadow
8219
+ context.shadowColor = shadowColor.toString();
8220
+ context.shadowBlur = shadowBlur;
8221
+ context.shadowOffsetX = shadowOffset.x;
8222
+ context.shadowOffsetY = shadowOffset.y;
8223
+ }
8179
8224
  context.beginPath();
8180
8225
  if (cornerRadius && context['roundRect'])
8181
8226
  context['roundRect'](pos.x-size.x/2, pos.y-size.y/2, size.x, size.y, cornerRadius);
8182
8227
  else
8183
8228
  context.rect(pos.x-size.x/2, pos.y-size.y/2, size.x, size.y);
8184
8229
  context.fill();
8230
+ context.shadowColor = '#0000'
8185
8231
  if (lineWidth)
8186
8232
  {
8187
8233
  context.strokeStyle = lineColor.toString();
@@ -8370,6 +8416,12 @@ class UIObject
8370
8416
  this.dragActivate = false;
8371
8417
  /** @property {boolean} - True if this can be a hover object */
8372
8418
  this.canBeHover = true;
8419
+ /** @property {Color} - Color for shadow, undefined if no shadow */
8420
+ this.shadowColor = uiSystem.defaultShadowColor?.copy();
8421
+ /** @property {number} - Size of shadow blur */
8422
+ this.shadowBlur = uiSystem.defaultShadowBlur;
8423
+ /** @property {Vector2} - Offset of shadow blur */
8424
+ this.shadowOffset = uiSystem.defaultShadowOffset.copy();
8373
8425
  uiSystem.uiObjects.push(this);
8374
8426
 
8375
8427
  /** @property {Vector2} - How much to offset the text shadow or undefined */
@@ -8487,7 +8539,7 @@ class UIObject
8487
8539
 
8488
8540
  const lineColor = this.interactive && this.isActiveObject() && !this.disabled ? this.color : this.lineColor;
8489
8541
  const color = this.disabled ? this.disabledColor : this.interactive ? this.isActiveObject() ? this.activeColor || this.color : this.isHoverObject() ? this.hoverColor : this.color : this.color;
8490
- uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius, this.gradientColor);
8542
+ uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius, this.gradientColor, this.shadowColor, this.shadowBlur, this.shadowOffset);
8491
8543
  }
8492
8544
 
8493
8545
  /** Special update when object is not visible */
@@ -7,7 +7,7 @@
7
7
  </head><body>
8
8
 
9
9
  <!-- LittleJS Engine -->
10
- <script src=../../dist/littlejs.js?1.15.2></script>
10
+ <script src=../../dist/littlejs.js?1.15.3></script>
11
11
 
12
12
  <!-- Add your game scripts here -->
13
- <script src=game.js?1.15.2></script>
13
+ <script src=game.js?1.15.3></script>
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html><meta charset=utf-8><body>
2
- <script src=../../dist/littlejs.js?1.15.2></script>
2
+ <script src=../../dist/littlejs.js?1.15.3></script>
3
3
  <script src=../../dist/box2d.wasm.js></script>
4
4
 
5
5
  <!-- LittleJS Engine Source
@@ -39,7 +39,7 @@ class CarObject extends Box2dObject
39
39
  joint.setSpringFrequencyHz(frequency);
40
40
  joint.setMaxMotorTorque(maxTorque);
41
41
  joint.enableMotor(!i);
42
- const friction = 1;
42
+ const friction = 20;
43
43
  wheel.addCircle(2, vec2(), 1, friction);
44
44
  wheel.motorJoint = joint;
45
45
  this.wheels[i] = wheel;
@@ -8,6 +8,7 @@ function gameInit()
8
8
  uiSystem.defaultSoundPress = new Sound([.5,0,220]);
9
9
  uiSystem.defaultSoundClick = new Sound([.5,0,440]);
10
10
  uiSystem.defaultCornerRadius = 20;
11
+ uiSystem.defaultShadowColor = BLACK;
11
12
  canvasClearColor = hsl(.9,.3,.2);
12
13
 
13
14
  // setup music player UI
@@ -9,6 +9,7 @@ function gameInit()
9
9
  uiSystem.defaultSoundClick = new Sound([.5,0,440]);
10
10
  uiSystem.defaultCornerRadius = 20;
11
11
  uiSystem.defaultGradientColor = WHITE;
12
+ uiSystem.defaultShadowColor = BLACK;
12
13
  canvasClearColor = hsl(.9,.3,.2);
13
14
 
14
15
  // setup music player UI
@@ -28,6 +28,7 @@ class UISequencerButton extends UIButton
28
28
  this.cornerRadius = 0;
29
29
  this.dragActivate = true;
30
30
  this.isOn = false;
31
+ this.shadowColor = CLEAR_BLACK;
31
32
 
32
33
  // set instrument and color based on track
33
34
  const pianoStart = 2;
@@ -70,6 +71,7 @@ function gameInit()
70
71
  // initialize UI system
71
72
  new UISystemPlugin;
72
73
  uiSystem.defaultCornerRadius = 8;
74
+ uiSystem.defaultShadowColor = BLACK;
73
75
  canvasClearColor = hsl(0,0,.3);
74
76
 
75
77
  // create sequencer buttons
@@ -2,6 +2,7 @@ function gameInit()
2
2
  {
3
3
  // initialize UI system
4
4
  new UISystemPlugin;
5
+ uiSystem.defaultShadowColor = BLACK;
5
6
  canvasClearColor = hsl(.6,.3,.2);
6
7
 
7
8
  // create a grid of buttons with different sounds
@@ -5,6 +5,7 @@ function gameInit()
5
5
  // setup ui system plugin
6
6
  new UISystemPlugin();
7
7
  uiSystem.defaultCornerRadius = 10;
8
+ uiSystem.defaultShadowColor = BLACK;
8
9
  canvasClearColor = hsl(.3,.3,.2);
9
10
 
10
11
  // create timer button
@@ -5,6 +5,7 @@ function gameInit()
5
5
  uiSystem.defaultSoundPress = new Sound([.5,0,220]);
6
6
  uiSystem.defaultSoundClick = new Sound([.5,0,440]);
7
7
  uiSystem.defaultCornerRadius = 8;
8
+ uiSystem.defaultShadowColor = BLACK;
8
9
 
9
10
  // example button that returns to menu
10
11
  const buttonBack = new UIButton(mainCanvasSize.scale(.5), vec2(200),
@@ -1,8 +1,9 @@
1
1
  function gameInit()
2
2
  {
3
3
  new UISystemPlugin;
4
- canvasClearColor = hsl(0,0,.1);
5
4
  uiSystem.defaultCornerRadius = 20;
5
+ uiSystem.defaultShadowColor = BLACK;
6
+ canvasClearColor = hsl(0,0,.1);
6
7
 
7
8
  // video player
8
9
  const center = mainCanvasSize.scale(.5);
@@ -7,7 +7,7 @@
7
7
  </head><body>
8
8
 
9
9
  <!-- LittleJS Engine -->
10
- <script src=../../dist/littlejs.js?1.15.2></script>
10
+ <script src=../../dist/littlejs.js?1.15.3></script>
11
11
 
12
12
  <!-- LittleJS Engine Source
13
13
  <script src=../../src/engine.js></script>
@@ -31,4 +31,4 @@
31
31
  -->
32
32
 
33
33
  <!-- Add your game scripts here -->
34
- <script src=game.js?1.15.2></script>
34
+ <script src=game.js?1.15.3></script>
@@ -25,6 +25,7 @@ function createUI()
25
25
  LJS.uiSystem.defaultSoundClick = new LJS.Sound([.5,0,440]);
26
26
  LJS.uiSystem.defaultCornerRadius = 8;
27
27
  LJS.uiSystem.defaultGradientColor = LJS.WHITE;
28
+ LJS.uiSystem.defaultShadowColor = LJS.BLACK;
28
29
 
29
30
  // setup root to attach all ui elements to
30
31
  uiRoot = new LJS.UIObject;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "littlejsengine",
3
- "version": "1.15.2",
3
+ "version": "1.15.3",
4
4
  "description": "LittleJS - Tiny and Fast HTML5 Game Engine",
5
5
  "main": "dist/littlejs.esm.js",
6
6
  "types": "dist/littlejs.d.ts",
@@ -36,6 +36,7 @@ class UISystemPlugin
36
36
  ASSERT(!uiSystem, 'UI system already initialized');
37
37
  uiSystem = this;
38
38
 
39
+ // default settings
39
40
  /** @property {Color} - Default fill color for UI elements */
40
41
  this.defaultColor = WHITE;
41
42
  /** @property {Color} - Default outline color for UI elements */
@@ -64,6 +65,13 @@ class UISystemPlugin
64
65
  this.defaultSoundRelease = undefined;
65
66
  /** @property {Sound} - Default sound when interactive UI element is clicked */
66
67
  this.defaultSoundClick = undefined;
68
+ /** @property {Color} - Color for shadow */
69
+ this.defaultShadowColor = CLEAR_BLACK;
70
+ /** @property {number} - Size of shadow blur */
71
+ this.defaultShadowBlur = 5;
72
+ /** @property {Vector2} - Offset of shadow blur */
73
+ this.defaultShadowOffset = vec2(5);
74
+ // system state
67
75
  /** @property {Array<UIObject>} - List of all UI elements */
68
76
  this.uiObjects = [];
69
77
  /** @property {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} - Context to render UI elements to */
@@ -154,8 +162,11 @@ class UISystemPlugin
154
162
  * @param {number} [lineWidth]
155
163
  * @param {Color} [lineColor]
156
164
  * @param {number} [cornerRadius]
157
- * @param {Color} [gradientColor] */
158
- drawRect(pos, size, color=WHITE, lineWidth=0, lineColor=BLACK, cornerRadius=0, gradientColor)
165
+ * @param {Color} [gradientColor]
166
+ * @param {Color} [shadowColor]
167
+ * @param {number} [shadowBlur]
168
+ * @param {Color} [shadowOffset] */
169
+ drawRect(pos, size, color=WHITE, lineWidth=0, lineColor=BLACK, cornerRadius=0, gradientColor, shadowColor=BLACK, shadowBlur=0, shadowOffset=vec2())
159
170
  {
160
171
  ASSERT(isVector2(pos), 'pos must be a vec2');
161
172
  ASSERT(isVector2(size), 'size must be a vec2');
@@ -177,12 +188,22 @@ class UISystemPlugin
177
188
  }
178
189
  else
179
190
  context.fillStyle = color.toString();
191
+ if (shadowBlur || shadowOffset.x || shadowOffset.y)
192
+ if (shadowColor.a > 0)
193
+ {
194
+ // setup shadow
195
+ context.shadowColor = shadowColor.toString();
196
+ context.shadowBlur = shadowBlur;
197
+ context.shadowOffsetX = shadowOffset.x;
198
+ context.shadowOffsetY = shadowOffset.y;
199
+ }
180
200
  context.beginPath();
181
201
  if (cornerRadius && context['roundRect'])
182
202
  context['roundRect'](pos.x-size.x/2, pos.y-size.y/2, size.x, size.y, cornerRadius);
183
203
  else
184
204
  context.rect(pos.x-size.x/2, pos.y-size.y/2, size.x, size.y);
185
205
  context.fill();
206
+ context.shadowColor = '#0000'
186
207
  if (lineWidth)
187
208
  {
188
209
  context.strokeStyle = lineColor.toString();
@@ -371,6 +392,12 @@ class UIObject
371
392
  this.dragActivate = false;
372
393
  /** @property {boolean} - True if this can be a hover object */
373
394
  this.canBeHover = true;
395
+ /** @property {Color} - Color for shadow, undefined if no shadow */
396
+ this.shadowColor = uiSystem.defaultShadowColor?.copy();
397
+ /** @property {number} - Size of shadow blur */
398
+ this.shadowBlur = uiSystem.defaultShadowBlur;
399
+ /** @property {Vector2} - Offset of shadow blur */
400
+ this.shadowOffset = uiSystem.defaultShadowOffset.copy();
374
401
  uiSystem.uiObjects.push(this);
375
402
 
376
403
  /** @property {Vector2} - How much to offset the text shadow or undefined */
@@ -488,7 +515,7 @@ class UIObject
488
515
 
489
516
  const lineColor = this.interactive && this.isActiveObject() && !this.disabled ? this.color : this.lineColor;
490
517
  const color = this.disabled ? this.disabledColor : this.interactive ? this.isActiveObject() ? this.activeColor || this.color : this.isHoverObject() ? this.hoverColor : this.color : this.color;
491
- uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius, this.gradientColor);
518
+ uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius, this.gradientColor, this.shadowColor, this.shadowBlur, this.shadowOffset);
492
519
  }
493
520
 
494
521
  /** Special update when object is not visible */
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.15.2';
33
+ const engineVersion = '1.15.3';
34
34
 
35
35
  /** Frames per second to update
36
36
  * @type {number}
@@ -113,7 +113,6 @@ class Sound
113
113
  ASSERT(isNumber(pitch), 'pitch must be a number');
114
114
  ASSERT(isNumber(randomnessScale), 'randomnessScale must be a number');
115
115
 
116
-
117
116
  if (!soundEnable || headlessMode) return;
118
117
  if (!this.sampleChannels) return;
119
118