-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnico.yaml
657 lines (500 loc) · 27.6 KB
/
nico.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
name: Nico-8 with Python
description: |
Learn to make cool games in Nico-8!
lessons:
-
project: new
name: Putting a Sprite on the Screen
description: In this lesson you'll learn how to use Nico and create your first sprite
slides:
-
name: Your First Sprite
description: |
Welcome to codingworkshops! Before we dive into coding, you should just take a moment to get used to the interface.
directions:
- |
Take a look around!
- |
Try to figure out how to draw a sprite in the first square.
-
name: Your First Code
description: |
Now that you've drawn the sprite, let's put in it on the screen!
Enter the following code in the editor:
```python
def draw():
sprite(0, 2, 3)
```
directions:
- |
Make one more sprite, and draw it in a different place.
- |
What could that code mean? Think about that with your partner.
-
name: Talking to Nico
description: |
In order to do anything with Nico, we need to give it instructions on what we want it to do. These instructions are called *code*.
If we want to draw something, (with `sprite`), Nico needs to know to things:
which sprite to draw, the first `0`
where to draw it, the position `2, 3`
If you forgot your sprite's number, click on the sprite tab so that you can see it again.
directions:
- |
Why do we specify the position using two numbers? What could they mean?
- |
Change the `2` and `3` to different numbers to figure out how the numbers affect where the sprite is drawn.
- |
You can think of `2, 3` as a coordinate pair (2, 3) like in math class. Notice that the Y axis is flipped from what you are used to, and that the point (0, 0) is in the top left corner instead of the bottom left. This means that y-coordinate gets bigger when you move down, not up.
-
name: More Sprites
description: |
Now that we understand one part of the code, let's try breaking down the other part:
```python
def draw():
```
This line starts the `draw` section of our program. In this section, we tell Nico all the drawing we need to do, **so you only need one.**
directions:
- |
Make one more sprite and draw it in the center of the screen.
-
name: Moving Your Sprites
description: |
Let's start getting your sprite to move!
Whenever you encounter a coding problem, it's always good to first think about it from a high level. In this case, what 'moving' really means is that we just need to gradually change the sprite's position.
directions:
- |
Erase your current code and tell Nico to draw your sprite at `0, 0`, then at `1, 0`, and then at `2, 0`.
- |
Do you notice anything strange happening? Why might this be occurring?
-
name: Uh Oh
description: |
Huh. That didn't work - Nico just drew three overlapping sprites that are all stuck there!
To make sense of this, you need to understand how Nico actually works. 60 times every second, Nico does three things: It changes the state of the game (for example, by moving something), clears the screen, and draws the new positions — this is called the **game loop**.
If you want to create motion, you need to change the position of a sprite between frames — not just draw the sprite three times each frame!
directions:
- |
Turn to your partner and explain why the last slide's approach to movement failed.
- |
How might we actually move the sprite? (Hint: Think about the game loop!)
- |
One idea for moving the sprite is to use the part of the game loop that changes the state of the game — in particular, if we could change the position of the player, that would be helpful. What do you think of this approach?
-
name: Variables
description: |
How do we actually change the state of the game?
If you look back at the sprite instruction, you'll see a bunch of constants, or values that stay the same. What we really need is a way to change those values.
This is where the variable comes in. You can think of it as an empty box with a label that can store a value, like a number.
Let's make an example. Put the following at the start of your program (before draw):
`x = 0`
In this case, `x` is the box, and `0` is the value that goes inside of it. The `=` is a way to put the `0` into the box.
When Nico sees a variable in a place where it expects a value, it takes the contents of the box out and uses that instead. That's how you use variables in your code.
directions:
- |
Create a second variable that stores the `y` coordinate of the object and use that as well.
- |
Remove the extra `sprite` statements from your code.
- |
Make use of your new variables by changing the code.
-
name: "Updating Variables 1: Not the Sequel"
description: |
Variables become really useful when you have a value that needs to change, like our coordinates. Since our code now uses boxes instead of hard-coded values, we can actually change their contents, moving the player.
If we have a variable (**don't actually add this to your code!**):
```python
my_variable = 5
```
We can update it like so:
```python
my_variable = 6
```
directions:
- |
You've seen how to set a variable's value, but how do you change it? Talk to the person next to you about how you could add `1` to a variable (Don't actually write this yet!).
-
name: "Updating Variables 2: The Sequel"
description: |
Recall that the *game loop* had two phases: the first phase changes the state of the game, and the second phase draws. We've seen how to use the draw phase; now, we want to change the state of the game by updating variables.
Similarly to the drawing phase, to start the update phase we use
```python
def update():
```
Remember that this is **not part of the `draw` section, and so it should not be indented!** Everything indented and below `def draw():` is interpreted as part of the draw section, but now we want to start a new section.
directions:
- |
Now try increasing the value of `x` by 1 inside of the `update` section. Just like adding instructions to the draw section, you need to **indent your code** so Nico knows it's inside the `update` section. - | You've just encountered your first error! Don't panic and **try to figure out what it means**. Remember that errors shouldn't be scary, and are really just a way for your friendly computer to tell you what went wrong.
-
name: Variable Scope
description: |
You should have gotten this error:
```
local variable 'x' referenced before assignment
```
What this really means is that you tried to use a variable that hasn't been created yet. Why's that--didn't we create it at the start of the program? Well, we created the variables at the start of the program--outside of the `update` section. So, when Nico sees
```python
def update():
x = x + 1
```
Nico sees `x = x + 1` and tries to figure out whether you're *creating* or *updating* a variable called `x`. Nico looks inside the `update` section and doesn't find anything, since our first `x` was created outside the `update` section. So, Nico ignores it, and assumes that now you're creating a new variable.
And so when it goes to the right side, and reads `x + 1`, it freaks out: It thinks `x` is a new variable that lives inside the `update` section and is in the process of being created, and so when it sees you reference `x` in `x + 1`, that `x` doesn't exist yet!
directions:
- |
Talk to your partner about why this error happened to make sure you both understand it. If you are confused, that's ok— this is probably the most difficult concept in our lesson.
- |
Try to think about why Nico doesn't freak out when we use `x` and `y` in the `draw` section.
-
name: global, our savior
description: |
To help Nico understand what we're trying to do, we need to make sure that when it sees
```python
def update():
x = x + 1
```
it looks for `x` outside of the `update` section. We can do that by **marking `x` as being `global`**.
```python
def update():
global x
x = x + 1
```
Notice how that reminder goes in the beginning of the section, before any variables are introduced.
directions:
- |
Fix your code with `global`
- |
Run your code and see your sprite move!
- |
Adjust the speed of your sprite so they go at a pace you find acceptable.
- |
Your sprite is only moving right at the moment — can you figure out how to make them move diagonally?
-
name: You're Done!
description: |
Congratulations, you've finished this lesson! Feel free to go back to re-read some parts and move on to the second lesson when you're ready.
-
project: new
name: Player Input
description: How can we give the player control?
slides:
-
name: Recap
description: |
Welcome to lesson 2! Let's start out by practicing what you learned last lesson, so delete any code that you have. You'll need to know these core concepts:
* how to use Nico
* game loop / code sections
* instructions
* variables
directions:
- |
Write a program with a sprite that starts in the middle of the screen and moves left (you might need a little trial-and-error to get this right!).
-
name: Introduction
description: |
Our game is pretty cool, but it can only really be a game until we actually respond to some kind of input from the player.
directions:
- |
At the moment, our code changes `x` and `y` automatically — the player can't influence it. As always, when dealing with a challenge, it's best to think about the solution abstractly and then get more specific:
1. we want a way to move our sprite based on player input
2. we want to **only change the sprite's position** based on player input
3. we need to change the sprite's position only **when the player presses a key**
But before we write that code, we need a way to ask Nico if the player is pressing a key.
-
name: Asking Nico Questions
description: |
Asking a question in nico is really just another type of instruction — one that Nico actually answers, unlike something like `sprite`.
To show this, let's ask Nico if a player is pressing W.
```python
is_w_down = key_down('w')
```
In this case, `key_down` will turn into Nico's answer — either `true` (yes) or `false` (no) — and that answer will be stored in the variable `is_w_down`.
directions:
- |
How would Nico answer `key_down('w')` if the player is pressing W? How would Nico answer if the player is *not* pressing W? (Remember, Nico **doesn't know** the words "yes" or "no"!)
- |
Talk to your partner about where in your code you'd want to ask these questions (think back to the game loop!).
- |
Ask Nico if the player wants to move the sprite down (pressing S) and store that in a variable.
-
name: Using Nico's Answers
description: |
Unfortunately, our code is useless until we can actually do something with Nico's answers. To do this, we can use **if statements**.
What's an `if` statement? Let's find out!
directions:
- |
Delete the current automatic movement code in your `update` section. **Don't delete** the code asking Nico if a key is being pressed, though!
- |
Add this code to your `update` section. Remember to indent!
```python
global y
if is_w_down:
y = y - 1
```
- |
Discuss with your partner about why we need to use `global y` in our code.
- |
Still with your partner, make a guess about how `if` statements might work, and why the code under them is indented.
- |
See if you can figure out how to let the player move left.
- |
Once the player is able to move left, try to let them move in all four directions.
- |
As you may have noticed, the `if` statement is a way to run some instructions **only if** a variable is `true`. Now, try to get rid of the variables entirely, by asking Nico the question more directly.
-
name: Controlling the Player
description: |
The player has control now. But they have too much control! They can walk off screen!
As always, let's start out by thinking about this problem abstractly:
1. we want to prevent the player from going offscreen
2. we want to **bring the player back** when they go offscreen
3. we want to bring the player back when ?
directions:
- |
We can ask Nico questions about numbers. With your partner, figure out what the values of `result_1`, `result_2`, and `result_3` be in the below sample.
```python
x = 51
result_1 = x < 5
result_2 = x >= 51
result_3 = (x - 1) == 50
```
- |
With your partner, figure out how to test if the player has gone offscreen *to the left.* (Hint: you'll need to use an `if` statement and a number question!)
- |
Make sure that the player can't exit the screen to the right.
- |
Prevent the player from moving off at the top or bottom of the screen. Now, they can't escape, mwahaha!
-
project: old
name: The Map
description: The empty white background is boring... let's build a world to explore!
slides:
-
name: Using the Tile View
description: |
We've seen the game, editor, and sprite views. Now, let's check out tile!
directions:
- |
Draw some terrain sprites from an **overhead view** (think of how a desert or grassland would look from above).
- |
Head to the tile view. Use the sprite selector at the very bottom to choose a terrain and start drawing a map!
- |
Draw a flower and add it to your new world 🌺 (It doesn't have to be a flower, but we'll be calling it a flower throughout the rest of this lesson, so just keep that in mind.)
-
name: Drawing the World
description: |
Now that you've drawn a world, let's get it on screen!
directions:
- |
The `tilemap` instruction is used to draw the world onto the screen. With your partner, figure out how to use this instruction to draw your game's world. Make sure you can still see the player!
- |
You may have noticed that the order of the draw instructions matters (if you haven't, try changing it around!). Talk to your partner about why this could be happening.
-
name: Flowers
description: |
You've drawn a flower and added it to your world. Now, let's let the player collect them!
Again, we should approach this from a high level.
1. We want the player to collect flowers.
2. We need to detect when the player is touching a flower.
3. We need to detect when the player is touching a flower, *and then* give them that flower.
4. We need to detect when the player is touching a flower, and then give them that flower, *and finally* remove the flower from the world.
directions:
- |
Add some flowers to your world if you haven't already.
- |
Our first objective is figuring out if a player is touching a flower. To do this, we'll need a new type of question: We need to ask Nico if something is a flower. To do that, we need to use sprite numbers.
```python
get_tile(x, y)
```
As with `key_down`, this instruction causes Nico to give something to us — in this case, that something is the sprite number of the tile at position `x, y`. For example, if I have a flower tile at `3, 4` and that flower tile is actually sprite `5`, then if I ask Nico `get_tile(3, 4)`, Nico will answer `5`.
Talk to your partner about how you could use this to figure out whether or not a player is touching a flower.
- |
Once you know a player is on a flower tile, we need to do something with that information. Create a variable called `flowers_collected` and increase it by `1` whenever a player is on a flower.
- |
We have `flowers_collected`, but the player has no way of seeing it's value!
To do this, let's use the `text` instruction. The `text` instruction just writes something onto the screen for us. The instruction `text(17, 0, 0)` will print the number `17` at the coordinates `(0, 0)`, for example.
With your partner, discuss how to use `text` to display the total flowers collected.
Do you notice anything wacky happening with the counter?
-
name: Flower Counters, Fixed
description: |
At the moment, our flower counter just keeps going up and up! We need to remove these flowers from the world so a player can't just keep collecting the same flower over and over again.
To do this, we can use the `change_tile` instruction.
directions:
- |
This is a good place to introduce the magical ✨ Nico Booklet ✨. The Nico Booklet knows everything about every instruction Nico has, so you don't have to!
To figure out how to use the `change_tile` instruction, open the Nico Booklet by pressing the little book icon at the right side of the editor. Then, click on the "Tilemap" section, and look for the `change_tile` instruction.
- |
Use `change_tile` to remove a flower once the player has collected it.
-
name: Flower Counters, Leveled Up
description: |
Let's reward the player for collecting every flower by displaying a little "Congratulations!" message.
directions:
- |
Count how many flowers are in your game. Create a new variable, called `total_flowers`, that stores this number.
But wait! That variable wouldn't change — why can't we just write the number in our program?
Well, imagine a week later you're looking at your code and you see some random number in your program. "What in the heck does that mean?", your future self thinks. This way, if they see the variable `total_flowers` they'll know immediately what it means.
Also, imagine you use the `total_flowers` number multiple times in your program. If you ever increase the total number of flowers, you'll have to change this number in a bunch of different spots! And what happens if you forget to change one of those spots?
- |
Once a player has collected all the flowers, talk with with your partner about how to show a special "Congratulations!" message.
To display a message like "Congratulations!", we need to use **strings**. A **string** is just some text, and you can create one by surround your text in little quotes--so, you'd use `text('Congratulations!', 0, 0)`.
Another tip: With `if` statements, you can use `else`. An `else` part of an `if` statement contains code that runs whenever the `if` statement *doesn't* run.
As an example, in the `if` statement
```python
if dogs > 34:
text('Woof!', 0, 0)
else:
text('Not enough dogs!', 0, 0)
```
If we have more than 34 dogs, then Nico will print Woof! Otherwise, Nico will tell us "Not enough dogs!"
- |
Remember the `key_down` instruction? Recall that we used it with quotes.
```python
key_down('w')
```
Why did we use quotes around the w?
- |
Let's make our flower counter a little prettier. While we know what the little number in the top left corner of our screen means, a random person playing your game might not! So, let's change the flower counter from just being a number to saying "You have _ flowers!" To do this, we'll need to combine strings. To combine strings, we just use the + operator. So, "You" + " have" would be "You have".
Try combining 'You have', flowers_collected, and 'flowers!' into one big string and printing it!
Does Nico have any errors?
- |
If you try using
```python
text('You have' + flowers_collected + 'flowers!', 0, 0)
```
you may notice a problem--Nico gives an error! Let's look at that error.
```python
TypeError: cannot concatenate 'str' and 'int' objects
```
In this error, "concatenate" is just a fancy word for "string addition," 'str' is short for string, and 'int' is short for integer (number). What Nico is telling us is that it doesn't know how to add a string and a number--they are different kinds, or types, of values (hence the name `TypeError`).
To solve this, use the `str` instruction to convert `flowers_collected` into a string. For example, `str(flowers_collected)` would create a string whose content is the number inside `flowers_collected`--so if `flowers_collected` contained the number `17`, then `str(flowers_collected)` would be the string `'17'`.
- |
You might notice that the spacing around the number is a bit awkward. This is because we have no spaces! `'Hello' + 'Dog'` is `'HelloDog'`, not `'Hello Dog'`. To fix this, add some spaces to the two strings around `flowers_collected`. Where should the spaces go?
-
name: Biodiversity University
description: |
Let's add some diversity to our vegetation!
directions:
- |
Draw some new kinds of plants and add them to your world.
- |
Currently, to check if the player is on a flower, we check if the tile their on is the flower tile. But if we add more flower tiles, then we'll need to have a whole bunch of `if` statements in our code, and we'll need to change the code whenever we add more!
This is where flags come in. A flag is like a switch that you can turn on to indicate something about a sprite. Keep in mind that flags are set on the sprite level, not the tile level — this means that if you turn on a flag for your flower sprite, all of your flower tiles will have that flag!
Mark flag `0` for all of your plant sprites to tell Nico that they can be picked up by the player.
- |
Use the `has_flag` instruction to help the player pick up all of your plants! (Remember to use the ✨ Nico Booklet ✨ if you need help.)
-
name: The Return of Flower Medusa
description: |
Flower Medusa is attacking! To save yourself, you convince her that turning *every plant in the world* into stone is way more fun than dealing with a puny human.
directions:
- |
Edit your plants to look like stones.
- |
Oh no! This means that the player can no longer walk freely around the map. Your challenge is to figure out how to prevent the player from walking into the stone plants.
As we've been doing, you should first think about this issue from a high level, and then worry about the actual code.
-
project: old
name: Tricky Flowers
description: |
Let's add a bit more WOOF to our flower game!
slides:
-
name: An Entire Garden!
description: |
For our next project we'll need at least 5 different parts of plants, so make sure to draw those if you don't have them already.
In our previous code, flag `0` meant "this is a flower." Now, let's change the meaning of flag `0` to mean "this is some vegetation"
directions:
- |
After creating your new vegetation, give each of them new types of vegetation flag `0`. This way, all your existing flower detection code will work.
- |
Give each type of vegetation its own flag: Flowers will be flag `1`, tomatoes will be flag `2`, apples will be flag `3`, ... whatever. Now, Nico will be able to tell them apart!
Note that you can have two flags on at the same time: So flowers will have both flags `0` and `1`, tomatoes both `0` and `2`, ...
-
name: A New Way to Play
description: |
Currently, you win by collecting every single piece of vegetation.
Let's shake this up: Now, to win you need to collection *one of each type* of vegetation.
directions:
- |
We'll need a way to keep track of which types of vegetation we've already collected. To do this, we'll use a **list.**
Below, you'll see a few examples of lists. What do you think the lists contain? How do lists `ayy` and `bee` differ?
```python
ayy = [1, 2, 3]
bee = [3, 2, 1]
cee = [4.5, 2 + 2, -1]
```
- |
Let's create a variable, called `vegetation_collected`, that will store the types of vegetation you've collected.
One problem: At the beginning of the game, the player has no vegetation, and so the list will be empty. How might you represent an empty list?
-
name: Using our List
description: |
Whenever a player collects a plant, we should check if this is a new type of plant. If it is a new type of plant, we should add it to the list of types of plants they've collected.
So, we need a way to 1. figure out if something is in a list and 2. add something to a list.
directions:
- |
To check if something is in a list, we can use the instruction `in`. What do you think the example below does?
```python
cool_numbers = [6, 17, 289]
if your_number in cool_numbers:
text('I like your number!', 0, 0)
```
- |
To add something to a list, we use the instruction `append`. What will the value of `good_dogs` be after we run the code below?
```python
good_dogs = ['Jack', 'Chrissy']
good_dogs.append('Princess')
```
- |
Using `in` and `append`, update your plant code to keep track of which types of vegetation you've collected.
-
name: Winning!
description: |
To win the game, a player needs to collect one of each type of vegetation. Let's implement this!
directions:
- |
The instruction `len` can be used to check the length of a string, like below. Can you use `len` to figure out when the player wins?
```python
good_dogs = ['Jack', 'Chrissy', 'Princess']
this_is_three = len(good_dogs)
```
-
project: new
name: Reign of the Chicken
description: |
Our player is lonely... let's give 'em a pet chicken!
slides:
-
name: Chicken
description: |
Let's add a chicken to accompany the player!
Instead of the player controlling the chicken, the chicken will be controlled by Nico. Let's figure out how to do that!
directions:
- |
Draw a chicken (or dog, or rock, or anything else!) sprite!
- |
Make the chicken move in some direction (think back to the first lesson).
- |
Right now, our chicken can escape from the screen. Make sure that this doesn't happen by moving it in the opposite direction when it hits an edge.
- |
Make your chicken move diagonally!
-
name: Non-Robotic Chickens
description: |
Right now our chicken's movement is very predictable - let's change that by adding some randomness! In order to do that, we need to use some extra code. This code is in what's called a _package_, which is just a collection of instructions that aren't included by default.
```python
import random
```
This instruction (usually placed at the top of a program) tells Nico to `import` this package into your program (aka, bringing the code in).
directions:
- |
Add the `import random` statement to the top of your program.
- |
To generate a random number between `0` and `5`, we use the instruction `random.randint(0, 5)`. This will output either `0`, `1`, `2`, `3`, `4`, or `5` at random.
How can you use `random.randint(a, b)` to create random chicken movement? Try it out until your chickens move all smooth.
-
name: Wow!
description: |
Congratulations! You just solved a pretty complicated problem completely on your own - you're on your way to becoming a coding wizard!
directions:
- |
Tweak your code to make sure it's as perfect as it can be.