The teaser for part 7 of the Hooray! series promised “patches multiple” because the amount of abstractions we were able to ferret out from the code was more than anticipated, and it was tiring to update the teaser w/ yet another number that would quickly become obsolete. So, get ready for a slew of patches this episode. The abstractions patches number eight (!), but they will be quick as we race towards the last two — patches 20 and 21 — which add real motion to the animation. Finally, we can see those throngs thronging! :-D
1 commit 383244898499097e033b67f9c337fe449077f73a
2 Author: Thien-Thi Nguyen <ttn@gnuvola.org>
3 Date: 2022-01-29 17:06:33 -0500
4
5 Add abstraction: BUTTONS
6
7 * hooray.scm (BUTTONS): New data structure.
8 (load-theme): Use ‘BUTTONS
’.
9 (change-scenery-slightly! random-button): Likewise.
10 ---
11 hooray.scm | 6 ++++--
12 1 file changed, 4 insertions(+), 2 deletions(-)
13
14 diff --git a/hooray.scm b/hooray.scm
15 index 37011a2..ca55c99 100644
16 --- a/hooray.scm
17 +++ b/hooray.scm
18 @@ -50,6 +50,8 @@ (define (make-tile-rect r c)
19 TILE-EDGE-LENGTH
20 TILE-EDGE-LENGTH))
21
22 +(define BUTTONS '(left right check-0 x mix tools blank check-1))
23 +
24 (define (load-theme filename) ; => hash table
25
26 (define (proper surface)
27 @@ -72,7 +74,7 @@ (define (load-theme filename) ; => hash table
28
29 (read-row! 0 '(window cell sender rec-0 rec-1 lock win unused))
30 (read-row! 1 '(up-0 up-1 opp-0 opp-1 corn-0 corn-1 tee-0 tee-1))
31 - (read-row! 2 '(left right check-0 x mix tools blank check-1))
32 + (read-row! 2 BUTTONS)
33
34 (hashq-remove! ht 'unused)
35
36 @@ -253,7 +255,7 @@ (define hooray!
37 (define (change-scenery-slightly!)
38
39 (define random-button
40 - (let ((v (list->vector '(left right check-0 x mix tools blank check-1))))
41 + (let ((v (list->vector BUTTONS)))
42 ;; random-button
43 (lambda ()
44 (vector-ref v (random (vector-length v))))))
Yes, abstractions can be data as well as control. Next!
1 commit 2fd1fe4b2ca3e638fd9c0eba1268a2340d9ec303
2 Author: Thien-Thi Nguyen <ttn@gnuvola.org>
3 Date: 2022-01-29 17:12:00 -0500
4
5 Add abstraction: rect-xy!
6
7 * hooray.scm (rect-xy!): New proc.
8 (smokin): Use ‘rect-xy!
’.
9 (hooray! place-fg!): Likewise.
10 (hooray!): Likewise.
11 ---
12 hooray.scm | 18 ++++++++++--------
13 1 file changed, 10 insertions(+), 8 deletions(-)
14
15 diff --git a/hooray.scm b/hooray.scm
16 index ca55c99..d33d595 100644
17 --- a/hooray.scm
18 +++ b/hooray.scm
19 @@ -116,6 +116,10 @@ (define refresh-scenery!
20 ;; mid ground
21 (array-map! rect place-tile! MID rect))))
22
23 +(define (rect-xy! rect x y)
24 + (SDL:rect:set-x! rect x)
25 + (SDL:rect:set-y! rect y))
26 +
27 (define smokin
28 (let ((keys (list->vector (hash-fold (lambda (k v acc)
29 (cons k acc))
30 @@ -138,8 +142,7 @@ (define smokin
31 (and (zero? (modulo i 42))
32 (refresh-scenery!))
33 (let ((tile (random-tile)))
34 - (SDL:rect:set-x! rect (random-coord))
35 - (SDL:rect:set-y! rect (random-coord))
36 + (rect-xy! rect (random-coord) (random-coord))
37 (SDL:blit-surface tile #f #f rect))
38 (SDL:flip)
39 (SDL:delay millisecs))
40 @@ -217,8 +220,10 @@ (define hooray!
41 (define (place-fg! fg w/2 h/2)
42 ;; rv
43 (lambda (dst x y)
44 - (SDL:rect:set-x! dst (- x w/2))
45 - (SDL:rect:set-y! dst (exact-truncate (- y h/2)))
46 + (rect-xy!
47 + dst
48 + (- x w/2))
49 + (exact-truncate (- y h/2))
50 (SDL:blit-surface fg #f #f dst)))
51
52 (let ((fg (svec))
53 @@ -239,10 +244,7 @@ (define hooray!
54 (lambda ()
55 (array-map! x (random-c +))
56 (array-map! y (random-c -))
57 - (array-for-each (lambda (rect x y)
58 - (SDL:rect:set-x! rect x)
59 - (SDL:rect:set-y! rect y))
60 - dst x y)
61 + (array-for-each rect-xy! dst x y)
62 (array-for-each
63 (lambda (fg w/2 h/2)
64 (refresh-scenery!)
This one is so useful, I'm considering adding it to Guile-SDL proper. Let's see how things go...
1 commit f6ad67557ac63403a20d92e6bfb38c77baf50304
2 Author: Thien-Thi Nguyen <ttn@gnuvola.org>
3 Date: 2022-01-29 17:16:16 -0500
4
5 Add abstraction: array-like-FAR
6
7 * hooray.scm (array-like-FAR): New proc.
8 (MID): Use ‘array-like-FAR
’.
9 (refresh-scenery!): Likewise.
10 ---
11 hooray.scm | 7 +++++--
12 1 file changed, 5 insertions(+), 2 deletions(-)
13
14 diff --git a/hooray.scm b/hooray.scm
15 index d33d595..ed158f0 100644
16 --- a/hooray.scm
17 +++ b/hooray.scm
18 @@ -95,12 +95,15 @@ (define FAR #2((window window window window window)
19 (window cell cell cell window)
20 (window window window window window)))
21
22 -(define MID (let ((a (apply make-array #f (array-shape FAR))))
23 +(define (array-like-FAR)
24 + (apply make-array #f (array-shape FAR)))
25 +
26 +(define MID (let ((a (array-like-FAR)))
27 (array-set! a 'rec-1 2 2)
28 a))
29
30 (define refresh-scenery!
31 - (let ((rect (apply make-array #f (array-shape FAR))))
32 + (let ((rect (array-like-FAR)))
33
34 (define (place-tile! name rect)
35 (and name (SDL:blit-surface (surf name) #f #f rect))
Probably you saw this coming from “a-FAR”, right? (Yuk yuk.)
1 commit da8888ea65cc96108ec5bcbf3c19a87fa7874061
2 Author: Thien-Thi Nguyen <ttn@gnuvola.org>
3 Date: 2022-01-29 17:19:07 -0500
4
5 Add abstraction: vrandom
6
7 * hooray.scm (vrandom): New proc.
8 (smokin random-tile): Use ‘vrandom
’.
9 (change-scenery-slightly! random-button): Likewise.
10 ---
11 hooray.scm | 7 +++++--
12 1 file changed, 5 insertions(+), 2 deletions(-)
13
14 diff --git a/hooray.scm b/hooray.scm
15 index ed158f0..0da2d6b 100644
16 --- a/hooray.scm
17 +++ b/hooray.scm
18 @@ -119,6 +119,9 @@ (define refresh-scenery!
19 ;; mid ground
20 (array-map! rect place-tile! MID rect))))
21
22 +(define (vrandom v)
23 + (vector-ref v (random (vector-length v))))
24 +
25 (define (rect-xy! rect x y)
26 (SDL:rect:set-x! rect x)
27 (SDL:rect:set-y! rect y))
28 @@ -133,7 +136,7 @@ (define smokin
29 (* TILE-EDGE-LENGTH (random 5)))
30
31 (define (random-tile)
32 - (let ((name (vector-ref keys (random (vector-length keys)))))
33 + (let ((name (vrandom keys)))
34 (display " ")
35 (display name)
36 (surf name)))
37 @@ -263,7 +266,7 @@ (define (change-scenery-slightly!)
38 (let ((v (list->vector BUTTONS)))
39 ;; random-button
40 (lambda ()
41 - (vector-ref v (random (vector-length v))))))
42 + (vrandom v))))
43
44 (define (new-place)
45 (let loop ((count 9))
This reminds me of 1990s modem marketing, v.fast, v.faster, v.ludicrous...
1 commit 4659a89fed66baaf8eb4411d9b227bdaac4ed562
2 Author: Thien-Thi Nguyen <ttn@gnuvola.org>
3 Date: 2022-01-29 17:48:52 -0500
4
5 Add abstraction: update-rect-and-blit!
6
7 * hooray.scm (update-rect-and-blit!): New proc.
8 (smokin): Use ‘update-rect-and-blit!
’.
9 (hooray! place-fg!): Likewise.
10 ---
11 hooray.scm | 19 +++++++++++--------
12 1 file changed, 11 insertions(+), 8 deletions(-)
13
14 diff --git a/hooray.scm b/hooray.scm
15 index 0da2d6b..52a2ada 100644
16 --- a/hooray.scm
17 +++ b/hooray.scm
18 @@ -126,6 +126,10 @@ (define (rect-xy! rect x y)
19 (SDL:rect:set-x! rect x)
20 (SDL:rect:set-y! rect y))
21
22 +(define (update-rect-and-blit! surface rect x y)
23 + (rect-xy! rect x y)
24 + (SDL:blit-surface surface #f #f rect))
25 +
26 (define smokin
27 (let ((keys (list->vector (hash-fold (lambda (k v acc)
28 (cons k acc))
29 @@ -147,9 +151,9 @@ (define smokin
30 ((= 420 i))
31 (and (zero? (modulo i 42))
32 (refresh-scenery!))
33 - (let ((tile (random-tile)))
34 - (rect-xy! rect (random-coord) (random-coord))
35 - (SDL:blit-surface tile #f #f rect))
36 + (update-rect-and-blit! (random-tile) rect
37 + (random-coord)
38 + (random-coord))
39 (SDL:flip)
40 (SDL:delay millisecs))
41 (newline))))
42 @@ -226,11 +230,10 @@ (define hooray!
43 (define (place-fg! fg w/2 h/2)
44 ;; rv
45 (lambda (dst x y)
46 - (rect-xy!
47 - dst
48 - (- x w/2))
49 - (exact-truncate (- y h/2))
50 - (SDL:blit-surface fg #f #f dst)))
51 + (update-rect-and-blit!
52 + fg dst
53 + (- x w/2)
54 + (exact-truncate (- y h/2)))))
55
56 (let ((fg (svec))
57 (w/2 (svec))
Note that we can have abstractions built upon other abstractions.
1 commit 662b9de748d471d8deba4e986f06092e767621ef 2 Author: Thien-Thi Nguyen <ttn@gnuvola.org> 3 Date: 2022-01-29 17:53:39 -0500 4 5 Add abstraction: layer! 6 7 * hooray.scm (refresh-scenery! layer!): New proc. 8 (refresh-scenery!): Use ‘layer!
’. 9 --- 10 hooray.scm | 9 +++++---- 11 1 file changed, 5 insertions(+), 4 deletions(-) 12 13 diff --git a/hooray.scm b/hooray.scm 14 index 52a2ada..4fad590 100644 15 --- a/hooray.scm 16 +++ b/hooray.scm 17 @@ -109,15 +109,16 @@ (define refresh-scenery! 18 (and name (SDL:blit-surface (surf name) #f #f rect)) 19 rect) 20 21 + (define (layer! ground) 22 + (array-map! rect place-tile! ground rect)) 23 + 24 ;; initialize ‘rect
’ 25 (array-index-map! rect make-tile-rect) 26 27 ;; refresh-scenery! 28 (lambda () 29 - ;; far ground 30 - (array-map! rect place-tile! FAR rect) 31 - ;; mid ground 32 - (array-map! rect place-tile! MID rect)))) 33 + (layer! FAR) 34 + (layer! MID)))) 35 36 (define (vrandom v) 37 (vector-ref v (random (vector-length v))))
Here we take the liberty of removing some comments (lines 29, 31), since the code has become so incredibly self-descriptive.
1 commit 24f1e68767edf106293fea6dea167e978b7f2d8d
2 Author: Thien-Thi Nguyen <ttn@gnuvola.org>
3 Date: 2022-01-29 18:00:06 -0500
4
5 Add abstraction: show!
6
7 * hooray.scm (show!): New proc.
8 (smokin): Use ‘show!
’.
9 (hooray!): Likewise.
10 ---
11 hooray.scm | 10 ++++++----
12 1 file changed, 6 insertions(+), 4 deletions(-)
13
14 diff --git a/hooray.scm b/hooray.scm
15 index 4fad590..02714c5 100644
16 --- a/hooray.scm
17 +++ b/hooray.scm
18 @@ -131,6 +131,10 @@ (define (update-rect-and-blit! surface rect x y)
19 (rect-xy! rect x y)
20 (SDL:blit-surface surface #f #f rect))
21
22 +(define (show! ms)
23 + (SDL:flip)
24 + (SDL:delay ms))
25 +
26 (define smokin
27 (let ((keys (list->vector (hash-fold (lambda (k v acc)
28 (cons k acc))
29 @@ -155,8 +159,7 @@ (define smokin
30 (update-rect-and-blit! (random-tile) rect
31 (random-coord)
32 (random-coord))
33 - (SDL:flip)
34 - (SDL:delay millisecs))
35 + (show! millisecs))
36 (newline))))
37
38 (define FG-EDGE-LENGTH 32)
39 @@ -260,8 +263,7 @@ (define hooray!
40 (refresh-scenery!)
41 (array-for-each (place-fg! fg w/2 h/2)
42 dst x y)
43 - (SDL:flip)
44 - (SDL:delay 42))
45 + (show! 42))
46 fg w/2 h/2)))))
47
48 (define (change-scenery-slightly!)
Small but sweet. We'll take it.
1 commit 0368f020fde9320cf073099c31a208ceec244bb6
2 Author: Thien-Thi Nguyen <ttn@gnuvola.org>
3 Date: 2022-01-29 18:03:02 -0500
4
5 Add abstraction: blit-to-screen!
6
7 * hooray.scm (blit-to-screen!): New proc.
8 (refresh-scenery! place-tile!): Use ‘blit-to-screen!
’.
9 (update-rect-and-blit!): Likewise.
10 ---
11 hooray.scm | 7 +++++--
12 1 file changed, 5 insertions(+), 2 deletions(-)
13
14 diff --git a/hooray.scm b/hooray.scm
15 index 02714c5..2fdc55e 100644
16 --- a/hooray.scm
17 +++ b/hooray.scm
18 @@ -102,11 +102,14 @@ (define MID (let ((a (array-like-FAR)))
19 (array-set! a 'rec-1 2 2)
20 a))
21
22 +(define (blit-to-screen! surface rect)
23 + (SDL:blit-surface surface #f #f rect))
24 +
25 (define refresh-scenery!
26 (let ((rect (array-like-FAR)))
27
28 (define (place-tile! name rect)
29 - (and name (SDL:blit-surface (surf name) #f #f rect))
30 + (and name (blit-to-screen! (surf name) rect))
31 rect)
32
33 (define (layer! ground)
34 @@ -129,7 +132,7 @@ (define (rect-xy! rect x y)
35
36 (define (update-rect-and-blit! surface rect x y)
37 (rect-xy! rect x y)
38 - (SDL:blit-surface surface #f #f rect))
39 + (blit-to-screen! surface rect))
40
41 (define (show! ms)
42 (SDL:flip)
This is a happy patch — it reduces negativity (‘#f
’)!
That was quick! Here's an interesting set of data points on the overall effect of these eight patches:
$ wc hooray.scm.{WAS,NOW} 293 985 8956 hooray.scm.WAS 312 989 9014 hooray.scm.NOW 605 1974 17970 totale
The ‘.WAS
’ is a snapshot prior to the eight, the ‘.NOW
’ is a snapshot after.
The figure of merit here is not line or character count, but word count.
It went from 985 to 989, barely one word per two patches!
From this we can see that our abstractions have increased the density of the code, which is a good thing.
And with that out of the way, we now turn our attention to the real interesting patches in this episode, the ones that add velocity and acceleration to our sprites.
1 commit 3f6436268063cab86890e9563df0529b052c764f 2 Author: Thien-Thi Nguyen <ttn@gnuvola.org> 3 Date: 2022-01-29 18:30:07 -0500 4 5 Add velocity 6 7 * hooray.scm (hooray! random-v): New proc. 8 (hooray! bump!): New proc. 9 (hooray!): Initialize and integrate velocity vectors. 10 --- 11 hooray.scm | 14 ++++++++++++++ 12 1 file changed, 14 insertions(+) 13 14 diff --git a/hooray.scm b/hooray.scm 15 index 2fdc55e..0c53f2b 100644 16 --- a/hooray.scm 17 +++ b/hooray.scm 18 @@ -234,6 +234,14 @@ (define hooray! 19 (lambda () 20 (+ origin (random 29) -14)))) 21 22 + (define (random-v bias) 23 + ;; rv 24 + (lambda () 25 + (+ (random 9) -4 bias))) 26 + 27 + (define (bump! orig delta) 28 + (array-map! orig + orig delta)) 29 + 30 (define (place-fg! fg w/2 h/2) 31 ;; rv 32 (lambda (dst x y) 33 @@ -247,6 +255,8 @@ (define hooray! 34 (h/2 (svec)) 35 (x (tvec)) ; location 36 (y (tvec)) 37 + (vx (tvec)) ; velocity 38 + (vy (tvec)) 39 (dst (tvec))) 40 41 (array-index-map! fg (lambda (i) 42 @@ -261,9 +271,13 @@ (define hooray! 43 (array-map! x (random-c +)) 44 (array-map! y (random-c -)) 45 (array-for-each rect-xy! dst x y) 46 + (array-map! vx (random-v 0)) 47 + (array-map! vy (random-v (random -4.20))) 48 (array-for-each 49 (lambda (fg w/2 h/2) 50 (refresh-scenery!) 51 + (bump! x vx) 52 + (bump! y vy) 53 (array-for-each (place-fg! fg w/2 h/2) 54 dst x y) 55 (show! 42))
The “velocity vectors” (line 9) sound racy and exciting, don't they? Actually, that's a literal description (lines 37-38) of the situation. Init is on lines 46-47 and the real Change happens on lines 51-52. Here's what I see when I run command “guile -s hooray.scm Plumbing.png 99”:
1 commit 8a7c45d387f0966dd683fc4f0ee328081e8fdafc 2 Author: Thien-Thi Nguyen <ttn@gnuvola.org> 3 Date: 2022-01-29 19:58:34 -0500 4 5 Add acceleration 6 7 * hooray.scm (hooray! random-gravity): New proc. 8 (hooray!): Initialize and integrate gravity vector. 9 --- 10 hooray.scm | 6 ++++++ 11 1 file changed, 6 insertions(+) 12 13 diff --git a/hooray.scm b/hooray.scm 14 index 0c53f2b..9b57804 100644 15 --- a/hooray.scm 16 +++ b/hooray.scm 17 @@ -239,6 +239,9 @@ (define hooray! 18 (lambda () 19 (+ (random 9) -4 bias))) 20 21 + (define (random-gravity) 22 + (random 0.420)) 23 + 24 (define (bump! orig delta) 25 (array-map! orig + orig delta)) 26 27 @@ -257,6 +260,7 @@ (define hooray! 28 (y (tvec)) 29 (vx (tvec)) ; velocity 30 (vy (tvec)) 31 + (gravity (tvec)) 32 (dst (tvec))) 33 34 (array-index-map! fg (lambda (i) 35 @@ -273,11 +277,13 @@ (define hooray! 36 (array-for-each rect-xy! dst x y) 37 (array-map! vx (random-v 0)) 38 (array-map! vy (random-v (random -4.20))) 39 + (array-map! gravity random-gravity) 40 (array-for-each 41 (lambda (fg w/2 h/2) 42 (refresh-scenery!) 43 (bump! x vx) 44 (bump! y vy) 45 + (bump! vy gravity) 46 (array-for-each (place-fg! fg w/2 h/2) 47 dst x y) 48 (show! 42))
Why call it “acceleration” in the commit log message title and “gravity” everywhere else? Well, “gravity” is familiar, and indicates direction (generally, “down”), not to mention shorter and faster to type. It also has a certain... weightiness to it, no? :-D Anyway, note that we only apply gravity to vertical component (line 45). It doesn't make sense (for this animation) to use it on the horizontal. Here's what “guile -s hooray.scm Plumbing.png 99” shows now, w/ this patch:
So, let's update our checklist now.
* PipeWalker fg behavior (to reproduce if possible) - [X] starts near top of center tile - [x] mostly upward velocity - [ ] rotates clockwise slightly - [ ] starts smaller than 32x32 - [ ] grows quickly - [ ] non synchronized (all aspects) - [x] fades to transparent
Like “fades to transparent”, we cannot give full marks to “mostly upward velocity” at this time. The reasoning behind our strictness differs, however, from before. For velocity and acceleration, our design and implementation is good, but the actual results do not truly live up to “mostly”. In other words, there's room for tweaking the constants. We'll get to that later (maybe).
Copyright (C) 2022 Thien-Thi Nguyen