pxt-arcade 1.10.10 → 1.10.13

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.
@@ -2,19 +2,25 @@
2
2
  ### @explicitHints true
3
3
 
4
4
 
5
- ## {Video Intro @showdialog}
5
+ ## Whack-the-Mole Intro @showdialog
6
6
 
7
- ![Whack'em All Carnival Intro](youtube:ow6P7wTs3Uk)
7
+ ![Whack-the-Mole Carnival Intro](youtube:LwzffWleZug)
8
8
 
9
9
 
10
10
 
11
11
  ## {2. Read Instructions}
12
12
 
13
- **🚩 Start with the basics 🚩**
13
+ **🎡 Start with Instructions 🎡**
14
14
 
15
- - :comment: This tutorial will show you how to get your mole moving. When you're done, move on to the next tutorial to add the hammer!
15
+ This is the **instruction panel**. It has directions
16
+ on what to do.
17
+
18
+ ---
19
+
20
+ Be on the lookout for secret information!
16
21
 
17
- ~hint Click here to reveal hidden info 🕵️
22
+
23
+ ~hint Click here to reveal hidden info 🕵🏽
18
24
 
19
25
  <br/>
20
26
  Look for clues like this when you read instructions.
@@ -23,134 +29,190 @@ Each one gives extra info, tips, or tricks.
23
29
 
24
30
  hint~
25
31
 
32
+ When you're done reading, click **Next** to move to the next instruction.
33
+
26
34
  ---
27
35
  ---
28
36
 
29
37
 
30
38
 
31
39
 
32
- ## {3. Background}
40
+ ## {3. Your First Block}
33
41
 
34
42
  **Ready to start coding?**
35
43
 
36
- Let's place a grid in the background where the mole can hide!
44
+ Let's place an image of a grassy grid of holes in the background!
37
45
 
38
46
 
39
- - :tree: From the ``||scene: Scene||`` category **in the toolbox**, grab <br/>
40
- ``||scene: set background image to []||`` </br>
47
+ - :tree: Go to the ``||scene: Scene||`` category **in the toolbox** and grab <br/>
48
+ ```block
49
+ scene.setBackgroundImage(img`.`)
50
+ ```
41
51
  and snap it inside the empty ``||loops: on start||`` block already in the workspace.
42
52
 
53
+ ~hint Click here to see how 🕵🏽
43
54
 
44
- ~hint What does that mean? 🕵️
55
+ ![Look under Scene for the block you need](/static/skillmap/mole/add-bg-block.gif "Drag out the background block to fill later.")
45
56
 
46
- In this tutorial, the instructions will give you the names of the blocks you need, and highlight them in the same color as the block you will find in the toolbox.
57
+ - :lightbulb: The panel with the colorful category names is called the
58
+ **toolbox**. <br/>
59
+ Click ``||scene: Scene||`` to find the event block you need.
60
+
61
+ hint~
62
+
63
+
64
+ ---
65
+ ---
47
66
 
48
- For example, this text: <br/>
49
- ``||scene: set background image to []||``<br/>
50
- is trying to direct you toward this block:
51
67
 
52
- ```block
53
- scene.setBackgroundImage(img`.`)
54
- ```
55
68
 
56
- And the rest of the instruction wants you to do this:
57
69
 
58
- ![Find the background block](/static/skillmap/mole/add-background.gif "Add your block to the `on start` container.")
70
+ ## {5. Check Your Game!}
71
+
72
+ Now it's time to take a look!
73
+
74
+ - :binoculars: Click the mini **game window** in the bottom corner to open the **bigger game window**!
75
+
76
+ You should see a green background with 9 purple holes for the mole to hide in.
77
+
78
+ - :mouse pointer: Don't forget to click **Next** to get back to the instructions.
79
+
80
+
81
+ ~hint Click here to see how 🕵🏽
82
+
83
+ ![Look for the game window in the lower right](/static/skillmap/mole/game.gif "Click the mini game window to pop open the bigger game window.")
59
84
 
60
85
  hint~
61
86
 
62
87
  ---
63
88
  ---
64
89
 
65
- #### ~ tutorialhint
66
90
 
67
- ```blocks
68
- scene.setBackgroundImage(img`.`)
69
- ```
70
91
 
71
92
 
72
- ## {4. Choose the Grid BG}
93
+ ## {6. Add the Sprite}
94
+
95
+
96
+ Now we'll add the mole **SPRITE** to our game.
97
+
98
+ ~hint What's a sprite? 💡
73
99
 
100
+ In Arcade, each character or image that does something is called a **SPRITE**.
74
101
 
75
- Now we'll select the grid from the **My Assets** library by clicking on the block.
102
+ Sprites have properties that you can use and change -- things like scale, position, and lifespan are all properties of sprites.
76
103
 
104
+ Our mole will be a sprite, too.
77
105
 
78
- - :mouse pointer: Click the empty square in <br/>
79
- ``||scene: set background image to []||``.<br/>
80
- The image editor will open automatically.
106
+ hint~
107
+
108
+ <br/>
81
109
 
82
- - :mouse pointer: Click the **My Assets** tab at the top of the image editor to see the sprite assets for this tutorial.
110
+ - :paper plane: From the ``||sprites: Sprites||`` category **in the toolbox**, grab <br/>
83
111
 
84
- - :mouse pointer: Select the **grid** background <br/>
85
- ![Choose the background that looks like a grid full of holes.](/static/skillmap/mole/grid.png "Select the grid from My Assets.")
86
- and click **Done**.
112
+ ```block
113
+ let mole = sprites.create(assets.image`mole`, SpriteKind.Enemy)
114
+ ```
87
115
 
116
+ and snap it inside at **the bottom** of the ``||loops: on start||`` block already in the workspace.
88
117
 
89
118
 
90
- ~hint Show me how! 🕵️
119
+ ~hint Show me how! 🕵🏽
91
120
 
92
121
 
93
- ![Choose the background that looks like a grid full of holes.](/static/skillmap/mole/choose-background.gif "Add your block to the `on start` container.")
122
+ ![Add the sprite block.](/static/skillmap/mole/add-sprite.gif "Add a sprite to your game.")
94
123
 
95
124
  hint~
96
125
 
97
126
  ---
98
127
  ---
99
128
 
100
- #### ~ tutorialhint
129
+
130
+
131
+ ## {8. Make the Mole Move}
132
+
133
+ Let's get the mole jumping from hole to hole every second.
134
+
135
+ - :circle: From the ``||game: Game||`` category **in the toolbox**, grab
101
136
 
102
137
  ```blocks
103
- scene.setBackgroundImage(assets.image`grid`)
138
+ game.onUpdateInterval(1000, function () {
139
+ })
104
140
  ```
105
141
 
142
+ and snap it into **an empty area** of the workspace.
106
143
 
107
- ## {5. Add the Mole}
144
+ - :mouse pointer: Click the number **500** and change it to **1 second** (which is the same as 1000 ms.)
108
145
 
146
+ This is an **EVENT** block and it will cause an action to happen each time a second passes.
109
147
 
110
- Now we'll add the **mole** sprite to our game.
148
+ ~hint Tell me about events! 💡
111
149
 
112
- - :paper plane: From the ``||sprites: Sprites||`` category **in the toolbox**, grab <br/>
113
- ``||variables: set [mySprite] to sprite [ ] of kind [Player]||`` </br>
114
- and snap it inside at **the bottom** of the ``||loops: on start||`` block already in the workspace.
150
+ Events are things that might or might not happen while the code is running. A player might press a button, a timer might run out, or one sprite might overlap with another.
151
+
152
+ Each of those things is an event that you can assign a special action to in Arcade.
153
+
154
+ hint~
155
+
156
+ ~hint Show me how! 🕵🏽
157
+
158
+ ![Add an on game update block.](/static/skillmap/mole/game-update.gif "Change 500ms to 1000ms.")
159
+
160
+ hint~
161
+
162
+ ---
163
+ ---
115
164
 
116
- - :mouse pointer: Click the **empty square** to open the image editor, then click the **My Assets** tab at the top to see the sprites for this tutorial.
117
165
 
118
- - :mouse pointer: Select the **mole** sprite <br/>
119
- ![Choose the image that looks like a mole head.](/static/skillmap/mole/mole.png "Select the mole from My Assets.")
120
- and click **Done**.
121
166
 
122
- - :mouse pointer: Click the kind ``||sprites: Player||`` and change it to ``||sprites: Enemy||`` so we know the sprite isn't on our side!
123
167
 
168
+ ## {9. Make the Mole Move pt. 2}
169
+
170
+
171
+ - :paper plane: From the ``||sprites: Sprites||`` category **in the toolbox**, grab <br/>
172
+ ```block
173
+ sprites.move_to_random_hole_on_grid(mySprite)
174
+ ```
175
+ and snap it into the empty ``||game: on game update every [1000] ms||`` block that's already in the workspace.
124
176
 
125
177
 
126
- ~hint Show me how! 🕵️
127
178
 
179
+ ~hint Show me how! 🕵🏽
128
180
 
129
- ![Choose the image that looks like a mole head.](/static/skillmap/mole/choose-mole.gif "Add a mole to your game.")
181
+ ![Add the random area block](/static/skillmap/mole/move-mole.gif "Make sure the new block connects inside the game update block.")
130
182
 
131
183
  hint~
132
184
 
133
185
  ---
134
186
  ---
135
187
 
136
- #### ~ tutorialhint
137
188
 
138
- ```blocks
139
- scene.setBackgroundImage(assets.image`grid`)
140
- let mySprite = sprites.create(assets.image`mole`, SpriteKind.Enemy)
141
- ```
142
189
 
143
190
 
144
191
 
192
+ ## {10. Check Your Game!}
193
+
194
+ Look at your project again!
145
195
 
146
- ## {12. Finale}
196
+ - :binoculars: Click the mini **game window** in the bottom corner to open the **bigger game window**!
197
+
198
+ You should see the mole changing spots every second.
199
+
200
+ (Don't forget to click **Next** to get back to the instructions.)
201
+
202
+
203
+ ---
204
+ ---
205
+
206
+
207
+
208
+
209
+ ## {11. Finale}
147
210
 
148
211
  **🎉 Way to Go 🎉**
149
212
 
150
- You have started your very own clicker game!
151
- Try it in the console and see if you can get more than **40 points**.
213
+ You have started your very own Whack-the-Mole game.
152
214
 
153
- When you're finished playing, come back to the instructions and click the **Done** button to return to the skillmap and continue building your amazing **🎈carnival game🎈**!
215
+ When you're ready, click **Done** to return to the skillmap so you can add the rubber hammer that will let you tag the mole!
154
216
 
155
217
  ---
156
218
  ---
@@ -158,29 +220,372 @@ When you're finished playing, come back to the instructions and click the **Done
158
220
 
159
221
 
160
222
 
223
+ ```blockconfig.local
224
+ scene.setBackgroundImage(assets.image`grid`)
225
+ game.onUpdateInterval(1000, function () { })
226
+ let mole = sprites.create(assets.image`mole`, SpriteKind.Enemy)
227
+ ```
228
+
229
+
161
230
  ```package
162
231
  simple-blocks=github:microsoft/arcade-tutorial-extensions/simple-blocks/
163
232
  arcade-text=github:microsoft/arcade-text/
164
233
  ```
165
234
 
166
235
 
167
- ```ghost
236
+ ```customts
168
237
 
169
- scene.setBackgroundImage(assets.image`grid`)
170
- let mySprite = sprites.create(assets.image`mole`, SpriteKind.Enemy)
171
- game.onUpdateInterval(1000, function () {
172
- mySprite.setPosition(simplified.chooseRandomNumber(28, 80, 130), simplified.chooseRandomNumber(21, 53, 85))
173
- })
238
+ enum winTypes {
239
+ //% block="win game"
240
+ Win,
241
+ //% block="lose game"
242
+ Lose,
243
+ //% block="high score"
244
+ Score,
245
+ //% block="multiplayer"
246
+ Multi
247
+ }
174
248
 
175
- ```
249
+ enum speeds {
250
+ //% block="fast"
251
+ Fast,
252
+ //% block="medium"
253
+ Med,
254
+ //% block="slow"
255
+ Slow
256
+ }
176
257
 
258
+ enum areas {
259
+ //% block="top"
260
+ Top,
261
+ //% block="middle"
262
+ Mid,
263
+ //% block="bottom"
264
+ Bottom
265
+ }
177
266
 
267
+ let textSprite: TextSprite = null
268
+ //let fanfare: effects.BackgroundEffect = undefined;
269
+ //let winStyle = winTypes.Score
178
270
 
179
- ```customts
180
271
 
181
- namespace simplified {
272
+
273
+ namespace animation {
274
+ /**
275
+ * Prefills animation block with hammer items
276
+ */
277
+ //% color="#03aa74"
278
+ //% blockId=run-image-animation-hammer
279
+ //% block="animate $sprite=variables_get(myHammer) frames $frames=animation_editor interval (ms) $frameInterval=timePicker loop $loop=toggleOnOff"
280
+ //% frameInterval.defl=100
281
+ //% group="Animate"
282
+ //% weight=100
283
+ //% help=animation/run-image-animation-hammer
284
+ export function runImageAnimationHammer(sprite: Sprite, frames: Image[], frameInterval?: number, loop?: boolean) {
285
+ const anim = new ImageAnimation(sprite, frames, frameInterval || 100, !!loop);
286
+ anim.init();
287
+ }
288
+ }
182
289
 
183
290
 
291
+
292
+ namespace scene {
293
+ /**
294
+ * Adds text to the top, middle, or bottom
295
+ * of screen as defined by circuis games
296
+ */
297
+ //% color="#4b6584"
298
+ //% blockId=add_label_to
299
+ //% block="add label $myLabel to $myPosition" of window
300
+ //% myLabel.defl="Whack-the-Mole"
301
+ //% myPosition.defl=areas.Bottom
302
+ //% inlineInputMode=inline
303
+ export function add_label_to(myLabel: string, myPosition: areas) {
304
+ textSprite = textsprite.create(myLabel)
305
+ if (myPosition == areas.Bottom) textSprite.setPosition(80, 110);
306
+ if (myPosition == areas.Mid) textSprite.setPosition(80, 60);
307
+ if (myPosition == areas.Top) textSprite.setPosition(80, 20);
308
+ }
309
+ }
310
+
311
+ namespace controller{
312
+
313
+ /**
314
+ * Combines a simple "move with arrows"
315
+ * and stay in screen
316
+ */
317
+ //% color="#d54322"
318
+ //% blockId=move_only_onscreen_with_arrows
319
+ //% block="move $thisSprite=variables_get(myHammer) on screen with speed $mySpeed"
320
+ //% mySpeed.defl=speeds.Fast
321
+ //% inlineInputMode=inline
322
+ export function move_only_onscreen_with_arrows(thisSprite: Sprite, mySpeed: speeds) {
323
+ thisSprite.setStayInScreen(true)
324
+ if (mySpeed == speeds.Fast) {
325
+ controller.moveSprite(thisSprite, 225, 225)
326
+ } else if (mySpeed == speeds.Med) {
327
+ controller.moveSprite(thisSprite, 175, 175)
328
+ } else {
329
+ controller.moveSprite(thisSprite, 100, 100)
330
+ }
331
+ }
332
+
333
+ }
334
+
335
+ namespace sprites {
336
+
337
+ /**
338
+ * Randomly moves mole to one of the holes on grid
339
+ */
340
+ //% color="#4b7bec"
341
+ //% blockId=move_to_random_hole_on_grid
342
+ //% block="move sprite $thisSprite=variables_get(mySprite) to random area"
343
+ //% inlineInputMode=inline
344
+ export function move_to_random_hole_on_grid(thisSprite: Sprite) {
345
+ thisSprite.setPosition(simplified.chooseRandomNumber(28, 80, 130), simplified.chooseRandomNumber(21, 53, 85))
346
+ }
347
+ }
348
+
349
+ namespace info {
350
+ let countdownInitialized = false;
351
+ /**
352
+ * Adds game end style to countdown
353
+ */
354
+ //% color="#cf6a87"
355
+ //% group=countdown
356
+ //% blockId=start_countdown_game
357
+ //% block="start countdown $myTime (s) and game over $winType || effect $winEffect"
358
+ //% myTime.defl=15
359
+ //% winType.defl=winTypes.Score
360
+ //% winEffect.defl=effects.confetti
361
+ //% inlineInputMode=inline
362
+ export function startCountdownGame(myTime: number, winType: winTypes, winEffect?: effects.BackgroundEffect) {
363
+ if (!winType)
364
+ winType = winTypes.Win;
365
+ if (!winEffect && winType != winTypes.Lose){
366
+ winEffect = effects.confetti;
367
+ }
368
+ else { winEffect = effects.melt;}
369
+ init(winType, winEffect);
370
+ info.startCountdown(myTime)
371
+
372
+ }
373
+
374
+ export function newGameOver(winStyle: winTypes, fanfare: effects.BackgroundEffect) {
375
+
376
+ // Prep default variables for different win types
377
+ let winnerNumber = 1;
378
+ let thisHigh = 0;
379
+
380
+ // Save all scores as relevant to the game.
381
+ info.saveAllScores();
382
+
383
+ // collect the scores before popping the scenes
384
+ const scoreInfo1 = info.player1.getState();
385
+ const scoreInfo2 = info.player2.getState();
386
+ const scoreInfo3 = info.player3.getState();
387
+ const scoreInfo4 = info.player4.getState();
388
+ const highScore = info.highScore();
389
+ const allScores = [scoreInfo1.score, scoreInfo2.score, scoreInfo3.score, scoreInfo4.score];
390
+
391
+ // Find player with highest score
392
+ for (let i = 0; i < 4; i++) {
393
+ if (allScores[i] > thisHigh) {
394
+ thisHigh = allScores[i];
395
+ winnerNumber = i+1;
396
+ }
397
+ }
398
+ // If highest score is higher than saved high, replace
399
+ if (thisHigh > highScore){
400
+ info.saveHighScore(); }
401
+
402
+
403
+ // releasing memory and clear fibers. Do not add anything that releases the fiber until background is set below,
404
+ // or screen will be cleared on the new frame and will not appear as background in the game over screen.
405
+ game.popScene();
406
+ game.pushScene();
407
+ scene.setBackgroundImage(screen.clone());
408
+
409
+ music.powerUp.play();
410
+
411
+ fanfare.startScreenEffect();
412
+
413
+ pause(400);
414
+
415
+ const overDialog = new GameOverDialog(true, thisHigh, highScore, winnerNumber, winStyle);
416
+ scene.createRenderable(scene.HUD_Z, target => {
417
+ overDialog.update();
418
+ target.drawTransparentImage(
419
+ overDialog.image,
420
+ 0,
421
+ (screen.height - overDialog.image.height) >> 1
422
+ );
423
+ });
424
+ pause(500); // wait for users to stop pressing keys
425
+ overDialog.displayCursor();
426
+ game.waitAnyButton();
427
+ control.reset();
428
+
429
+ }
430
+
431
+ function init(winStyle: winTypes, fanfare: effects.BackgroundEffect) {
432
+ if (countdownInitialized) return;
433
+ countdownInitialized = true;
434
+
435
+ info.onCountdownEnd(function () {
436
+ if (winStyle == winTypes.Win) {
437
+ game.over(true, fanfare)
438
+ } else if (winStyle == winTypes.Lose) {
439
+ game.over(false, fanfare)
440
+ } else {
441
+ newGameOver(winStyle, fanfare);
442
+ }
443
+ })
444
+ }
445
+
446
+ export class GameOverDialog extends game.BaseDialog {
447
+ protected cursorOn: boolean;
448
+ protected isNewHighScore: boolean;
449
+
450
+ constructor(
451
+ protected win: boolean,
452
+ protected score?: number,
453
+ protected highScore?: number,
454
+ protected winnerNum?: number,
455
+ protected winStyle?: winTypes
456
+ ) {
457
+ super(screen.width, 46, img`
458
+ 1 1 1
459
+ f f f
460
+ 1 1 1
461
+ `);
462
+ this.cursorOn = false;
463
+ this.isNewHighScore = this.score > this.highScore;
464
+ }
465
+
466
+ displayCursor() {
467
+ this.cursorOn = true;
468
+ }
469
+
470
+ update() {
471
+ this.clearInterior();
472
+ this.drawTextCore();
473
+
474
+ if (this.cursorOn) {
475
+ this.drawCursorRow();
476
+ }
477
+ }
478
+
479
+ drawTextCore() {
480
+ const titleHeight = 8;
481
+ if (this.winStyle == winTypes.Multi){
482
+ this.image.printCenter(
483
+ "Player " + this.winnerNum + " wins!",
484
+ titleHeight,
485
+ screen.isMono ? 1 : 5,
486
+ image.font8
487
+ );
488
+
489
+ if (this.score !== undefined) {
490
+ const scoreHeight = 23;
491
+ const highScoreHeight = 34;
492
+ const scoreColor = screen.isMono ? 1 : 2;
493
+
494
+ this.image.printCenter(
495
+ "Score:" + this.score,
496
+ scoreHeight,
497
+ scoreColor,
498
+ image.font8
499
+ );
500
+
501
+ if (this.isNewHighScore) {
502
+ this.image.printCenter(
503
+ "New High Score!",
504
+ highScoreHeight,
505
+ scoreColor,
506
+ image.font5
507
+ );
508
+ } else {
509
+ this.image.printCenter(
510
+ "HI:" + this.highScore,
511
+ highScoreHeight,
512
+ scoreColor,
513
+ image.font8
514
+ );
515
+ }
516
+ }
517
+ }
518
+ else {
519
+ this.image.printCenter(
520
+ "Great Job!",
521
+ titleHeight,
522
+ screen.isMono ? 1 : 5,
523
+ image.font8
524
+ );
525
+
526
+ if (this.score !== undefined) {
527
+ const scoreHeight = 23;
528
+ const highScoreHeight = 34;
529
+ const scoreColor = screen.isMono ? 1 : 2;
530
+
531
+ this.image.printCenter(
532
+ "Score:" + this.score,
533
+ scoreHeight,
534
+ scoreColor,
535
+ image.font8
536
+ );
537
+
538
+ if (this.isNewHighScore) {
539
+ this.image.printCenter(
540
+ "New High Score!",
541
+ highScoreHeight,
542
+ scoreColor,
543
+ image.font5
544
+ );
545
+ } else {
546
+ this.image.printCenter(
547
+ "HI:" + this.highScore,
548
+ highScoreHeight,
549
+ scoreColor,
550
+ image.font8
551
+ );
552
+ }
553
+ }
554
+ }
555
+ }
556
+ }
557
+ }
558
+
559
+ namespace game {
560
+ /**
561
+ * Adds additional end game styles
562
+ */
563
+ //% color="#8854d0"
564
+ //% group=Gameplay
565
+ //% blockId=on_game_over_expanded
566
+ //% block="game over $winType || add effect $winEffect"
567
+ //% winType.defl=winTypes.Win
568
+ //% winEffect.defl=effects.confetti
569
+ //% inlineInputMode=inline
570
+ export function onGameOverExpanded(winStyle: winTypes, winEffect?: effects.BackgroundEffect) {
571
+ if (!winStyle)
572
+ winStyle = winTypes.Win;
573
+ if (!winEffect && winStyle != winTypes.Lose) {
574
+ winEffect = effects.confetti;
575
+ }
576
+ else { winEffect = effects.melt; }
577
+
578
+ if (winStyle == winTypes.Win) {
579
+ game.over(true, winEffect)
580
+ } else if (winStyle == winTypes.Lose) {
581
+ game.over(false, winEffect)
582
+ } else {
583
+ info.newGameOver(winStyle, winEffect);
584
+ }
585
+ }
586
+ }
587
+
588
+ namespace simplified {
184
589
  /**
185
590
  * Randomly chooses one of the parameter numbers
186
591
  *
@@ -207,11 +612,14 @@ namespace simplified {
207
612
  return myList._pickRandom();
208
613
  }
209
614
 
615
+
616
+
210
617
  }
211
618
 
212
619
  ```
213
620
 
214
621
 
622
+
215
623
  ```assetjson
216
624
  {
217
625
  "README.md": " ",