-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathCh4_Agrar.html
More file actions
1159 lines (1142 loc) · 58.7 KB
/
Ch4_Agrar.html
File metadata and controls
1159 lines (1142 loc) · 58.7 KB
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
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<title>JavaScript: Ch4 Agrar</title>
<meta name="title" content="Variations on a Theme: JavaScript: Ch4 Agrar">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta charset="UTF-8">
<meta name="description" content="An object-oriented Introduction">
<meta name="keywords" content="JavaScript,object orientation,introduction">
<meta name="author" content="Ralph P. Lano">
<meta name="robots" content="index,follow">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="book.css">
</head>
<body>
<center>
<div id="wrap">
<ul class="sidenav">
<p><a href="../index.html">Variations on a Theme</a><a href="index.html">JavaScript</a></p>
<li><a href="Ch1_Karel.html">Karel</a></li>
<li><a href="Ch2_Graphics.html">Graphics</a></li>
<li><a href="Ch3_Console.html">Console</a></li>
<li><a href="Ch4_Agrar.html">Agrar</a></li>
<li><a href="Ch5_MindReader.html">MindReader</a></li>
<li><a href="Ch6_Swing.html">Swing</a></li>
<li><a href="Ch7_Asteroids.html">Asteroids</a></li>
<li><a href="Ch8_Stocks.html">Stocks</a></li>
<li><a href="index.html"> </a></li>
<li><a href="AppA_Primer.html">Primer</a></li>
<li><a href="AppB_Libraries.html">Libraries</a></li>
<li><a href="AppC_Ideas.html">Ideas</a></li>
</ul>
<div class="content">
<p>
<img alt="" src="img/8380f6ab-e1dc-4095-96f6-e3aa733122d7.png" style="display: block; margin-left: auto; margin-right: auto; width: 233px; height: 223px;" /></p>
<h1>
Agrar</h1>
<p>
In the last chapter we have neglected the top-down approach at the expense of variables, but in this chapter we will see how to get back to the top-down approach with functions. And we will write our first animations and games. It promises to get interesting.</p>
<p>
.</p>
<h2>
Functions</h2>
<p>
We have known functions for a quite a some time now. With Karel we called them commands, e.g. move(), turnLeft() and frontIsClear(). Also in graphics programs we used them, at that time we called them messages that we send to a GRect, e.g. setColor() and setFilled(). Even with console programs we had them, e.g. readInt() and println(). So nothing new.</p>
<p>
With Karel there was the cool possibility to create new commands, like turnRight() or moveToWall(). That's what we did back then:</p>
<pre style="margin-left: 40px;">
function turnRight() {
turnLeft();
turnLeft();
turnLeft();
}
</pre>
<p>
Wouldn't it have been cool if we could have had the following new command in our Archery program?</p>
<pre style="margin-left: 40px;">
function drawCircle( radius, color ) {
...
}
</pre>
<p>
Or for our Wall program, a function like the following would have been quite practical:</p>
<pre style="margin-left: 40px;">
function drawRowOfNBricks( numberOfBricks ) {
...
}
</pre>
<p>
Well, the nice thing is, this actually is possible!</p>
<p>
<strong>SEP: Functions always do something, they convey an action, so functions should always be verbs.</strong></p>
<p>
.</p>
<h2>
Defining Functions</h2>
<p>
Creating a new function is as easy as teaching Karel new commands. The general syntax of a function declaration is as follows:</p>
<pre style="margin-left: 40px;">
function name( parameters ) {
... body...
}</pre>
<p>
where we mean by</p>
<ul>
<li>
<strong>name:</strong> the name of the function, here the same rules apply as for variables and function names should always be written in lower case,</li>
<li>
<strong>parameters:</strong> parameters are new, they did not exist with Karel, but they are very practical as we will see soon.</li>
</ul>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch4_Agrar/archery" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/archery.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
Exercise: Archery</h2>
<p>
Let's take another look at our Archery program. But now we try using the drawCircle(radius, color) function. We will find that the code becomes much shorter and also more readable.</p>
<pre style="margin-left: 40px;">
function drawCircle(radius, color) {
let ring = new GOval(2 * radius, 2 * radius);
ring.setColor(color);
ring.setFilled(true);
let x = 50 + 72 - radius;
add(ring, x + 25, x - 48);
}</pre>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch4_Agrar/wall" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/wall.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
Exercise: Wall</h2>
<p>
Let's try the Wall program again, using the help of functions. We want to build a wall consisting of 15 bricks (GRect). However, we want to use the function</p>
<pre style="margin-left: 40px;">
function drawRowOfNBricks(j) {
let x = 70; // beginning x position of wall
let y = 108 + j * 15; // beginning y position of wall
for (let i = 0; i < 5; i++) {
let brick = new GRect(30, 15);
add(brick, x, y);
x = x + 30;
}
}
</pre>
<p>
Question: Does the function above contain magic numbers? Can we change that?</p>
<p>
.</p>
<h2>
Return Value</h2>
<p>
So far we have only seen functions that return nothing. But there are also functions that give something back. Most of the time the functions calculate something and return the result as a return value. A nice example is the following function that returns how many inches there are in a given number of feet:</p>
<pre style="margin-left: 40px;">
function feetToInches(feet) {
let inches = 12 * feet;
return inches;
}</pre>
<p>
We can use this function in a console program.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch4_Agrar/convertFeetToInches" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/convertFeetToInches.png" style="width: 220px; display: block; height: 124px;" />Try it</a></div>
<h2>
Exercise: ConvertFeetToInches</h2>
<p>
We want to write a small console program that converts feet to inches. It asks the user for the number of feet using readDouble() and then calls our feetToInches() function and returns the result in the console window.</p>
<pre style="margin-left: 40px;">
let feet = await readDouble("Enter feet: ");
let inches = <span style="color:#0000ff;">feetToInches</span>(feet);
println(feet + " feet are " + inches + " inches.");
</pre>
<p>
If we look closely, we see that we use the feetToInches() function in the same way as the readInt() or println() functions. The only difference is that we wrote it ourselves.</p>
<p>
.</p>
<h2>
Objects as Return Value</h2>
<p>
We can not only return numbers, but every possible data type, including GOvals for instance. The following function generates a colored filled circle with a given radius r at positions x and y:</p>
<pre style="margin-left: 40px;">
function createFilledCircle(x, y, r, color) {
let circle = new GOval(x-r, y-r, 2*r, 2*r);
circle.setColor(color);
circle.setFilled(true);
return circle;
}</pre>
<p>
All we have to do now is add it to our Archery program.</p>
<p>
.</p>
<h2>
Local Variables</h2>
<p>
The variables we have been dealing with so far are called local variables. Local with respect to a function. This means that variables are only visible inside the function in which they were declared, outside, that is, in other functions they are not visible or accessible. Let's look at an example:</p>
<pre style="margin-left: 40px;">
async function setup() {
createConsole();
let feet = await readDouble("Enter feet: ");
println(feet);
}
function feetToInches() {
let inches = 42;
println(inches);
}</pre>
<p>
In this example there is a variable called feet that exists inside the function setup() and a variable inches that exists in the function feetToInches(). If we try to access the variable feet in the function feetToInches(), then this is not possible. The same applies the other way round. The variables are therefore only visible locally in their respective functions.</p>
<p>
How can we pass variables from one function to another function? That's what parameters are for:</p>
<pre style="margin-left: 40px;">
function feetToInches(feet) {
let inches = 12 * feet;
println(inches);
}</pre>
<p>
We pass variables from one function to another using these parameters.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch4_Agrar/localVariables" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/localVariables.png" style="width: 220px; height: 130px; display: block;" />Try it</a></div>
<p>
However, only a copy of the variable is passed. To see this, let's have a quick look at the following program:</p>
<pre style="margin-left: 40px;">
async function setup() {
createConsole();
let <span style="color:#0000ff;">feet</span> = await readDouble("Enter feet: ");
feetToInches(<span style="color:#0000ff;">feet</span>);
println(<span style="color:#0000ff;">feet</span>);
}
function feetToInches(<span style="color:#ff0000;">feet</span>) {
<span style="color:#ff0000;">feet</span> = 42;
}
</pre>
<p>
First we ask the user to give us a value, e.g. '12'. We pass this value to the feetToInches() function. Now inside that function, we reassign feet to a new value, say feet = 42. But this reassignment only applies to the copy, the original remains unchanged, as we see when we look at what is displayed in the console window. The original feet still has the value '12', i.e., it was not changed.</p>
<p>
That's why it doesn't really matter whether we call the red feet also feet or give it another name:</p>
<pre style="margin-left: 40px;">
async function setup() {
createConsole();
let <span style="color:#0000ff;">feet</span> = await readDouble("Enter feet: ");
feetToInches(<span style="color:#0000ff;">feet</span>);
println(<span style="color:#0000ff;">feet</span>);
}
function feetToInches(<span style="color:#ff0000;">fritz</span>) {
<span style="color:#ff0000;">fritz</span> = 42;
}</pre>
<p>
This will hopefully make clear why we need return values. Because if something is calculated in the function feetToInches(), then this is only visible locally inside that function. To get it back out into the calling function, we need the return value.</p>
<p>
As a note, a function can have several parameters, but it can only have one return value.</p>
<p>
.</p>
<h2>
Animation</h2>
<p>
Now we have functions in our toolbox. That's great, because we can start doing really cool things with them, namely animations and games. We'll start with animations. But for that we need one more thing.</p>
<p>
.</p>
<h2>
GObject</h2>
<p>
Let's remember the graphics classes we know already: GRect, GOval, GLine, GImage, GLabel, GArc and GPolygon. These classes are not completely independent of each other, they even have something in common: they are all GObjects.</p>
<p>
<img alt="" src="img/ACM_Hierarchy.png" style="margin-left: 10px; margin-right: 10px; width: 438px; height: 100px;" /></p>
<p>
The class GObject is also called a parent class. We say that the child classes such as GRect and GOval inherit from their parent class. What do they inherit? The functions of the parent class. That's super convenient, as we'll see. But first let's take a look at those inherited functions:</p>
<ul>
<li>
<strong>setLocation(x, y):</strong> move the GObject to the position x, y.</li>
<li>
<strong>move(dx, dy):</strong> move the GObject by dx and dy.</li>
<li>
<strong>getX():</strong> returns the x coordinate of the GObject.</li>
<li>
<strong>getY():</strong> returns the y coordinate of the GObject.</li>
<li>
<strong>getWidth():</strong> returns the width of the GObject.</li>
<li>
<strong>getHeight():</strong> returns the height of the GObject.</li>
<li>
<strong>setColor(col):</strong> changes the color of the GObject.</li>
</ul>
<p>
All the graphic classes we've seen so far have these functions.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch4_Agrar/billiards" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/billiards.png" style="width: 200px; height: 200px; display: block;" />Try it</a></div>
<h2>
Animations using the Game Loop</h2>
<p>
For our first animation we choose billiard: We want a black ball to move across a green table and bounce back from the sides.</p>
<p>
Every animation has a game loop. The game loop is our <em>draw()</em> function, which we have been ignoring up to this point:</p>
<pre style="margin-left: 40px;">
<span style="color:#ff0000;">let ball;</span>
function setup() {
createCanvas(300, 300);
<span style="color:#0000ff;">frameRate(25)</span>;
setBackground(Color.GREEN);
ball = new GOval(20, 20);
ball.setFilled(true);
add(ball, 150, 150);
}
function <span style="color:#0000ff;">draw()</span> {
ball.move(4, -3);
update();
}</pre>
<p>
Everything that has to do with the setup and initialization goes in the setup() function. Then the game loop starts: if we set the frame rate to 25, then the draw() function is called 25 times per second, or every 40 ms. </p>
<p>
Let us go through the functions in detail. In the setup() function we set the size of the window, then we set the framerate to 25 and the background color to green. Finally, we create a ball:</p>
<pre style="margin-left: 40px;">
function setup() {
createCanvas(300, 300);
<span style="color:#0000ff;">frameRate(25)</span>;
setBackground(Color.GREEN);
ball = new GOval(20, 20);
ball.setFilled(true);
add(ball, 150, 150);
}</pre>
<p>
What should stand out here is that it is "ball =" and not "let ball =". More on that in a moment. The next function is the draw() function:</p>
<pre style="margin-left: 40px;">
function draw() {
ball.move(4, -3);
update();
}</pre>
<p>
We simply tell the ball to move. And the update() we need for the drawing to happen.</p>
<p>
So what is the problem with the ball? Well, remember local variables: a variable declared inside a function is only valid in that function. So if we declare ball inside setup(), then it is only available inside setup(), but not draw(). If we declare it in draw(), then we create 25 balls per second, because draw() is called 25 time per second. But we do not need 25 or more balls, we need only one. We need one that is shared by both functions, or that can be accessed from within both functions. The solution is simple: just declare the ball outside the functions. This is what we call a <em>global</em> variable.</p>
<p>
.</p>
<h2>
Exercise: Billiards</h2>
<p>
Once we know about global variables, we might as well us them. We need a ball and its velocities, hence we declare them as global variables:</p>
<pre style="margin-left: 40px;">
// global variables
let ball;
let vx = 4;
let vy = -3;</pre>
<p>
The setup() function stays the same as above. But we want to change the draw() function a little. First, we want to return to our top-down approach:</p>
<pre style="margin-left: 40px;">
function draw() {
moveBall();
checkForCollisionsWithWall();
update();
}</pre>
<p>
Meaning we introduce two functions, called moveBall() and checkForCollisionsWithWall(). The first one is easy:</p>
<pre style="margin-left: 40px;">
function moveBall() {
ball.move(vx, vy);
}</pre>
<p>
The second one is a little more complicated:</p>
<pre style="margin-left: 40px;">
function checkForCollisionsWithWall() {
let x = ball.getX();
let y = ball.getY();
if ((x < 0) || (x > WIDTH)) {
vx = -vx;
}
if ((y < 0) || (y > HEIGHT)) {
vy = -vy;
}
}</pre>
<p>
We get the current x- and y-position of the ball and test if it is inside the playing field. If not, we change the sign of the speed, i.e., the ball turns around. If you want, you could reduce the speed a little with every collision, but we don't.</p>
<p>
Let's talk a little more about ball, vx and vy. So far we only know about local variables. The problem with local variables is that they are only valid within one function. In our billiard example, however, we need the ball in three functions: the setup(), the moveBall(), and the checkForCollisionsWithWall() functions. Obviously we cannot use a local variable for the ball (and also vx and vy). Instead, we use a global variable. Global variables are declared at the beginning of a class, before the setup() function, and most importantly, outside the setup() function (or any other function). The advantage of global variables is that they are accessible in any function. However, global variables are a little dangerous, as we will see later, hence the following SEP.</p>
<p>
<strong>SEP: When possible try to use local variables.</strong></p>
<p>
.</p>
<h2>
Events</h2>
<p>
So animations are not really that difficult. Let's move on to games: our games should be controllable with the mouse. To do this, we have to tell our program that we are interested in mouse events such as whether the mouse button was pressed or the mouse was moved. In code all we have to do add the mousePressed() function to our program:</p>
<pre style="margin-left: 40px;">
function mousePressed() {
let x = mouseX;
let y = mouseY;
...
}</pre>
<p>
The variables mouseX and mouseY contain the x- and y-position of the mouse. Similarily, if we want to find out if the mouse has moved, we implement the mouseMoved() function. Of course we can also use both. On mobile devices, like Android or iPad, the corresponding functions are called touchPressed() or touchMoved().</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch4_Agrar/builder" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/builder.png" style="width: 200px; height: 200px; display: block;" />Try it</a></div>
<h2>
Exercise: Builder</h2>
<p>
Builder is inspired by Lego: we have small blocks and we can place them anywhere on the screen by clicking with the mouse on the position where the block should go. The program code for this is totally simple. The setup() and draw() functions do not really do anything:</p>
<pre style="margin-left: 40px;">
function setup() {
createCanvas(WIDTH, HEIGHT);
frameRate(5);
}
function draw() {
update();
}</pre>
<p>
But in the mousePressed() function all the action happens:</p>
<pre style="margin-left: 40px;">
function mousePressed() {
let x = mouseX;
let y = mouseY;
x = Math.trunc(x / BLOCK_SIZE) * BLOCK_SIZE;
y = Math.trunc(y / BLOCK_SIZE) * BLOCK_SIZE;
let block = new GRect(BLOCK_SIZE, BLOCK_SIZE);
block.setColor(Color.RED);
block.setFilled(true);
block.setFillColor(Color.YELLOW);
add(block, x, y);
}</pre>
<p>
To get the x- and y-position of the mouse we use the mouseX and mouseY variables. Once we have those, we create a new GRect and place it at the current mouse position.</p>
<p>
With a little trick, we can "quantize" the position of the blocks:</p>
<pre style="margin-left: 40px;">
x = Math.trunc(x / BLOCK_SIZE) * BLOCK_SIZE;</pre>
<p>
This is a trick you will see again and again.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch4_Agrar/mouseTracker" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/mouseTracker.png" style="width: 200px; height: 133px; display: block;" />Try it</a></div>
<h2>
Exercise: MouseTracker</h2>
<p>
Next we want to track the mouse movement. We start again with the setup() function:</p>
<pre style="margin-left: 40px;">
// global variables
let lbl;
function setup() {
createCanvas(300, 200);
frameRate(25);
lbl = new GLabel("");
lbl.setFont('Arial');
lbl.setFontSize(20);
add(lbl, 0, 0);
}</pre>
<p>
To display the position of the mouse we want to use a GLabel called lbl. It is an global variable and must be initialized and added to our canvas. After that we tell our program again that we want to listen to mouse events. In this example we want to know if the mouse has moved, so we overwrite the mouseMoved() function:</p>
<pre style="margin-left: 40px;">
function mouseMoved() {
let x = mouseX;
let y = mouseY;
lbl.setLabel("x=" + x + ",y=" + y);
lbl.setLocation(x, y);
}</pre>
<p>
We get the x and y position of the mouse, change the text of the label with the setLabel() function, and move the label to the mouse position with the setLocation() function. And that's it.</p>
<p>
.</p>
<h2>
RandomGenerator</h2>
<p>
For many games we need random numbers. To get random numbers we use the class RandomGenerator. This class does not only generate random numbers, but it can also generate random colors. The code</p>
<pre style="margin-left: 40px;">
let rgen = new RandomGenerator();
...
let width = rgen.nextDouble(0, 150);
let col = rgen.nextColor()
</pre>
<p>
shows how to generate random numbers and random colors. Two other useful functions are <em>nextInt(low,high)</em> and <em>nextBoolean()</em>.</p>
<p>
.</p>
<h2>
Canvas</h2>
<p>
At this point it makes sense to talk a little more about our canvas. We have been using it all the time, when we were adding our GObjects to our programs, like</p>
<pre style="margin-left: 40px;">
add(lisa, 70, 50);</pre>
<p>
The question we should have asked ourselves back then was: where to do we add those GRects and GOvals? The answer is of course: to the canvas. The canvas is our felt board from kindergarten. If we can add something, the next question is, can we also remove something? Or are there other things we can do with the canvas? Well, the following lists the things we can do with and to the canvas:</p>
<ul>
<li>
<strong>add(object):</strong> add a GObject to the canvas.</li>
<li>
<strong>add(object, x, y):</strong> add a GObject to the canvas at position x, y.</li>
<li>
<strong>addAtEnd(object, x, y):</strong> add a GObject to the canvas at position x, y.</li>
<li>
<strong>remove(object):</strong> remove the GObject from the canvas.</li>
<li>
<strong>removeAll():</strong> remove all GObjects from the canvas.</li>
<li>
<strong>sendToFront():</strong> bring the GObject to the front (z-order).</li>
<li>
<strong>sendToBack():</strong> send the GObject to the back (z-order).</li>
<li>
<strong>getElementAt(x, y):</strong> return the first GObject at the position x, y, if there is one.</li>
<li>
<strong>getElementsAt(x, y):</strong> return all GObjects at the position x, y, if there is any.</li>
<li>
<strong>setBackground(c):</strong> change the background color of the canvas.</li>
</ul>
<p>
.</p>
<hr />
<h1>
Review</h1>
<p>
It may seem that we didn't do all that much in this chapter. But that's not true at all: as we will see in the projects, we can already program really cool things. We now know what</p>
<ul>
<li>
functions,</li>
<li>
parameters,</li>
<li>
return values,</li>
<li>
and local variables</li>
</ul>
<p>
are. In addition, we learned more about</p>
<ul>
<li>
GObjects,</li>
<li>
the canvas,</li>
<li>
and the RandomGenerator.</li>
</ul>
<p>
The most important thing in this chapter however was that we can do animations using the game loop and listen to mouse events.</p>
<p>
.</p>
<hr />
<h1>
Projects</h1>
<p>
The projects in this chapter are real fun. Let's get started.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/stairs" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/stairs.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
Stairs</h2>
<p>
Our first project is a small staircase. The problem is very similar to the Wall problem. Therefore, it makes sense to adopt the top-down approach here as well - write a function called drawRowOfNBricks( n ). We should also be careful not to use magic numbers, only constants.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/pyramid" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/pyramid.png" style="width: 200px; height: 133px; display: block;" />Try it</a></div>
<h2>
Pyramid</h2>
<p>
The pyramid is almost identical to the stairs. The only difference is that the steps are always offset by half a stone. The pyramid should have nine stones in the bottom row. For this, we need to change the code from the last example only slightly.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/chessBoard" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/chessBoard.png" style="width: 200px; height: 200px; display: block;" />Try it</a></div>
<h2>
ChessBoard</h2>
<p>
Let's get back to our chessboard. But this time we want to use the top-down approach. There are several approaches, but one would be to declare a function called drawOneRow(). Here you have to consider exactly which parameters you pass to the function. You could also have two functions, one for even lines and one for odd lines.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/rgbColor" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/rgbColor.png" style="width: 200px; height: 133px; display: block;" />Try it</a></div>
<h2>
RGBColor</h2>
<p>
We have already drawn the rainbow, but still rather "manually". Now we want to draw the HSV color palette [5]. In JavaScript you can create any color using</p>
<pre style="margin-left: 40px;">
let col = color(r, g, b);</pre>
<p>
where the variables r, g, and b each represent the red, green and blue components. These must have values between 0 and 255. So for instance, red color can be made like this</p>
<pre style="margin-left: 40px;">
let colRed = color(255, 0, 0);</pre>
<p>
If we look closely at the colors in the HSV color palette, we notice that it starts with red, then yellow, green, cyan, blue, magenta, returning to red. Hence, there are a total of six color transitions. The first transition from red to yellow could be reached with the following lines:</p>
<pre style="margin-left: 40px;">
for (int x = 0; x < 255; x++) {
let col = color(255, x, 0);
let line = new GLine(x, 0, x, HEIGHT);
line.setColor(col);
add(line);
}</pre>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/moire" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/moire.png" style="width: 200px; height: 200px; display: block;" />Try it</a></div>
<h2>
Moire</h2>
<p>
The Moiré effect [6] is usually rather undesirable, but it can also be quite pretty. First we divide the length and width into equal parts, e.g. eleven parts. Then we draw a line from each point above to each point below and the same from left to right. To get a feeling for how this works, take a piece of paper and try to draw it by hand. It comes down to two nested for loops.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/randomSquares" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/randomSquares.png" style="width: 200px; height: 200px; display: block;" />Try it</a></div>
<h2>
RandomSquares</h2>
<p>
Let's continue our artistic activities. We want to draw rectangles of different colors of random size and position. Of course we use the random generator. First we set a random width and height for a GRect. Width and height should perhaps not be too large or too small. Then we give the rectangle a random color with</p>
<pre style="margin-left: 40px;">
rect.setFillColor(rgen.nextColor());</pre>
<p>
Finally, we place the GRect at a random x and y position. We place this code in the draw() function and maybe change the frame rate to 10 or less.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/twinkleTwinkle" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/twinkleTwinkle.png" style="width: 200px; height: 134px; display: block;" />Try it</a></div>
<h2>
TwinkleTwinkle</h2>
<p>
TwinkleTwinkle is about generating a random night sky. The stars are GOvals with a random size between 1 and 4 pixels. They're distributed randomly on the canvas. It makes sense to first set the background to black using</p>
<pre style="margin-left: 40px;">
setBackground(Color.BLACK);</pre>
<p>
The whole thing then comes into the game loop and we wait perhaps 500 ms until we draw the next star.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/confetti" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/confetti.png" style="width: 200px; height: 133px; display: block;" />Try it</a></div>
<h2>
Confetti</h2>
<p>
We all love confetti. They are very easy to make, either with a hole punch or with GOvals. The confetti can all be the same size (e.g. 20 pixels), but do not have to be. They have different colors, again a case for the random generator. And of course the position of the confetti should be random, and the whole thing again runs in the game loop, that is the draw() function.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/animatedPacman" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/animatedPacman.png" style="width: 200px; height: 133px; display: block;" />Try it</a></div>
<h2>
AnimatedPacman</h2>
<p>
We painted our first PacMan two chapters ago. But it was quite static. We want to animate PacMan now. It is useful to know that GArcs have the following two commands:</p>
<pre style="margin-left: 40px;">
pacman.setStartAngle(angle);
pacman.setSweepAngle(360 - 2 * angle);</pre>
<p>
If we now let the angle variable vary between 0 and 40, and do this every 50 ms, then it appears as if PacMan is animated.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/trafficLight" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/trafficLight2.png" style="width: 200px; height: 133px; display: block;" />Try it</a></div>
<h2>
TrafficLight</h2>
<p>
We also drew the traffic light two chapters ago. Now let's animate the traffic light. The traffic light starts with red, then turns to red-yellow, followed by green. Finally it goes via yellow back to red. The transition should take a second. For example, you could have global variables for the lights, and then use</p>
<pre style="margin-left: 40px;">
if (currentLight == 0) {
redLight.setFillColor(Color.RED);
yellowLight.setFillColor(Color.BLACK);
greenLight.setFillColor(Color.BLACK);
} ...
</pre>
<p>
to turn the lights on and off. Next you have to think about how to switch between the different states. This can be done very cleverly with the remainder operator %:</p>
<pre style="margin-left: 40px;">
currentLight++;
currentLight = currentLight % 3;</pre>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/analogClock" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/analogClock.png" style="width: 200px; height: 200px; display: block;" />Try it</a></div>
<h2>
AnalogClock</h2>
<p>
For our clock, we use a GOval for the face and GLabels for the digits. We do this in the setup() function. We could set the GLabels by hand, or calculate their position by means of sine and cosine. Both take about the same time, but the second requires a little more brains.</p>
<p>
However, when it comes to drawing the hands, we can no longer ignore sine and cosine [7].</p>
<pre style="margin-left: 40px;">
function drawSeconds(seconds) {
let radians = 2 * Math.PI * seconds / 60;
let lengthSecondHand = 250;
let x = SIZE / 2 + Math.sin(radians) * lengthSecondHand / 2;
let y = SIZE / 2 - Math.cos(radians) * lengthSecondHand / 2;
secondsHand.setEndPoint(x, y);
}</pre>
<p>
here the hand for the seconds turns out to be a Gline,</p>
<pre style="margin-left: 40px;">
secondsHand = new GLine(SIZE / 2, SIZE / 2, SIZE / 2, SIZE / 2);</pre>
<p>
which has been declared as an global variable. How to get hours, minutes and seconds we have already seen in the project "Time" in the last chapter. Since the clock should be animated, we need to place the code in the draw() function, with a frame rate one per second, or maybe only half a second.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/drunkenWalk" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/drunkenWalk.png" style="width: 200px; height: 200px; display: block;" />Try it</a></div>
<h2>
DrunkenWalk</h2>
<p>
Once in a while Karel meets with a couple of friends in his favorite bar. On his way home, he no longer walks in straight lines. In this example, Karel starts in the middle. Once per second he takes one step, a random distance in a random direction. We connect the steps with GLines. The next morning, we show Karel his serpentines to let him know that next time he better take a taxi.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/tree" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/tree.png" style="width: 200px; height: 200px; display: block;" />Try it</a></div>
<h2>
Tree*</h2>
<p>
Drawing trees turns out to be relatively difficult. A popular technique to solve this problem is recursion. Since we haven't heard anything about recursion yet, we try to draw a tree without recursion. After this experience, we may be more motivated to learn the secrets of recursion in the next semester.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/asteroidCreator" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/asteroidCreator.png" style="width: 200px; height: 133px; display: block;" />Try it</a></div>
<h2>
AsteroidCreator</h2>
<p>
The arcade game 'AsteroidCreator®' was an absolute hit in the late 80s. The objective of the game is to draw an asteroid at the location where the user clicks with the mouse. Asteroids are simply GRects of different, random sizes with a black border. For this we have to implement the mousePressed() function, where we simply draw a rectangle at the position where the user clicked with the mouse.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/connectTheClicks" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/connectTheClicks.png" style="width: 200px; height: 200px; display: block;" />Try it</a></div>
<h2>
ConnectTheClicks</h2>
<p>
Similar to the previous game, 'ConnectTheClicks®' was very popular in the late 1970s. This is a game in which the user clicks with the mouse on a point, which is then connected to the previous point. What makes the game a little more complicated is that we have to remember where the user clicked before. To do this, we simply use two global variables:</p>
<pre style="margin-left: 40px;">
let x0 = -1;
let y0 = -1;</pre>
<p>
If we initialize these variables with the value "-1", we can use this to determine whether this is the first click. Because then we shouldn't draw a line. Otherwise, we simply draw a line (GLine) with each click from the old position to the new mouse position.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/ticTacToe" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/ticTacToe.png" style="width: 200px; height: 200px; display: block;" />Try it</a></div>
<p>
</p>
<h2>
TicTacToe</h2>
<p>
Everyone knows TicTacToe from kindergarten or school, if you don't, you can read the following about it in the Wikipedia [9]:</p>
<p>
"TicTacToe is a pencil-and-paper game for two players, X and O, who take turns marking the spaces in a 3×3 grid. The X player usually goes first. The player who succeeds in placing three respective marks in a horizontal, vertical, or diagonal row wins the game."</p>
<p>
In the setup() we draw the background. The easiest way is as an image, but we can also draw lines. Also, we have to add the mousePressed() function. There we simply have to draw an "X" or an "O" alternately, depending on who's turn it is. How do you know who's turn it is? This can be done using an global variable, for example:</p>
<pre style="margin-left: 40px;">
let currentPlayer = 1;</pre>
<p>
This variable can have two values, '1' for player one and '2' for player two. Switching between the two players is then very easy:</p>
<pre style="margin-left: 40px;">
if (currentPlayer == 1) {
...
currentPlayer = 2;
} else {
...
currentPlayer = 1;
}</pre>
<p>
A little thing that is very practical: you can of course simply paint the "X" and "O" where the user clicked. That looks a bit squeaky. A little trick uses Math.trunc() for positioning the "X" and "O":</p>
<pre style="margin-left: 40px;">
function mousePressed() {
let x = mouseX;
let y = mouseY;
let i = Math.trunc(x / CELL_WIDTH);
let j = Math.trunc(y / CELL_WIDTH);
...
}</pre>
<p>
.</p>
<hr />
<h1>
Challenges</h1>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/agrar" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/agrar.png" style="width: 200px; height: 184px; display: block;" />Try it</a></div>
<h2>
Agrar</h2>
<p>
Agrar is inspired by the online game Agar.io, which according to Wikipedia [10] is about</p>
<p>
"... navigating a cell that grows by eating pellets and other cells. However, it must not be eaten by larger cells itself."</p>
<p>
Our version of the game is a bit simpler, there is only one cell, and it can only eat pellets. But that is already something.</p>
<p>
First, we need an global variable for the cell:</p>
<pre style="margin-left: 40px;">
let cell;</pre>
<p>
We initialize it in the setup() function, . Next, we need the game loop:</p>
<pre style="margin-left: 40px;">
function draw() {
moveCell();
createRandomFood();
checkForCollision();
update();
}</pre>
<p>
Here we create a pellet at a random position, i.e., a GOval with random color. Next we check if there was a collision between the cell and a pellet. How do we know if there's been a collision? The getElementAt() function is used for this:</p>
<pre style="margin-left: 40px;">
let collisonObject = getElementAt(x, y);
if ((collisonObject != null) && (collisonObject != cell)) {
let w = cell.getWidth();
cell.setSize(w + 1, h + 1);
removeObj(collisonObject);
} </pre>
<p>
This function checks if there is something at the x,y position. If there is nothing there, the function returns the value "null". Otherwise, it returns the object that is at this position. It could be a pellet or it could be the cell itself. Therefore, we must check that it is not "null" and that it is not the cell itself. Since there is nothing else, we now know that the collisonObject must be a pellet. We "eat" the pellet, which means that the cell gets fatter and the pellet is removed.</p>
<p>
Of course we still have to implement the mouseMoved() function. This is quite easy, we simply move the cell to the position of the mouse:</p>
<pre style="margin-left: 40px;">
function mouseMoved() {
xMouse = mouseX;
yMouse = mouseY;
cell.setLocation(x, y);
}</pre>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/tetris" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/tetris.png" style="width: 200px; height: 219px; display: block;" />Try it</a></div>
<h2>
Tetris</h2>
<p>
Tetris is a classic, everybody knows it. Originally it was programmed by Russian programmer Alexei Paschitnow [11]. Tetris has different stone forms that resemble Latin letters (I, O, T, Z and L). Players must rotate the individual pieces that fall from the top of the board in 90 degree increments and move them so that they form horizontal, preferably gapless rows at the bottom edge. As usual, we limit ourselves to a somewhat simpler version, in which there are only four stone forms: a single block, a horizontal and a vertical block of two, and a block of four. We cannot rotate the blocks in our simple version.</p>
<p>
In the setup() function we create a new stone:</p>
<pre style="margin-left: 40px;">
function setup() {
...
createNewBrick();
}</pre>
<p>
The createNewBrick() function creates a random new stone. The stone shape depends on a random number:</p>
<pre style="margin-left: 40px;">
function createNewBrick() {
switch (rgen.nextInt(0, 3)) {
case 0:
brick = new GRect(WIDTH / 2, 0, BRICK_SIZE, BRICK_SIZE * 2);
break;
case 1:
...
}
brick.setFilled(true);
brick.setFillColor(rgen.nextColor());
add(brick);
}</pre>
<p>
The brick must be an global variable, otherwise it won't work. The same applies to our random generator. In order for the stones to start falling down, we need a game loop:</p>
<pre style="margin-left: 40px;">
function draw() {
moveBrick();
checkForCollision();
update();
}</pre>
<p>
The moveBrick() function simply moves the brick down by one brick width. The checkForCollision() function determines whether the stone is allowed to fall any further. Once the stone has arrived at the bottom, it just sits there. How do we do that? We simply create a new stone, and leave the old one where it is:</p>
<pre style="margin-left: 40px;">
function checkForCollision() {
// check bottom
if (brick.getY() > HEIGHT - brick.getHeight()) {
createNewBrick();
}
...
</pre>
<p>
However, we can also have collisions with other blocks, that are sitting already at the bottom. In this case the falling stone also is not allowed to fall any further. We need to use the getElementAt() function and check for collisions:</p>
<pre style="margin-left: 40px;">
// check for other bricks
let x = brick.getX() + 1;
let y = brick.getY() + brick.getHeight();
let obj = getElementAt(x, y);
if ((obj != null) && (obj != brick)) {
createNewBrick();
return;
}
...
}
</pre>
<p>
This function tells us whether there is a GObject at the x,y position. If there is, we simply create a new stone.</p>
<p>
So, now our stones are falling. The only thing missing is key control. When a key on the keyboard is pressed, a KeyEvent occurs. This is completely analogous to the mouse events. Therefore, we need to add a keyPressed() function to our Tetris class:</p>
<pre style="margin-left: 40px;">
function keyPressed() {
switch (keyCode) {
case LEFT_ARROW:
brick.move(-BRICK_SIZE, 0);
break;
case RIGHT_ARROW:
brick.move(BRICK_SIZE, 0);
break;
}
}</pre>
<p>
The <em>keyCode</em> tells us which key was pressed: for the left arrow key the keycode is 37, for the right the keycode is 39 and that is all we need to finish our simple Tetris game.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/pong" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/pong.png" style="width: 200px; height: 150px; display: block;" />Try it</a></div>
<h2>
Pong</h2>
<p>
Pong was released by Atari in 1972 and is considered the forefather of all video games [8]. It is a game for two players who try to play a ball back and forth similar to ping-pong. To get started, we need three global variables for the ball and the two paddles.</p>
<pre style="margin-left: 40px;">
let ball;
let leftPaddle;
let rightPaddle;</pre>
<p>
Then of course there is our game loop:</p>
<pre style="margin-left: 40px;">
function draw() {
moveBall();
checkForCollision();
update();
}</pre>
<p>
The moveBall() function simply moves the ball by a certain amount in x and y direction.</p>
<p>
The checkForCollision() function does two things: it checks if there was a collision with the wall or if there was a collision with one of the paddles. If the ball wants to leave the playing field on the top or bottom, it is simply reflected. If it wants to leave on the left or right, then it simply disappears, and the round is over. If the ball collides with the paddles, it is also reflected.</p>
<p>
For the collisions with the paddles we use the getElementAt() function. Reflection is quite simple. We first need an global variable for the speed:</p>
<pre style="margin-left: 40px;">
let vx = 2;
let vy = 3;</pre>
<p>
and then reflection simply means:</p>
<pre style="margin-left: 40px;">
vy = -vy;</pre>
<p>
Of course, the moveBall() function must also use these variables.</p>
<p>
The paddles should be controlled by the keyboard, so we need to add the KeyListener again and add the keyPressed() function:</p>
<pre style="margin-left: 40px;">
function keyPressed() {
switch (key) {
case 'p': // right paddle up
rightPaddle.move(0, -PADDLE_VY);
break;
case 'l': // right paddle down
...
}
}
</pre>
<p>
Notice, we use <em>key</em> instead of <em>keyCode</em> here. We use <em>keyCode</em> if we want to detect special keys, however, for letters and digits, we use key. The first player controls her paddle with the keys 'q' and 'a', the second player with the keys 'p' and 'l'.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr4_Agrar/brickBreaker" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/brickBreaker.png" style="width: 200px; height: 250px; display: block;" />Try it</a></div>
<h2>