pxt-common-packages 9.4.4 → 9.4.8

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.
Files changed (58) hide show
  1. package/built/common-sim.d.ts +3 -2
  2. package/built/common-sim.js +15 -1
  3. package/libs/azureiot/built/debug/binary.js +461 -461
  4. package/libs/color/built/debug/binary.js +8 -8
  5. package/libs/color/colors.ts +11 -0
  6. package/libs/color-sensor/built/debug/binary.js +8 -8
  7. package/libs/controller/built/debug/binary.js +9043 -7832
  8. package/libs/controller---none/built/debug/binary.js +9022 -7811
  9. package/libs/datalogger/built/debug/binary.js +63 -63
  10. package/libs/edge-connector/built/debug/binary.js +8 -8
  11. package/libs/esp32/built/debug/binary.js +462 -462
  12. package/libs/game/_locales/game-strings.json +21 -0
  13. package/libs/game/built/debug/binary.js +8935 -7724
  14. package/libs/game/hitbox.ts +40 -22
  15. package/libs/game/renderText.ts +74 -11
  16. package/libs/game/sprite.ts +244 -16
  17. package/libs/game/spritesay.ts +206 -53
  18. package/libs/lcd/built/debug/binary.js +8 -8
  19. package/libs/light-spectrum-sensor/built/debug/binary.js +8 -8
  20. package/libs/lora/built/debug/binary.js +8 -8
  21. package/libs/matrix-keypad/built/debug/binary.js +8 -8
  22. package/libs/mqtt/built/debug/binary.js +176 -176
  23. package/libs/net/built/debug/binary.js +176 -176
  24. package/libs/net/controller.ts +4 -0
  25. package/libs/net-game/built/debug/binary.js +10832 -9617
  26. package/libs/palette/built/debug/binary.js +8934 -7723
  27. package/libs/pixel/built/debug/binary.js +8 -8
  28. package/libs/power/built/debug/binary.js +8 -8
  29. package/libs/proximity/built/debug/binary.js +9 -9
  30. package/libs/radio/built/debug/binary.js +8 -8
  31. package/libs/radio-broadcast/built/debug/binary.js +8 -8
  32. package/libs/rotary-encoder/built/debug/binary.js +8 -8
  33. package/libs/screen/built/debug/binary.js +50 -50
  34. package/libs/screen/image.cpp +14 -4
  35. package/libs/screen/image.ts +5 -4
  36. package/libs/screen/sim/image.ts +15 -3
  37. package/libs/servo/built/debug/binary.js +8 -8
  38. package/libs/sprite-scaling/README.md +3 -0
  39. package/libs/sprite-scaling/_locales/sprite-scaling-jsdoc-strings.json +1 -0
  40. package/libs/sprite-scaling/_locales/sprite-scaling-strings.json +9 -0
  41. package/libs/sprite-scaling/built/debug/binary.js +40047 -0
  42. package/libs/sprite-scaling/pxt.json +16 -0
  43. package/libs/sprite-scaling/scaling.ts +111 -0
  44. package/libs/sprite-scaling/targetoverrides.ts +1 -0
  45. package/libs/sprite-scaling/test.ts +0 -0
  46. package/libs/storyboard/built/debug/binary.js +8934 -7723
  47. package/libs/wifi---esp32/buildlogin.sh +1 -0
  48. package/libs/wifi---esp32/controller.ts +19 -1
  49. package/libs/wifi---esp32/enums.d.ts +2 -0
  50. package/libs/wifi---esp32/httpserver.cpp +166 -0
  51. package/libs/wifi---esp32/login.full.html +37 -0
  52. package/libs/wifi---esp32/login.html +1 -0
  53. package/libs/wifi---esp32/pxt.json +1 -0
  54. package/libs/wifi---esp32/shims.d.ts +4 -0
  55. package/libs/wifi---esp32/sim/wifisockets.ts +3 -0
  56. package/libs/wifi---esp32/wifi.cpp +13 -14
  57. package/libs/wifi---esp32/wifi.h +13 -1
  58. package/package.json +1 -1
@@ -1,21 +1,19 @@
1
1
  namespace game {
2
2
  export class Hitbox {
3
- img: Image;
4
- rev: number;
3
+ hash: Fx8;
5
4
  parent: Sprite;
6
5
  ox: Fx8;
7
6
  oy: Fx8;
8
7
  width: Fx8;
9
8
  height: Fx8;
10
9
 
11
- constructor(parent: Sprite, width: number, height: number, ox: number, oy: number) {
12
- this.img = parent.image;
13
- this.rev = parent.image.revision();
10
+ constructor(parent: Sprite, width: Fx8, height: Fx8, ox: Fx8, oy: Fx8) {
11
+ this.hash = parent.calcDimensionalHash();
14
12
  this.parent = parent;
15
- this.width = Fx8(width);
16
- this.height = Fx8(height);
17
- this.ox = Fx8(ox);
18
- this.oy = Fx8(oy);
13
+ this.width = width;
14
+ this.height = height;
15
+ this.ox = ox;
16
+ this.oy = oy;
19
17
  }
20
18
 
21
19
  get left() {
@@ -41,7 +39,23 @@ namespace game {
41
39
  }
42
40
 
43
41
  isValid() {
44
- return this.img === this.parent.image && this.rev === this.parent.image.revision();
42
+ return this.hash === this.parent.calcDimensionalHash();
43
+ }
44
+
45
+ contains(x: Fx8, y: Fx8): boolean {
46
+ return (x >= this.left) && (x <= this.right) && (y >= this.top) && (y <= this.bottom);
47
+ }
48
+
49
+ overlapsWith(other: Hitbox): boolean {
50
+ if (this.contains(other.left, other.top)) return true;
51
+ if (this.contains(other.left, other.bottom)) return true;
52
+ if (this.contains(other.right, other.top)) return true;
53
+ if (this.contains(other.right, other.bottom)) return true;
54
+ if (other.contains(this.left, this.top)) return true;
55
+ if (other.contains(this.left, this.bottom)) return true;
56
+ if (other.contains(this.right, this.top)) return true;
57
+ if (other.contains(this.right, this.bottom)) return true;
58
+ return false;
45
59
  }
46
60
  }
47
61
 
@@ -51,24 +65,28 @@ namespace game {
51
65
  return s._hitbox;
52
66
 
53
67
  const i = s.image;
54
- let minX = i.width;
55
- let minY = i.height;
56
- let maxX = 0;
57
- let maxY = 0;
68
+ let minX = Fx8(i.width);
69
+ let minY = Fx8(i.height);
70
+ let maxX = Fx.zeroFx8;
71
+ let maxY = Fx.zeroFx8;
58
72
 
59
- for (let c = 0; c < i.width; c++) {
60
- for (let r = 0; r < i.height; r++) {
73
+ for (let c = 0, fxc = Fx.zeroFx8; c < i.width; c++, fxc = Fx.add(fxc, Fx.oneFx8)) {
74
+ for (let r = 0, fxr = Fx.zeroFx8; r < i.height; r++, fxr = Fx.add(fxr, Fx.oneFx8)) {
61
75
  if (i.getPixel(c, r)) {
62
- minX = Math.min(minX, c);
63
- minY = Math.min(minY, r);
64
- maxX = Math.max(maxX, c);
65
- maxY = Math.max(maxY, r);
76
+ minX = Fx.min(minX, fxc);
77
+ minY = Fx.min(minY, fxr);
78
+ maxX = Fx.max(maxX, fxc);
79
+ maxY = Fx.max(maxY, fxr);
66
80
  }
67
81
  }
68
82
  }
69
83
 
70
- const width = maxX - minX + 1;
71
- const height = maxY - minY + 1;
84
+ minX = Fx.mul(minX, s._sx);
85
+ minY = Fx.mul(minY, s._sy);
86
+ maxX = Fx.mul(maxX, s._sx);
87
+ maxY = Fx.mul(maxY, s._sy);
88
+ const width = Fx.add(Fx.sub(maxX, minX), Fx.oneFx8);
89
+ const height = Fx.add(Fx.sub(maxY, minY), Fx.oneFx8);
72
90
 
73
91
  return new Hitbox(s, width, height, minX, minY);
74
92
  }
@@ -61,6 +61,8 @@ namespace sprites {
61
61
  }
62
62
 
63
63
  calculatePartialHeight(startLine: number, lengthToDraw: number) {
64
+ if (this.linebreaks.length === 0) return this.font.charHeight;
65
+
64
66
  let current = 0;
65
67
 
66
68
  for (let i = startLine; i < this.linebreaks.length + 1; i++) {
@@ -93,9 +95,9 @@ namespace sprites {
93
95
  return total;
94
96
  }
95
97
 
96
- protected lineEnd(index: number) {
97
- const prevEnd = index > 0 ? this.linebreaks[index - 1] : 0;
98
- let end = index < this.linebreaks.length ? this.linebreaks[index] : this.text.length;
98
+ lineEnd(lineIndex: number) {
99
+ const prevEnd = lineIndex > 0 ? this.linebreaks[lineIndex - 1] : 0;
100
+ let end = lineIndex < this.linebreaks.length ? this.linebreaks[lineIndex] : this.text.length;
99
101
  let didMove = false;
100
102
 
101
103
  // Trim trailing whitespace
@@ -115,8 +117,8 @@ namespace sprites {
115
117
  return didMove ? end + 1 : end;
116
118
  }
117
119
 
118
- protected lineStart(index: number) {
119
- let start = index > 0 ? this.linebreaks[index - 1] : 0;
120
+ lineStart(lineIndex: number) {
121
+ let start = lineIndex > 0 ? this.linebreaks[lineIndex - 1] : 0;
120
122
 
121
123
  // Trim leading whitespace
122
124
  while (start < this.text.length) {
@@ -133,6 +135,29 @@ namespace sprites {
133
135
 
134
136
  return start;
135
137
  }
138
+
139
+ widthOfLine(lineIndex: number, fullTextOffset?: number) {
140
+ if (fullTextOffset != undefined) {
141
+ return (Math.min(this.lineEnd(lineIndex), fullTextOffset + 1) - this.lineStart(lineIndex)) * this.font.charWidth;
142
+ }
143
+ return (this.lineEnd(lineIndex) - this.lineStart(lineIndex)) * this.font.charWidth;
144
+ }
145
+
146
+ widthOfLines(lineStartIndex: number, lineEndIndex: number, offset?: number) {
147
+ if (this.linebreaks.length === 0) return this.widthOfLine(0, offset);
148
+
149
+ let width = 0;
150
+ let fullTextOffset: number;
151
+ for (let i = lineStartIndex; i < Math.min(lineEndIndex, this.linebreaks.length + 1); i++) {
152
+ if (offset != undefined) {
153
+ fullTextOffset = this.lineStart(i) + offset;
154
+ offset -= this.lineEnd(i) - this.lineStart(i);
155
+ }
156
+ if (fullTextOffset !== undefined && this.lineStart(i) > fullTextOffset) break;
157
+ width = Math.max(width, this.widthOfLine(i, fullTextOffset));
158
+ }
159
+ return width;
160
+ }
136
161
  }
137
162
 
138
163
 
@@ -203,6 +228,9 @@ namespace sprites {
203
228
  protected pageLine: number;
204
229
  protected timer: number;
205
230
  protected pauseMillis: number;
231
+ protected onTickCB: () => void;
232
+ protected onEndCB: () => void;
233
+ protected prevOffset: number;
206
234
 
207
235
  constructor(public text: RenderText, public height: number) {
208
236
  this.state = RenderTextAnimationState.Idle;
@@ -232,17 +260,21 @@ namespace sprites {
232
260
  }
233
261
 
234
262
  currentHeight() {
235
- const maxHeight = Math.min(
236
- Math.idiv(this.height, this.text.lineHeight()) + 1,
237
- this.text.linebreaks.length + 1 - this.pageLine
238
- ) * this.text.lineHeight();
263
+ const minHeight = this.text.lineHeight();
264
+ const maxHeight = Math.max(
265
+ Math.min(
266
+ Math.idiv(this.height, this.text.lineHeight()) + 1,
267
+ this.text.linebreaks.length + 1 - this.pageLine
268
+ ) * this.text.lineHeight(),
269
+ minHeight
270
+ );
239
271
 
240
272
 
241
273
  if (this.state === RenderTextAnimationState.Printing) {
242
- return Math.min(
274
+ return Math.max(Math.min(
243
275
  this.text.calculatePartialHeight(this.pageLine, this.currentOffset()),
244
276
  maxHeight
245
- );
277
+ ), minHeight)
246
278
  }
247
279
  else if (this.state === RenderTextAnimationState.Pausing) {
248
280
  return maxHeight
@@ -252,10 +284,34 @@ namespace sprites {
252
284
  }
253
285
  }
254
286
 
287
+ currentWidth() {
288
+ return this.text.widthOfLines(
289
+ this.pageLine,
290
+ this.pageLine + Math.idiv(this.currentHeight(), this.text.lineHeight()) + 1,
291
+ this.state === RenderTextAnimationState.Printing ? this.currentOffset() : undefined
292
+ );
293
+ }
294
+
255
295
  currentOffset() {
256
296
  return Math.idiv(control.millis() - this.timer, this.tickPeriod)
257
297
  }
258
298
 
299
+ isDone() {
300
+ return this.state === RenderTextAnimationState.Idle;
301
+ }
302
+
303
+ cancel() {
304
+ this.state = RenderTextAnimationState.Idle;
305
+ }
306
+
307
+ onCharacterPrinted(cb: () => void) {
308
+ this.onTickCB = cb;
309
+ }
310
+
311
+ onAnimationEnd(cb: () => void) {
312
+ this.onEndCB = cb;
313
+ }
314
+
259
315
  draw(canvas: Image, left: number, top: number, color: number) {
260
316
  if (this.state === RenderTextAnimationState.Idle) return;
261
317
  else if (this.state === RenderTextAnimationState.Printing) {
@@ -269,6 +325,10 @@ namespace sprites {
269
325
  this.pageLine + Math.idiv(this.height, this.text.lineHeight()) + 1
270
326
  );
271
327
 
328
+ if (this.onTickCB && this.prevOffset !== this.currentOffset()) {
329
+ this.onTickCB();
330
+ }
331
+
272
332
  if (pageFinished) {
273
333
  this.state = RenderTextAnimationState.Pausing;
274
334
  this.timer = this.pauseMillis
@@ -290,6 +350,7 @@ namespace sprites {
290
350
  this.pageLine += Math.idiv(this.height, this.text.lineHeight()) + 1;
291
351
  if (this.pageLine > this.text.linebreaks.length) {
292
352
  this.state = RenderTextAnimationState.Idle;
353
+ if (this.onEndCB) this.onEndCB();
293
354
  }
294
355
  else {
295
356
  this.state = RenderTextAnimationState.Printing;
@@ -297,6 +358,8 @@ namespace sprites {
297
358
  }
298
359
  }
299
360
  }
361
+
362
+ this.prevOffset = this.currentOffset();
300
363
  }
301
364
  }
302
365
  }
@@ -58,6 +58,36 @@ enum FlipOption {
58
58
  FlipXY
59
59
  }
60
60
 
61
+ enum ScaleDirection {
62
+ //% block="vertically"
63
+ Vertically = 0x01,
64
+ //% block="horizontally"
65
+ Horizontally = 0x02,
66
+ //% block="uniformly"
67
+ Uniformly = Vertically | Horizontally,
68
+ }
69
+
70
+ enum ScaleAnchor {
71
+ //% block="middle"
72
+ Middle = 0,
73
+ //% block="top"
74
+ Top = 0x01,
75
+ //% block="left"
76
+ Left = 0x02,
77
+ //% block="right"
78
+ Right = 0x04,
79
+ //% block="bottom"
80
+ Bottom = 0x08,
81
+ //% block="top left"
82
+ TopLeft = Top | Left,
83
+ //% block="top right"
84
+ TopRight = Top | Right,
85
+ //% block="bottom left"
86
+ BottomLeft = Bottom | Left,
87
+ //% block="bottom right"
88
+ BottomRight = Bottom | Right,
89
+ }
90
+
61
91
  /**
62
92
  * A sprite on the screen
63
93
  **/
@@ -71,27 +101,31 @@ class Sprite extends sprites.BaseSprite {
71
101
  _ay: Fx8
72
102
  _fx: Fx8 // friction
73
103
  _fy: Fx8 // friction
104
+ _sx: Fx8 // scale
105
+ _sy: Fx8 // scale
106
+ _width: Fx8 // scaled width
107
+ _height: Fx8 // scaled height
74
108
 
75
109
  //% group="Physics" blockSetVariable="mySprite"
76
110
  //% blockCombine block="x" callInDebugger
77
111
  get x(): number {
78
- return Fx.toFloat(this._x) + (this._image.width / 2)
112
+ return Fx.toFloat(Fx.add(this._x, Fx.div(this._width, Fx.twoFx8)));
79
113
  }
80
114
  //% group="Physics" blockSetVariable="mySprite"
81
115
  //% blockCombine block="x"
82
116
  set x(v: number) {
83
- this.left = v - (this._image.width / 2)
117
+ this.left = v - (this.width / 2)
84
118
  }
85
119
 
86
120
  //% group="Physics" blockSetVariable="mySprite"
87
121
  //% blockCombine block="y" callInDebugger
88
122
  get y(): number {
89
- return Fx.toFloat(this._y) + (this._image.height / 2)
123
+ return Fx.toFloat(Fx.add(this._y, Fx.div(this._height, Fx.twoFx8)));
90
124
  }
91
125
  //% group="Physics" blockSetVariable="mySprite"
92
126
  //% blockCombine block="y"
93
127
  set y(v: number) {
94
- this.top = v - (this._image.height / 2)
128
+ this.top = v - (this.height / 2)
95
129
  }
96
130
 
97
131
  //% group="Physics" blockSetVariable="mySprite"
@@ -158,6 +192,42 @@ class Sprite extends sprites.BaseSprite {
158
192
  set fy(v: number) {
159
193
  this._fy = Fx8(Math.max(0, v))
160
194
  }
195
+ //% group="Physics" blockSetVariable="mySprite"
196
+ //% blockCombine block="sx (scale x)" callInDebugger
197
+ get sx(): number {
198
+ return Fx.toFloat(this._sx);
199
+ }
200
+ //% group="Physics" blockSetVariable="mySprite"
201
+ //% blockCombine block="sx (scale x)"
202
+ set sx(v: number) {
203
+ const x = this.x;
204
+ this._sx = Fx8(Math.max(0, v));
205
+ this.recalcSize();
206
+ this.left = x - this.width / 2;
207
+ }
208
+ //% group="Physics" blockSetVariable="mySprite"
209
+ //% blockCombine block="sy (scale y)" callInDebugger
210
+ get sy(): number {
211
+ return Fx.toFloat(this._sy);
212
+ }
213
+ //% group="Physics" blockSetVariable="mySprite"
214
+ //% blockCombine block="sy (scale y)"
215
+ set sy(v: number) {
216
+ const y = this.y;
217
+ this._sy = Fx8(Math.max(0, v));
218
+ this.recalcSize();
219
+ this.top = y - this.height / 2;
220
+ }
221
+ //% group="Physics" blockSetVariable="mySprite"
222
+ //% blockCombine block="scale" callInDebugger
223
+ get scale(): number {
224
+ return Math.max(this.sx, this.sy);
225
+ }
226
+ //% group="Physics" blockSetVariable="mySprite"
227
+ //% blockCombine block="scale"
228
+ set scale(v: number) {
229
+ this.sx = this.sy = v;
230
+ }
161
231
 
162
232
  private _data: any;
163
233
  /**
@@ -219,6 +289,8 @@ class Sprite extends sprites.BaseSprite {
219
289
  this.ay = 0
220
290
  this.fx = 0
221
291
  this.fy = 0
292
+ this._sx = Fx.oneFx8;
293
+ this._sy = Fx.oneFx8;
222
294
  this.flags = 0
223
295
  this.setImage(img);
224
296
  this.setKind(-1); // not a member of any type by default
@@ -229,7 +301,7 @@ class Sprite extends sprites.BaseSprite {
229
301
  }
230
302
 
231
303
  __serialize(offset: number): Buffer {
232
- const buf = control.createBuffer(offset + 12);
304
+ const buf = control.createBuffer(offset + 16);
233
305
  let k = offset;
234
306
  buf.setNumber(NumberFormat.Int16LE, k, Fx.toInt(this._x)); k += 2;
235
307
  buf.setNumber(NumberFormat.Int16LE, k, Fx.toInt(this._y)); k += 2;
@@ -237,6 +309,8 @@ class Sprite extends sprites.BaseSprite {
237
309
  buf.setNumber(NumberFormat.Int16LE, k, Fx.toInt(this._vy)); k += 2;
238
310
  buf.setNumber(NumberFormat.Int16LE, k, Fx.toInt(this._ax)); k += 2;
239
311
  buf.setNumber(NumberFormat.Int16LE, k, Fx.toInt(this._ay)); k += 2;
312
+ buf.setNumber(NumberFormat.Int16LE, k, Fx.toInt(this._sx)); k += 2;
313
+ buf.setNumber(NumberFormat.Int16LE, k, Fx.toInt(this._sy)); k += 2;
240
314
  return buf;
241
315
  }
242
316
 
@@ -257,8 +331,17 @@ class Sprite extends sprites.BaseSprite {
257
331
  //% blockId=spritesetimage block="set %sprite(mySprite) image to %img=screen_image_picker"
258
332
  //% weight=7 help=sprites/sprite/set-image
259
333
  setImage(img: Image) {
260
- if (!img) return; // don't break the sprite
334
+ if (!img || img === this._image) return;
261
335
  this._image = img;
336
+ this.recalcSize();
337
+ }
338
+
339
+ calcDimensionalHash() {
340
+ return Fx.mul(Fx.mul(this._width, this._height), Fx8(this._image.revision()));
341
+ }
342
+
343
+ resetHitbox() {
344
+ this._hitbox = null;
262
345
  this.setHitbox();
263
346
  }
264
347
 
@@ -311,19 +394,29 @@ class Sprite extends sprites.BaseSprite {
311
394
  return !(this.flags & SpriteFlag.Invisible);
312
395
  }
313
396
 
397
+ private recalcSize(): void {
398
+ this._width = Fx8(this._image.width * this.sx);
399
+ this._height = Fx8(this._image.height * this.sy);
400
+ this.resetHitbox();
401
+ }
402
+
403
+ private isScaled(): boolean {
404
+ return this._sx !== Fx.oneFx8 || this._sy !== Fx.oneFx8;
405
+ }
406
+
314
407
  //% group="Physics" blockSetVariable="mySprite"
315
- //% blockCombine block="width"
408
+ //% blockCombine block="width" callInDebugger
316
409
  get width() {
317
- return this._image.width
410
+ return Fx.toInt(this._width);
318
411
  }
319
412
  //% group="Physics" blockSetVariable="mySprite"
320
- //% blockCombine block="height"
413
+ //% blockCombine block="height" callInDebugger
321
414
  get height() {
322
- return this._image.height
415
+ return Fx.toInt(this._height);
323
416
  }
324
417
 
325
418
  //% group="Physics" blockSetVariable="mySprite"
326
- //% blockCombine block="left"
419
+ //% blockCombine block="left" callInDebugger
327
420
  get left() {
328
421
  return Fx.toFloat(this._x)
329
422
  }
@@ -342,7 +435,7 @@ class Sprite extends sprites.BaseSprite {
342
435
  }
343
436
 
344
437
  //% group="Physics" blockSetVariable="mySprite"
345
- //% blockCombine block="right"
438
+ //% blockCombine block="right" callInDebugger
346
439
  get right() {
347
440
  return this.left + this.width
348
441
  }
@@ -353,7 +446,7 @@ class Sprite extends sprites.BaseSprite {
353
446
  }
354
447
 
355
448
  //% group="Physics" blockSetVariable="mySprite"
356
- //% blockCombine block="top"
449
+ //% blockCombine block="top" callInDebugger
357
450
  get top() {
358
451
  return Fx.toFloat(this._y);
359
452
  }
@@ -372,7 +465,7 @@ class Sprite extends sprites.BaseSprite {
372
465
  }
373
466
 
374
467
  //% group="Physics" blockSetVariable="mySprite"
375
- //% blockCombine block="bottom"
468
+ //% blockCombine block="bottom" callInDebugger
376
469
  get bottom() {
377
470
  return this.top + this.height;
378
471
  }
@@ -576,7 +669,19 @@ class Sprite extends sprites.BaseSprite {
576
669
  const l = Math.floor(this.left - ox);
577
670
  const t = Math.floor(this.top - oy);
578
671
 
579
- screen.drawTransparentImage(this._image, l, t)
672
+ if (!this.isScaled())
673
+ screen.drawTransparentImage(this._image, l, t);
674
+ else
675
+ screen.blit(
676
+ // dst rect in screen
677
+ l, t,
678
+ this.width,
679
+ this.height,
680
+ // src rect in sprite image
681
+ this._image,
682
+ 0, 0,
683
+ this._image.width, this._image.height,
684
+ true, false);
580
685
 
581
686
  if (this.flags & SpriteFlag.ShowPhysics) {
582
687
  const font = image.font5;
@@ -697,7 +802,46 @@ class Sprite extends sprites.BaseSprite {
697
802
  return false
698
803
  if (other.flags & SPRITE_NO_SPRITE_OVERLAPS)
699
804
  return false
700
- return other._image.overlapsWith(this._image, this.left - other.left, this.top - other.top)
805
+ if (!other._hitbox.overlapsWith(this._hitbox))
806
+ return false;
807
+ if (!this.isScaled() && !other.isScaled()) {
808
+ return other._image.overlapsWith(
809
+ this._image,
810
+ this.left - other.left,
811
+ this.top - other.top)
812
+ } else {
813
+ if (this.sx == 0 || this.sy == 0 || other.sx == 0 || other.sy == 0) return false;
814
+
815
+ let A: Sprite;
816
+ let B: Sprite;
817
+
818
+ // Render larger-scaled sprite onto smaller-scaled one so that we don't
819
+ // skip over source pixels in the check.
820
+
821
+ // A is the smaller-scaled sprite
822
+ if (this.sx * this.sy < other.sx * other.sy) {
823
+ A = this;
824
+ B = other;
825
+ } else {
826
+ A = other;
827
+ B = this;
828
+ }
829
+
830
+ // Render B onto A
831
+ return helpers.imageBlit(
832
+ A.image,
833
+ // Dst rect in A
834
+ (B.left - A.left) / A.sx,
835
+ (B.top - A.top) / A.sy,
836
+ B.width / A.sx,
837
+ B.height / A.sy,
838
+ B.image,
839
+ // Src rect in B
840
+ 0, 0,
841
+ B.image.width,
842
+ B.image.height,
843
+ true, true);
844
+ }
701
845
  }
702
846
 
703
847
  /**
@@ -939,6 +1083,90 @@ class Sprite extends sprites.BaseSprite {
939
1083
  }
940
1084
  }
941
1085
 
1086
+ setScaleCore(sx?: number, sy?: number, anchor?: ScaleAnchor, proportional?: boolean): void {
1087
+ anchor = anchor || ScaleAnchor.Middle;
1088
+
1089
+ const hasSx = sx != null;
1090
+ const hasSy = sy != null;
1091
+
1092
+ const oldW = this.width;
1093
+ const oldH = this.height;
1094
+
1095
+ if (hasSx) {
1096
+ const oldSx = this.sx;
1097
+ this.sx = sx;
1098
+ if (!hasSy && proportional) {
1099
+ const ratio = sx / oldSx;
1100
+ this.sy *= ratio;
1101
+ }
1102
+ }
1103
+ if (hasSy) {
1104
+ const oldSy = this.sy;
1105
+ this.sy = sy;
1106
+ if (!hasSx && proportional) {
1107
+ const ratio = sy / oldSy;
1108
+ this.sx *= ratio;
1109
+ }
1110
+ }
1111
+
1112
+ if (anchor & (ScaleAnchor.Left | ScaleAnchor.Right)) {
1113
+ const newW = this.width;
1114
+ const diff = newW - oldW;
1115
+ const diffOver2 = (diff / 2) | 0;
1116
+ if (anchor & ScaleAnchor.Left) { this.x += diffOver2; }
1117
+ if (anchor & ScaleAnchor.Right) { this.x -= diffOver2; }
1118
+ }
1119
+ if (anchor & (ScaleAnchor.Top | ScaleAnchor.Bottom)) {
1120
+ const newH = this.height;
1121
+ const diff = newH - oldH;
1122
+ const diffOver2 = (diff / 2) | 0;
1123
+ if (anchor & ScaleAnchor.Top) { this.y += diffOver2; }
1124
+ if (anchor & ScaleAnchor.Bottom) { this.y -= diffOver2; }
1125
+ }
1126
+ }
1127
+
1128
+ //% blockId=sprite_set_scale
1129
+ //% block="set %sprite(mySprite) scale to $value anchor $anchor"
1130
+ //% expandableArgumentMode=enabled
1131
+ //% inlineInputMode=inline
1132
+ //% value.defl=1
1133
+ //% anchor.defl=ScaleAnchor.Middle
1134
+ //% help=sprites/sprite/set-scale
1135
+ //% group="Scale" weight=90
1136
+ setScale(value: number, anchor?: ScaleAnchor): void {
1137
+ const direction = ScaleDirection.Uniformly;
1138
+ anchor = anchor || ScaleAnchor.Middle;
1139
+
1140
+ let sx: number;
1141
+ let sy: number;
1142
+
1143
+ if (direction & ScaleDirection.Horizontally) sx = value;
1144
+ if (direction & ScaleDirection.Vertically) sy = value;
1145
+
1146
+ this.setScaleCore(sx, sy, anchor);
1147
+ }
1148
+
1149
+ //% blockId=sprite_change_scale
1150
+ //% block="change %sprite(mySprite) scale by $value anchor $anchor"
1151
+ //% expandableArgumentMode=enabled
1152
+ //% inlineInputMode=inline
1153
+ //% value.defl=1
1154
+ //% anchor.defl=ScaleAnchor.Middle
1155
+ //% help=sprites/sprite/change-scale
1156
+ //% group="Scale" weight=90
1157
+ changeScale(value: number, anchor?: ScaleAnchor): void {
1158
+ const direction = ScaleDirection.Uniformly;
1159
+ anchor = anchor || ScaleAnchor.Middle;
1160
+
1161
+ let sx: number;
1162
+ let sy: number;
1163
+
1164
+ if (direction & ScaleDirection.Horizontally) sx = this.sx + value;
1165
+ if (direction & ScaleDirection.Vertically) sy = this.sy + value;
1166
+
1167
+ this.setScaleCore(sx, sy, anchor);
1168
+ }
1169
+
942
1170
  toString() {
943
1171
  return `${this.id}(${this.x},${this.y})->(${this.vx},${this.vy})`;
944
1172
  }