pxt-arcade 1.12.2 → 1.12.4

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 (103) hide show
  1. package/built/common-sim.d.ts +2 -2
  2. package/built/target.js +158 -146
  3. package/built/target.json +158 -146
  4. package/built/targetlight.json +5 -5
  5. package/built/theme.json +5 -0
  6. package/docs/SUMMARY.md +1 -0
  7. package/docs/hardware/adding.md +46 -52
  8. package/docs/hero-banner.md +8 -8
  9. package/docs/hour-of-code-2022-es.html +0 -1
  10. package/docs/hour-of-code-2022-pt.html +0 -1
  11. package/docs/hour-of-code-2022.html +12 -13
  12. package/docs/index-ref.json +1 -1
  13. package/docs/kiosk.html +1 -1
  14. package/docs/multiplayer.md +135 -0
  15. package/docs/projects/SUMMARY.md +3 -1
  16. package/docs/skillmap/balloon/balloon1.md +26 -312
  17. package/docs/skillmap/balloon/balloon2.md +18 -315
  18. package/docs/skillmap/balloon/balloon3.md +18 -317
  19. package/docs/skillmap/balloon/balloon4.md +105 -583
  20. package/docs/skillmap/balloon.md +14 -13
  21. package/docs/skillmap/mole/mole1.md +51 -326
  22. package/docs/skillmap/mole/mole2.md +43 -332
  23. package/docs/skillmap/mole/mole3.md +47 -316
  24. package/docs/{test/skillmap → skillmap}/mole/mole4.md +0 -0
  25. package/docs/skillmap/mole.md +14 -4
  26. package/docs/skillmap/turkey/turkey1.md +194 -127
  27. package/docs/skillmap/turkey/turkey2.md +144 -96
  28. package/docs/skillmap/turkey/turkey3.md +135 -84
  29. package/docs/skillmap/turkey.md +12 -10
  30. package/docs/skillmaps.md +24 -8
  31. package/docs/static/hero-gallery/holiday.png +0 -0
  32. package/docs/static/kiosk/asset-manifest.json +6 -6
  33. package/docs/static/kiosk/static/css/main.b60591be.css +2 -0
  34. package/docs/static/kiosk/static/css/main.b60591be.css.map +1 -0
  35. package/docs/static/kiosk/static/js/main.7c9f0b91.js +3 -0
  36. package/docs/static/kiosk/static/js/{main.01c7792a.js.LICENSE.txt → main.7c9f0b91.js.LICENSE.txt} +12 -32
  37. package/docs/static/kiosk/static/js/main.7c9f0b91.js.map +1 -0
  38. package/docs/static/multiplayer/help/emojis.png +0 -0
  39. package/docs/static/multiplayer/help/host-multiplayer.png +0 -0
  40. package/docs/static/multiplayer/help/hosted-game.png +0 -0
  41. package/docs/static/multiplayer/help/join-game.png +0 -0
  42. package/docs/static/multiplayer/help/joined-game.png +0 -0
  43. package/docs/static/multiplayer/help/share-button.png +0 -0
  44. package/docs/static/multiplayer/help/start-game.png +0 -0
  45. package/docs/static/skillmap/assets/dkc-logo-small.png +0 -0
  46. package/docs/static/tutorials/aliens/reload.png +0 -0
  47. package/docs/static/tutorials/arrows/2pbg.png +0 -0
  48. package/docs/static/tutorials/arrows/key.png +0 -0
  49. package/docs/static/tutorials/arrows/p1.png +0 -0
  50. package/docs/static/tutorials/arrows/p2.png +0 -0
  51. package/docs/static/tutorials/holiday/bgd.png +0 -0
  52. package/docs/static/tutorials/holiday/p1.png +0 -0
  53. package/docs/static/tutorials/holiday/p2.png +0 -0
  54. package/docs/static/tutorials/horse/finish.png +0 -0
  55. package/docs/static/tutorials/horse/frame.png +0 -0
  56. package/docs/static/tutorials/horse/p1.png +0 -0
  57. package/docs/static/tutorials/horse/p2.png +0 -0
  58. package/docs/test/courses/carnival.md +57 -0
  59. package/docs/test/courses/class-arcade.md +57 -0
  60. package/docs/test/skillmap/balloon.md +1 -1
  61. package/docs/test/skillmap/dino/{collectort1.md → dino1.md} +135 -79
  62. package/docs/test/skillmap/dino/{collectort2.md → dino2.md} +0 -0
  63. package/docs/test/skillmap/dino/{collectort3.md → dino3.md} +0 -0
  64. package/docs/test/skillmap/dino/{collectort4.md → dino4.md} +0 -0
  65. package/docs/test/skillmap/dino/{collectort5.md → dino5.md} +0 -0
  66. package/docs/test/skillmap/dino.md +82 -0
  67. package/docs/test/skillmap/mole.md +1 -1
  68. package/docs/test/skillmap/story/story1.md +8 -21
  69. package/docs/test/skillmap/story/story2.md +17 -28
  70. package/docs/test/skillmap/story/story3.md +51 -469
  71. package/docs/test/skillmap/story/story4.md +1 -2
  72. package/docs/test/skillmap/turkey.md +1 -0
  73. package/docs/test/tutorials/arrow.md +677 -0
  74. package/docs/test/tutorials/debug.md +180 -0
  75. package/docs/test/tutorials/holiday.md +609 -0
  76. package/docs/test/tutorials/horse.md +456 -0
  77. package/docs/test/tutorials/hundred.md +400 -0
  78. package/docs/test/tutorials/target.md +6 -2
  79. package/docs/test/tutorials/wakanda-forever.md +206 -147
  80. package/docs/tutorials/arrow.md +677 -0
  81. package/docs/tutorials/holiday.md +609 -0
  82. package/docs/tutorials/horse.md +456 -0
  83. package/docs/{test/tutorials/target/target_copy.md → tutorials/target.md} +11 -1085
  84. package/docs/tutorials/wakanda-forever.md +206 -147
  85. package/package.json +3 -3
  86. package/docs/skillmap/turkey/turkey0.md +0 -197
  87. package/docs/skillmap/turkey/turkey1a.md +0 -308
  88. package/docs/skillmap/turkey/turkey2a.md +0 -277
  89. package/docs/skillmap/turkey/turkey3a.md +0 -219
  90. package/docs/static/kiosk/static/css/main.927f4dad.css +0 -2
  91. package/docs/static/kiosk/static/css/main.927f4dad.css.map +0 -1
  92. package/docs/static/kiosk/static/js/main.01c7792a.js +0 -3
  93. package/docs/static/kiosk/static/js/main.01c7792a.js.map +0 -1
  94. package/docs/test/skillmap/balloon/balloon1.md +0 -247
  95. package/docs/test/skillmap/balloon/balloon2.md +0 -377
  96. package/docs/test/skillmap/balloon/balloon3.md +0 -389
  97. package/docs/test/skillmap/balloon/balloon4.md +0 -385
  98. package/docs/test/skillmap/mole/mole1.md +0 -382
  99. package/docs/test/skillmap/mole/mole2.md +0 -422
  100. package/docs/test/skillmap/mole/mole3.md +0 -384
  101. package/docs/test/skillmap/turkey/turkey1.md +0 -338
  102. package/docs/test/skillmap/turkey/turkey2.md +0 -318
  103. package/docs/test/skillmap/turkey/turkey3.md +0 -265
@@ -6,6 +6,8 @@
6
6
 
7
7
  ![Make your own Target Practice Game](/static/skillmap/target/target3.gif "This is what we'll be making today.")
8
8
 
9
+ Special thanks to *Lucas_M* for creating the original Target Practice game!
10
+
9
11
 
10
12
 
11
13
  ## {2. Read Instructions}
@@ -15,86 +17,33 @@
15
17
 
16
18
  This video will show you what to do.
17
19
 
18
- Watch the video and follow along!
20
+ Feel free to pause or restart the video as often as you need!
21
+
22
+ Click "Pop out video" to resize the video window or move it around the screen.
19
23
 
20
- ![Balloon Bursting Carnival Intro](youtube:ttlam7rkh1U)
24
+ ![Balloon Bursting Carnival Intro](azuremedia:2593255d-ab7a-49e1-99b2-bbf59af49d97/Target-Practice.ism?start=29)
21
25
 
22
26
 
23
27
 
24
28
  ```package
25
29
  simple-blocks=github:microsoft/arcade-tutorial-extensions/simple-blocks/
26
- arcade-text=github:microsoft/arcade-text/
27
- pxt-sprite-scaling=github:microsoft/pxt-common-packages/libs/sprite-scaling/
30
+ carnival=github:microsoft/arcade-carnival
28
31
  ```
29
32
 
30
33
 
31
- ```template
32
-
33
- controller.up.onEvent(ControllerButtonEvent.Pressed, function () {
34
- carnival.startTimer()
35
- })
36
- // game.onGameOverExpanded(winTypes.Multi)
37
- controller.B.onEvent(ControllerButtonEvent.Pressed, function () {
38
- info.player2.setScore(0)
39
- info.player1.setScore(10)
40
- // game.onGameOverExpanded(winTypes.Timed)
41
- carnival.customGameOverExpanded("Spooky!", effects.confetti, music.magicWand, scoreTypes.HTime, 0)
42
- })
43
- controller.A.onEvent(ControllerButtonEvent.Pressed, function () {
44
- throwBall = carnival.createProjectileBallFromSprite(assets.image`ball-blue`, myBall)
45
- })
46
- sprites.onOverlap(SpriteKind.Projectile, SpriteKind.Booth, function (sprite, otherSprite) {
47
- info.changeScoreBy(-1)
48
- sprite.destroy()
49
- })
50
- sprites.onOverlap(SpriteKind.Projectile, SpriteKind.Enemy, function (sprite, otherSprite) {
51
- otherSprite.destroy()
52
- sprite.destroy()
53
- info.changeScoreBy(1)
54
- music.baDing.play()
55
- })
56
- let theTarget: Sprite = null
57
- let throwBall: Ball = null
58
- let myBall: Ball = null
59
- scene.setBackgroundImage(assets.image`wildWest`)
60
- myBall = carnival.create(assets.image`ball-yellow`, SpriteKind.Player)
61
- myBall.setPosition(80, 90)
62
- let statusbar = statusbars.create(120, 6, StatusBarKind.Health)
63
- statusbar.setColor(5, 10)
64
- statusbar.setBarBorder(1, 1)
65
- statusbar.setPosition(80, 113)
66
- let myBooth = sprites.create(assets.image`booth`, SpriteKind.Booth)
67
- carnival.startTimer()
68
- myBall.controlBallWithArrowKeys(true)
69
- myBall.setIter(10)
70
- myBall.setTraceMulti(tracers.Cross)
71
- myBall.variablePower(
72
- statusbar,
73
- 30,
74
- 50,
75
- 100
76
- )
77
- forever(function () {
78
- theTarget = sprites.createProjectileFromSide(assets.image`target`, 50, 0)
79
- theTarget.bottom = 56
80
- theTarget.setKind(SpriteKind.Enemy)
81
- pause(randint(500, 2000))
82
- })
83
-
84
34
 
85
- ```
86
35
 
87
36
  ```ghost
88
37
 
89
38
  controller.up.onEvent(ControllerButtonEvent.Pressed, function () {
90
39
  carnival.startTimer()
91
40
  })
92
- // game.onGameOverExpanded(winTypes.Multi)
41
+ // game.onGameOverExpanded(carnival.WinTypes.Multi)
93
42
  controller.B.onEvent(ControllerButtonEvent.Pressed, function () {
94
43
  info.player2.setScore(0)
95
44
  info.player1.setScore(10)
96
- // game.onGameOverExpanded(winTypes.Timed)
97
- carnival.customGameOverExpanded("Spooky!", effects.confetti, music.magicWand, scoreTypes.HTime, 0)
45
+ // game.onGameOverExpanded(carnival.WinTypes.Timed)
46
+ carnival.customGameOverExpanded("Spooky!", effects.confetti, music.magicWand, carnival.ScoreTypes.HTime, 0)
98
47
  })
99
48
  controller.A.onEvent(ControllerButtonEvent.Pressed, function () {
100
49
  throwBall = carnival.createProjectileBallFromSprite(assets.image`ball-blue`, myBall)
@@ -123,7 +72,7 @@ let myBooth = sprites.create(assets.image`booth`, SpriteKind.Booth)
123
72
  carnival.startTimer()
124
73
  myBall.controlBallWithArrowKeys(true)
125
74
  myBall.setIter(10)
126
- myBall.setTraceMulti(tracers.Cross)
75
+ myBall.setTraceMulti(carnival.Tracers.Cross)
127
76
  myBall.variablePower(
128
77
  statusbar,
129
78
  30,
@@ -137,1029 +86,6 @@ forever(function () {
137
86
  pause(randint(500, 2000))
138
87
  })
139
88
 
140
-
141
-
142
- ```
143
-
144
-
145
- ```customts
146
-
147
-
148
-
149
- namespace SpriteKind {
150
- //% isKind
151
- export const Ball = SpriteKind.create()
152
- //% isKind
153
- export const Booth = SpriteKind.create()
154
- //% isKind
155
- export const Mouse = SpriteKind.create()
156
- //% isKind
157
- export const Crosshair = SpriteKind.create()
158
- //% isKind
159
- export const Moon = SpriteKind.create()
160
- }
161
-
162
- enum winTypes {
163
- //% block="win game"
164
- Win,
165
- //% block="lose game"
166
- Lose,
167
- //% block="best score"
168
- Score,
169
- //% block="best time"
170
- Timed,
171
- //% block="multiplayer"
172
- Multi,
173
- //% block="custom" blockHidden
174
- Custom
175
- }
176
-
177
- enum scoreTypes {
178
- //% block="high score"
179
- HScore,
180
- //% block="low score"
181
- LScore,
182
- //% block="high time"
183
- HTime,
184
- //% block="low time"
185
- LTime,
186
- //% block="none"
187
- None
188
- }
189
-
190
- enum speeds {
191
- //% block="fast"
192
- Fast,
193
- //% block="medium"
194
- Med,
195
- //% block="slow"
196
- Slow
197
- }
198
-
199
- enum areas {
200
- //% block="top"
201
- Top,
202
- //% block="middle"
203
- Mid,
204
- //% block="bottom"
205
- Bottom
206
- }
207
-
208
- enum tracers {
209
- //% block="full"
210
- Full,
211
- //% block="partial"
212
- Part,
213
- //% block="pointer"
214
- Pointer,
215
- //% block="crosshair"
216
- Cross,
217
- //% block="off"
218
- Off
219
- }
220
-
221
- let textSprite: TextSprite = null
222
- //let fanfare: effects.BackgroundEffect = undefined;
223
- //let winStyle="winTypes.Score"
224
-
225
- // Get array of player info
226
- let players: info.PlayerInfo[];
227
-
228
-
229
-
230
- /**
231
- * An extension full of carnival goodness
232
- */
233
- //% weight=100 color=#b70082 icon="\uf54e"
234
- //% groups='["Ball", "Timer", "Countdown", "Game", "Scene"]'
235
- namespace carnival {
236
-
237
- /**
238
- * Adds text to the top, middle, or bottom
239
- * of screen as defined by games
240
- */
241
- //% group="Scene"
242
- //% blockId=add_label_to
243
- //% block="add label $myLabel to $myPosition of window || $myColor"
244
- //% myLabel.defl="Whack-the-Mole"
245
- //% myColor.shadow="colorindexpicker"
246
- //% myColor.defl=4
247
- //% myPosition.defl=areas.Bottom
248
- //% inlineInputMode=inline
249
- export function add_label_to(myLabel: string, myPosition: areas, myColor?: number) {
250
- if (myColor == undefined)
251
- myColor = 4;
252
-
253
- textSprite = textsprite.create(myLabel, 0, myColor)
254
- if (myPosition == areas.Bottom) textSprite.setPosition(80, 110);
255
- if (myPosition == areas.Mid) textSprite.setPosition(80, 50);
256
- if (myPosition == areas.Top) textSprite.setPosition(80, 20);
257
- }
258
-
259
-
260
-
261
- // Formerly of the Info Category -----
262
-
263
- let countdownInitialized = false;
264
- let countUpInitialized = false;
265
-
266
- class TimerState {
267
- public playerStates: info.PlayerState[];
268
- public visibilityFlag: number;
269
-
270
- //public timerElapsed: number;
271
- public bgColor: number;
272
- public borderColor: number;
273
- public fontColor: number;
274
-
275
- constructor() {
276
- this.visibilityFlag = info.Visibility.Hud;
277
- this.bgColor = screen.isMono ? 0 : 1;
278
- this.borderColor = screen.isMono ? 1 : 3;
279
- this.fontColor = screen.isMono ? 1 : 3;
280
- }
281
- }
282
-
283
- let timerState: TimerState = undefined;
284
-
285
- let timerStateStack: {
286
- state: TimerState,
287
- scene: scene.Scene
288
- }[];
289
-
290
-
291
- /**
292
- * Adds timer to game
293
- */
294
- //% color="#b70082"
295
- //% group="Timer"
296
- //% blockId=start_count_up_game
297
- //% block="start timer"
298
- //% inlineInputMode=inline
299
- export function startTimer() {
300
- control.timer1.reset();
301
- updateFlag(info.Visibility.Countdown, true);
302
- timerHUD();
303
-
304
- }
305
-
306
- /**
307
- * Set whether timer should be displayed
308
- * @param on if true, countdown is shown; otherwise, countdown is hidden
309
- */
310
- //% color="#b70082"
311
- //% group="Timer"
312
- //% blockId=show_timer
313
- //% block="show timer $on=toggleOnOff"
314
- //% inlineInputMode=inline
315
- export function showTimer(on: boolean) {
316
- updateFlag(info.Visibility.Countdown, on);
317
- }
318
-
319
- /**
320
- * Return the current value of the count-up timer
321
- */
322
- //% color="#b70082"
323
- //% group="Timer"
324
- //% blockId=get_timer
325
- //% block="timer value"
326
- //% inlineInputMode=inline
327
- export function getTimerValue():number {
328
- return control.timer1.millis();
329
- }
330
-
331
-
332
- function updateFlag(flag: info.Visibility, on: boolean) {
333
- timerHUD();
334
- if (on) timerState.visibilityFlag |= flag;
335
- else timerState.visibilityFlag = ~(~timerState.visibilityFlag | flag);
336
- }
337
-
338
- function drawTimer(millis: number) {
339
- if (millis < 0) millis = 0;
340
- millis |= 0;
341
-
342
- const font = image.font8;
343
- const smallFont = image.font5;
344
- const seconds = Math.idiv(millis, 1000);
345
- const width = font.charWidth * 5 - 2;
346
- let left = (screen.width >> 1) - (width >> 1) + 1;
347
- let color1 = timerState.fontColor;
348
- let color2 = timerState.bgColor;
349
-
350
- screen.fillRect(left - 3, 0, width + 6, font.charHeight + 3, timerState.borderColor)
351
- screen.fillRect(left - 2, 0, width + 4, font.charHeight + 2, color2)
352
-
353
- if (seconds < 60) {
354
- const top = 1;
355
- const remainder = Math.idiv(millis % 1000, 10);
356
-
357
- screen.print(formatDecimal(seconds) + ".", left, top, color1, font)
358
- const decimalLeft = left + 3 * font.charWidth;
359
- screen.print(formatDecimal(remainder), decimalLeft, top + 2, color1, smallFont)
360
- }
361
- else {
362
- const minutes = Math.idiv(seconds, 60);
363
- const remainder = seconds % 60;
364
- screen.print(formatDecimal(minutes) + ":" + formatDecimal(remainder), left, 1, color1, font);
365
- }
366
- }
367
-
368
- function formatDecimal(val: number) {
369
- val |= 0;
370
- if (val < 10) {
371
- return "0" + val;
372
- }
373
- return val.toString();
374
- }
375
-
376
- function timerHUD() {
377
- if (timerState) return;
378
-
379
- timerState = new TimerState();
380
-
381
- scene.createRenderable(
382
- scene.HUD_Z,
383
- () => {
384
-
385
- // show timer
386
- if (timerState.visibilityFlag & info.Visibility.Countdown) {
387
- const scene = game.currentScene();
388
- //const elapsed = scene.millis();
389
- const elapsed = control.timer1.millis();
390
- drawTimer(elapsed);
391
- let t = elapsed / 1000;
392
- if (t <= 0) {
393
- t = 0;
394
-
395
- }
396
- }
397
- }
398
- );
399
- }
400
-
401
-
402
-
403
- /**
404
- * Adds game end style to countdown
405
- */
406
- //% color="#b70082"
407
- //% group="Countdown"
408
- //% blockId=start_countdown_game
409
- //% block="start countdown $myTime (s) and game over $winType || effect $winEffect"
410
- //% myTime.defl=15
411
- //% winType.defl=winTypes.Score
412
- //% winEffect.defl=effects.confetti
413
- //% inlineInputMode=inline
414
- export function startCountdownGame(myTime: number, winType: winTypes, winEffect?: effects.BackgroundEffect) {
415
- if (!winType)
416
- winType = winTypes.Win;
417
- if (!winEffect && winType != winTypes.Lose) {
418
- winEffect = effects.confetti;
419
- }
420
- else { winEffect = effects.melt; }
421
-
422
- init(winType, winEffect);
423
- info.startCountdown(myTime);
424
-
425
- }
426
-
427
- function saveLowScore(newLow: number) {
428
- const curr = settings.readNumber("low-score")
429
- if (curr == undefined || newLow < curr){
430
- settings.writeNumber("low-score", newLow);
431
- }
432
- }
433
-
434
- // Get the last recorded low score
435
- function lowScore(): number {
436
- return settings.readNumber("low-score");
437
- }
438
-
439
-
440
- function newGameOver(winStyle: winTypes, fanfare: effects.BackgroundEffect, winSound?:music.Melody, scoreType?: scoreTypes, message?: string, customScore?: number) {
441
-
442
- // Prep default variables for different win types
443
- let winnerNumber = [1]; // Which players have the high scores?
444
- let thisBest = info.score(); // Who has the best score this round?
445
- let newBest = false; // Is thisBest the newBest for all games?
446
- let bestScore = info.highScore(); // What is the bestScore of all time?
447
-
448
- // Save number of seconds passed during game
449
- const thisScene = game.currentScene();
450
- //let timeElapsed = roundOff(thisScene.millis() / 1000, 2); //Can't get points to match timer perfectly
451
- let timeElapsed = Math.floor(thisScene.millis() / 1000);
452
-
453
- if (control.timer1.millis() >=0) {
454
- timeElapsed = Math.floor(control.timer1.millis() / 1000);
455
- // timeElapsed = roundOff(control.timer1.millis() / 1000, 2); //Can't get points to match timer perfectly
456
-
457
- }
458
-
459
- /*
460
- // Save all scores as relevant to the game.
461
- info.saveAllScores(); // This is throwing an error for some reason
462
- */
463
-
464
-
465
- // Initialize thisBest if customScore wasn't included
466
- if (customScore === undefined) {
467
- thisBest = info.player1.getState().score;
468
- }
469
-
470
- // Initialize the messaging / fanfare based on winStyle
471
- if (winStyle == winTypes.Custom) {
472
- if (!scoreType) { scoreType = scoreTypes.HScore;}
473
- if (!message) { message = "Game Over!"; }
474
- if (!fanfare) { fanfare = effects.confetti; }
475
-
476
-
477
- } else if (winStyle == winTypes.Win) {
478
- scoreType = scoreTypes.HScore;
479
- message = "You Win!";
480
- if (!fanfare) { fanfare = effects.confetti; }
481
-
482
- } else if (winStyle == winTypes.Score) {
483
- scoreType = scoreTypes.HScore;
484
- message = "Great Score!" ;
485
- if (!fanfare) { fanfare = effects.confetti; }
486
-
487
- } else if (winStyle == winTypes.Timed) {
488
- scoreType = scoreTypes.LTime;
489
- message = "Great Time!" ;
490
- if (!fanfare) { fanfare = effects.confetti; }
491
-
492
- } else if (winStyle == winTypes.Multi) {
493
- scoreType = scoreTypes.HScore;
494
- if (!fanfare) { fanfare = effects.confetti; }
495
-
496
- // Find winner of multiplayer
497
- const scoreInfo1 = info.player1.getState();
498
- const scoreInfo2 = info.player2.getState();
499
- const scoreInfo3 = info.player3.getState();
500
- const scoreInfo4 = info.player4.getState();
501
- const allScores = [scoreInfo1.score, scoreInfo2.score, scoreInfo3.score, scoreInfo4.score];
502
-
503
-
504
- // Find player with highest score in Multi
505
- thisBest = -Infinity; // Make sure there's no false tie
506
- for (let i = 0; i < 4; i++) {
507
- if (allScores[i] != undefined && allScores[i] > thisBest) {
508
- thisBest = allScores[i];
509
- winnerNumber = [i+1];
510
- } else if (allScores[i] != undefined && allScores[i] == thisBest) {
511
- winnerNumber.push(i + 1);
512
- }
513
- }
514
-
515
- // Construct string for one winner
516
- if (!message && winnerNumber.length <= 1) {
517
- message = "Player " + winnerNumber[0] + " Wins!" ;
518
- } else {
519
- //Construct string for ties
520
- message = "Players ";
521
-
522
- for (let i = 0; i < ((winnerNumber.length)-1); i++) {
523
- message += winnerNumber[i] + " & ";
524
- }
525
-
526
- // remove the last ampersand and the trailing space
527
- message += winnerNumber[(winnerNumber.length) - 1] + " Tied!";
528
- }
529
-
530
- } else {
531
- if (!scoreType) { scoreType = scoreTypes.None;}
532
- if (!message) { message = "Game Over!"; }
533
- if (!fanfare) { fanfare = effects.melt; }
534
- }
535
-
536
- // Overwrite current game score if something was passed in
537
- if (customScore != undefined) {
538
- thisBest = customScore;
539
- }
540
-
541
- // Set bestScore and newBest based on score and scoreType
542
- if (scoreType == scoreTypes.HScore){
543
- if (thisBest > bestScore) {
544
- newBest = true;
545
- bestScore = thisBest;
546
- info.setScore(thisBest);
547
- info.saveHighScore();
548
- }
549
-
550
- } else if (scoreType == scoreTypes.LScore) {
551
- bestScore = settings.readNumber("low-score");
552
- if(bestScore == undefined){bestScore = Infinity;}
553
- if (thisBest < bestScore) {
554
- newBest = true;
555
- bestScore = thisBest;
556
- info.setScore(thisBest);
557
- saveLowScore(thisBest);
558
- }
559
-
560
- } else if (scoreType == scoreTypes.HTime) {
561
-
562
- // Set thisBest to timeElapsed if no customScore
563
- if (!customScore) {
564
- thisBest = timeElapsed;
565
- }
566
-
567
- if (thisBest > bestScore) {
568
- newBest = true;
569
- bestScore = thisBest;
570
- info.setScore(thisBest);
571
- info.saveHighScore();
572
- }
573
-
574
- } else if (scoreType == scoreTypes.LTime) {
575
- bestScore = settings.readNumber("low-score");
576
- if (bestScore == undefined) { bestScore = Infinity; }
577
-
578
- // Set thisBest to timeElapsed if no customScore
579
- if (!customScore) {
580
- thisBest = timeElapsed;
581
- }
582
-
583
- if (thisBest < bestScore) {
584
- newBest = true;
585
- bestScore = thisBest;
586
- info.setScore(thisBest);
587
- saveLowScore(thisBest);
588
- }
589
-
590
- } else {
591
-
592
- // Score judging type must be "None"
593
- thisBest = undefined;
594
- bestScore = undefined;
595
- newBest = false;
596
- }
597
-
598
- // Make sure there's a sound to playe
599
- if (! winSound){winSound = music.powerUp;}
600
-
601
- // releasing memory and clear fibers. Do not add anything that releases the fiber until background is set below,
602
- // or screen will be cleared on the new frame and will not appear as background in the game over screen.
603
- game.popScene();
604
- game.pushScene();
605
- scene.setBackgroundImage(screen.clone());
606
-
607
- winSound.play();
608
-
609
- fanfare.startScreenEffect();
610
-
611
- pause(400);
612
-
613
- const overDialog = new GameOverDialog(true, message, thisBest, bestScore, newBest);
614
- scene.createRenderable(scene.HUD_Z, target => {
615
- overDialog.update();
616
- target.drawTransparentImage(
617
- overDialog.image,
618
- 0,
619
- (screen.height - overDialog.image.height) >> 1
620
- );
621
- });
622
- pause(500); // wait for users to stop pressing keys
623
- overDialog.displayCursor();
624
- game.waitAnyButton();
625
- control.reset();
626
-
627
- }
628
-
629
- function roundOff(thisNum:number, toPlace:number): number {
630
- const x = Math.pow(10, toPlace);
631
- return Math.round(thisNum * x) / x;
632
- }
633
-
634
- function init(winStyle: winTypes, fanfare: effects.BackgroundEffect) {
635
- if (countdownInitialized) return;
636
- countdownInitialized = true;
637
-
638
- info.onCountdownEnd(function () {
639
-
640
- //Handling manually to include number of seconds passed
641
- /*
642
- if (winStyle == winTypes.Win) {
643
- game.over(true, fanfare)
644
- } else */ if (winStyle == winTypes.Lose) {
645
- game.over(false, fanfare)
646
- } else {
647
- newGameOver(winStyle, fanfare);
648
- }
649
- })
650
- }
651
-
652
- export class GameOverDialog extends game.BaseDialog {
653
- protected cursorOn: boolean;
654
- protected isNewbestScore: boolean;
655
-
656
- constructor(
657
- protected win: boolean,
658
- protected messageText: string,
659
- protected score?: number,
660
- protected best?: number,
661
- protected newBest?: boolean
662
- ) {
663
- super(screen.width, 46, img`
664
- 1 1 1
665
- f f f
666
- 1 1 1
667
- `);
668
- this.cursorOn = false;
669
-
670
- /* Since best time is lower, need to do this elsewhere
671
- this.isNewbestScore = this.score > this.bestScore;
672
- */
673
- }
674
-
675
- displayCursor() {
676
- this.cursorOn = true;
677
- }
678
-
679
- update() {
680
- this.clearInterior();
681
- this.drawTextCore();
682
-
683
- if (this.cursorOn) {
684
- this.drawCursorRow();
685
- }
686
- }
687
-
688
- drawTextCore() {
689
- const titleHeight = 8;
690
-
691
- this.image.printCenter(
692
- this.messageText,
693
- titleHeight,
694
- screen.isMono ? 1 : 5,
695
- image.font8
696
- );
697
-
698
-
699
- if (this.score != undefined) {
700
- const scoreHeight = 23;
701
- const bestScoreHeight = 34;
702
- const scoreColor = screen.isMono ? 1 : 2;
703
-
704
- this.image.printCenter(
705
- "Score:" + this.score,
706
- scoreHeight,
707
- scoreColor,
708
- image.font8
709
- );
710
-
711
- if (this.newBest == true) {
712
- this.image.printCenter(
713
- "New Best Score!",
714
- bestScoreHeight,
715
- scoreColor,
716
- image.font5
717
- );
718
- } else {
719
- this.image.printCenter(
720
- "Best:" + this.best,
721
- bestScoreHeight,
722
- scoreColor,
723
- image.font8
724
- );
725
- }
726
- }
727
- }
728
- }
729
-
730
- // End Info
731
-
732
- // Formerly namespace Game
733
-
734
-
735
- /**
736
- * Adds additional end game styles
737
- */
738
- //% color="#b70082"
739
- //% group="Game"
740
- //% blockId=on_game_over_expanded
741
- //% block="game over $winStyle || add effect $winEffect"
742
- //% winType.defl=winTypes.Win
743
- //% winEffect.defl=effects.confetti
744
- //% inlineInputMode=inline
745
- export function onGameOverExpanded(winStyle: winTypes, winEffect?: effects.BackgroundEffect) {
746
-
747
- if (winEffect == undefined) {
748
- if (winStyle == winTypes.Lose) { winEffect = effects.melt; }
749
- else { winEffect = effects.confetti; }
750
- }
751
-
752
- if (winStyle == winTypes.Lose) {
753
- game.over(false, winEffect)
754
- } else {
755
- newGameOver(winStyle, winEffect);
756
- }
757
- }
758
-
759
- /**
760
- * Adds custom end game styles
761
- */
762
- //% color="#b70082"
763
- //% group="Game"
764
- //% blockId=on_game_over_custom_expanded
765
- //% block="game over $message || with $winEffect and $gameSound send score $score judge $scoring"
766
- //% message.defl="Great Job!"
767
- //% scoring.defl=scoreTypes.None
768
- //% winEffect.defl=effects.confetti
769
- //% gameSound.defl=music.powerUp
770
- //% inlineInputMode=inline
771
- export function customGameOverExpanded(message: string, winEffect?: effects.BackgroundEffect, gameSound?: music.Melody, scoring?: scoreTypes, score?: number) {
772
- if (!winEffect) { winEffect = effects.confetti; }
773
- if (!scoring) { scoring = scoreTypes.HScore; }
774
- if (score == undefined) { info.score();}
775
- if (!gameSound) { gameSound = music.powerUp;}
776
- game.setGameOverSound(true, gameSound);
777
- newGameOver(winTypes.Custom, winEffect, gameSound, scoring, message, score);
778
- }
779
-
780
-
781
- // Formerly namespace Ball
782
-
783
-
784
-
785
- /**
786
- * Creates a new throwable from an image and kind
787
- * @param img the image for the sprite
788
- * @param kind the kind to make the throwable
789
- * @param x optional initial x position, eg: 10
790
- * @param y optional initial y position, eg: 110
791
- */
792
- //% blockId=throwCreate block="ball $img=screen_image_picker of kind $kind=spritekind || at x $x y $y"
793
- //% color="#b70082"
794
- //% group="Ball"
795
- //% expandableArgumentMode=toggle
796
- //% inlineInputMode=inline
797
- //% blockSetVariable=myBall
798
- //% weight=100
799
- export function create(img: Image,
800
- kind: number,
801
- x: number = 10,
802
- y: number = 110): Ball {
803
- return new Ball(img, kind, x, y);
804
- }
805
-
806
-
807
-
808
- /**
809
- * Create a new ball with a given speed that starts from the location of another sprite.
810
- * The sprite auto-destroys when it leaves the screen. You can modify position after it's created.
811
- */
812
- //% group="Ball"
813
- //% color="#b70082"
814
- //% blockId=spritescreateprojectileballfromparent block="ball projectile $img=screen_image_picker based on $parentBall=variables_get(myBall) || of kind $kind=spritekind"
815
- //& kind.defl=1
816
- //% blockSetVariable=myBall
817
- //% inlineInputMode=inline
818
- export function createProjectileBallFromSprite(img: Image, parentBall: Ball, kind?: number): Ball {
819
- let vx = xComponent(parentBall.angle, parentBall.pow);
820
- let vy = carnival.yComponent(parentBall.angle, parentBall.pow);
821
- let ay = parentBall.gravity;
822
- let ax = parentBall.wind;
823
- let p = parentBall.pow;
824
- if (!kind) { kind = SpriteKind.Projectile;}
825
- return createProjectileBall(img, vx, vy, ax, ay, p, kind, parentBall);
826
- }
827
-
828
- /**
829
- * Create a new sprite with given speed, and place it at the edge of the screen so it moves towards the middle.
830
- * The sprite auto-destroys when it leaves the screen. You can modify position after it's created.
831
- */
832
- //% group="Ball"
833
- //% color="#b70082"
834
- //% blockId=spritescreateprojectileball block="ball $img=screen_image_picker vx $vx vy $vy of kind $kind=spritekind||based on $parentBall=variables_get(myBall)"
835
- //% weight=99
836
- //% blockSetVariable=myBall
837
- //% inlineInputMode=inline
838
- //% expandableArgumentMode=toggle
839
- function createProjectileBall(img: Image, vx: number, vy: number, ax: number, ay: number, power: number, kind?: number, parentBall?: Ball) {
840
- const s = carnival.create(img, kind || SpriteKind.Projectile);
841
- const sc = game.currentScene();
842
-
843
- if (parentBall) {
844
- s.setPosition(parentBall.x, parentBall.y);
845
- s.vx = xComponent(parentBall.angle, parentBall.pow);
846
- s.vy = carnival.yComponent(parentBall.angle, parentBall.pow);
847
- s.ay = parentBall.gravity;
848
- s.ax = parentBall.wind;
849
- s.pow = parentBall.pow;
850
- } else {
851
- // put it at the edge of the screen so that it moves towards the middle
852
- // If the scene has a tile map, place the sprite fully on the screen
853
- const xOff = sc.tileMap ? -(s.width >> 1) : (s.width >> 1) - 1;
854
- const yOff = sc.tileMap ? -(s.height >> 1) : (s.height >> 1) - 1;
855
- const cam = game.currentScene().camera;
856
-
857
- let initialX = cam.offsetX;
858
- let initialY = cam.offsetY;
859
-
860
- if (vx < 0) {
861
- initialX += screen.width + xOff;
862
- } else if (vx > 0) {
863
- initialX += -xOff;
864
- }
865
-
866
- if (vy < 0) {
867
- initialY += screen.height + yOff;
868
- } else if (vy > 0) {
869
- initialY += -yOff;
870
- }
871
-
872
- s.setPosition(initialX, initialY);
873
- }
874
-
875
- s.moon.destroy();
876
- s.flags |= sprites.Flag.AutoDestroy | sprites.Flag.DestroyOnWall;
877
-
878
- return s;
879
- }
880
-
881
-
882
-
883
- /**
884
- * Convert degrees to radians
885
- * @param degree to convert
886
- * @return converted value in radians
887
- */
888
- function degreeToRadian(degree: number): number {
889
- return degree * Math.PI / 180;
890
- }
891
-
892
- /**
893
- * Evaluate the x component of a given vector
894
- * @param degree angle of vector
895
- * @param magnitude magnitude of vector
896
- * @return x component of vector
897
- */
898
- //% group="Ball"
899
- //% color="#b70082"
900
- export function xComponent(degree: number, magnitude: number): number {
901
- return magnitude * Math.cos(degreeToRadian(degree));
902
- }
903
-
904
- /**
905
- * Evaluate the y component of a given vector
906
- * @param degree angle of vector
907
- * @param magnitude magnitude of vector
908
- * @return y component of vector
909
- */
910
- //% group="Ball"
911
- //% color="#b70082"
912
- export function yComponent(degree: number, magnitude: number): number {
913
- return -magnitude * Math.sin(degreeToRadian(degree));
914
- }
915
- }
916
-
917
- /**
918
- * A throwable
919
- **/
920
-
921
- //% blockNamespace=carnival color="#b70082" blockGap=8
922
- class Ball extends sprites.ExtendableSprite {
923
- private renderable: scene.Renderable;
924
-
925
- private controlKeys: boolean;
926
- private trace: boolean;
927
-
928
- //% group="Ball" blockSetVariable="myBall"
929
- //% blockCombine block="angle"
930
- //% weight=8
931
- public angle: number;
932
- //% group="Ball" blockSetVariable="myBall"
933
- //% blockCombine block="power"
934
- //% weight=8
935
- public pow: number;
936
- //% group="Ball" blockSetVariable="myBall"
937
- //% blockCombine block="tracing time (seconds)"
938
- //% weight=8
939
- public iter: number;
940
- //% group="Ball" blockSetVariable="myBall"
941
- //% blockCombine block="trace color"
942
- //% weight=8
943
- public traceColor: number;
944
- //% group="Ball" blockSetVariable="myBall"
945
- //% blockCombine block="gravity"
946
- //% weight=8
947
- public gravity: number;
948
- //% group="Ball" blockSetVariable="myBall"
949
- //% blockCombine block="wind"
950
- //% weight=8
951
- public wind: number;
952
- //% group="Ball" blockSetVariable="myBall"
953
- //% blockCombine block="angle adjust rate"
954
- //% weight=8
955
- public angleRate: number;
956
- //% group="Ball" blockSetVariable="myBall"
957
- //% blockCombine block="wind"
958
- //% weight=8
959
- public powerRate: number;
960
- //% blockSetVariable="myBall"
961
- //% blockCombine block="moon"
962
- //% weight=8
963
- public moon: Sprite;
964
-
965
-
966
- public constructor(img: Image,
967
- kind: number,
968
- x: number,
969
- y: number) {
970
- super(img);
971
- this.setKind(kind);
972
- this.x = x;
973
- this.y = y;
974
-
975
- this.gravity = 20;
976
- this.pow = 50;
977
- this.angle = 10;
978
- this.angleRate = 3;
979
- this.powerRate = 3;
980
- this.iter = .4;
981
- this.wind = 0;
982
- this.moon = sprites.create(assets.image`crosshair`, SpriteKind.Moon);
983
- this.moon.setFlag(SpriteFlag.Invisible, true);
984
-
985
- this.renderable = scene.createRenderable(-0.5, (target, camera) => {
986
- let xComp = carnival.xComponent(this.angle, this.pow);
987
- let yComp = carnival.yComponent(this.angle, this.pow);
988
- let xOffset = camera.offsetX;
989
- let yOffset = camera.offsetY;
990
-
991
- for (let i: number = 0.1; i < this.iter; i += i / 5) {
992
- let x = this.x + i * xComp + (i ** 2) * this.wind / 2;
993
- let y = this.y + i * yComp + (i ** 2) * this.gravity / 2;
994
- target.setPixel(
995
- x - xOffset,
996
- y - yOffset,
997
- this.traceColor
998
- );
999
- }
1000
- }, () => !this.ay && this.trace);
1001
-
1002
- this.controlKeys = false;
1003
- this.trace = false;
1004
- this.traceColor = 1;
1005
- }
1006
-
1007
- /**
1008
- * Gets the throwables's sprite
1009
- */
1010
- //% blockId=throwSprite block="$this sprite"
1011
- //% weight=8
1012
- get sprite(): Sprite {
1013
- return this;
1014
- }
1015
-
1016
- /**
1017
- * Set how to show the trace for the estimated path
1018
- * @param on whether to turn on or off this feature, eg: true
1019
- */
1020
- //% blockId=setTraceMulti block="trace $this path estimate $traceWay"
1021
- //% weight=50
1022
- //% color="#b70082"
1023
- //% group="Ball"
1024
- //% traceWay.defl="tracers.Full"
1025
- //% this.defl=myBall
1026
- public setTraceMulti(traceWay: tracers): void {
1027
-
1028
- if(traceWay == tracers.Full){
1029
- this.moon.setFlag(SpriteFlag.Invisible, true);
1030
- this.iter = 3;
1031
- this.trace = true;
1032
- } else if (traceWay == tracers.Part) {
1033
- this.moon.setFlag(SpriteFlag.Invisible, true);
1034
- this.iter = .3;
1035
- this.trace = true;
1036
- } else if (traceWay == tracers.Pointer) {
1037
- this.moon.setFlag(SpriteFlag.Invisible, true);
1038
- this.iter = .2;
1039
- this.trace = true;
1040
- } else if (traceWay == tracers.Cross) {
1041
- this.trace = false;
1042
- this.moon.setFlag(SpriteFlag.Invisible, false);
1043
- } else {
1044
- this.trace = false;
1045
- this.moon.setFlag(SpriteFlag.Invisible, false);
1046
- }
1047
- }
1048
-
1049
-
1050
- /**
1051
- * Set the crosshairs to distance away from center of
1052
- * ball in direction ball will travel
1053
- */
1054
- //% color="#b70082"
1055
- //% weight=50
1056
- //% blockId=updatecross block="update crosshairs || using distance $dist "
1057
- //% expandableArgumentMode=toggle
1058
- //% dist.defl=3
1059
- public update_crosshair(dist?:number) {
1060
- if(dist == undefined) {dist = 3;}
1061
- spriteutils.placeAngleFrom(
1062
- this.moon,
1063
- this.angle * Math.PI / -180,
1064
- Math.max(this.width + dist, this.height + dist),
1065
- this
1066
- )
1067
- }
1068
-
1069
- /**
1070
- * Set the trace length for the estimated path in percent
1071
- */
1072
- //% weight=50
1073
- //% color="#b70082"
1074
- //% group="Ball""
1075
- //% blockId=setIter block="set $this trace length to $len \\%"
1076
- //% len.defl=50
1077
- //% this.defl=myBall
1078
- public setIter(len: number): void {
1079
- // Make 100 percent distance = 3
1080
- this.iter = 3 * (len/100);
1081
- }
1082
-
1083
- /**
1084
- * Throw the throwable with the current settings
1085
- */
1086
- //% weight=50
1087
- //% color="#b70082"
1088
- //% group="Ball"
1089
- //% blockId=throwIt block="toss $this"
1090
- //% this.defl=myBall
1091
- public throwIt(): void {
1092
- this.vx = carnival.xComponent(this.angle, this.pow);
1093
- this.vy = carnival.yComponent(this.angle, this.pow);
1094
- this.ay = this.gravity;
1095
- this.ax = this.wind;
1096
- }
1097
-
1098
- /**
1099
- * Stop the throwable at the current location
1100
- */
1101
- //% color="#b70082"
1102
- //% weight=50
1103
- //% group="Ball"
1104
- //% blockId=stopIt block="stop $this"
1105
- //% this.defl=myBall
1106
- public stopIt(): void {
1107
- this.ay = 0;
1108
- this.ax = 0;
1109
- this.vx = 0;
1110
- this.vy = 0;
1111
- }
1112
-
1113
- /**
1114
- * Set whether to control the throwable with the arrow keys; left and right
1115
- * to adjust the angle, and up and down to increase / decrease power
1116
- * @param on whether to turn on or off this feature, eg: true
1117
- */
1118
- //% color="#b70082"
1119
- //% weight=50
1120
- //% group="Ball"
1121
- //% blockId=controlBallKeys block="control $this with arrow keys || $on=toggleOnOff"
1122
- //% this.defl=myBall
1123
- //% inlineInputMode=inline
1124
- public controlBallWithArrowKeys(on: boolean = true): void {
1125
- this.controlKeys = on;
1126
-
1127
- game.onUpdate(() => {
1128
- if (this.controlKeys) {
1129
- this.angle -= controller.dx() * this.angleRate / 2;
1130
- this.pow -= controller.dy() * this.powerRate / 2;
1131
- }
1132
- })
1133
- }
1134
-
1135
- /**
1136
- * Set whether to control the throwable with the arrow keys; left and right
1137
- * to adjust the angle, and up and down to increase / decrease power
1138
- * @param on whether to turn on or off this feature, eg: true
1139
- */
1140
- //% blockId=variablePower block="vary $this power using $status(statusbar) from $minNum \\% to $maxNum \\% || speed $thisSpeed"
1141
- //% weight=2
1142
- //% color="#b70082"
1143
- //% group="Ball"
1144
- //% minNum.defl=50
1145
- //% maxNum.defl=100
1146
- //% this.defl=myBall
1147
- //% inlineInputMode=inline
1148
- public variablePower(status: StatusBarSprite, minNum: number, maxNum: number, thisSpeed?:number): void {
1149
- if(thisSpeed == undefined){thisSpeed = 100;}
1150
- if(minNum < 0){minNum = 0;}
1151
- if(maxNum > 100){maxNum = 100;}
1152
- game.onUpdate(() => {
1153
- status.value = minNum + Math.abs(Math.sin(game.runtime() / (90000*(1/thisSpeed))) * (maxNum-minNum))
1154
- this.pow = status.value;
1155
- this.update_crosshair();
1156
- })
1157
- }
1158
-
1159
- }
1160
-
1161
-
1162
-
1163
89
  ```
1164
90
 
1165
91