sourceextensions/scene/demos/voxels-walk.xtl
1⍝# Voxels, 5: walking. The island of voxels-world, seen from inside it.
2⍝# The player is nine numbers -- x y z (feet), vx vy vz, yaw, pitch, on
3⍝# the ground -- and every frame X_eTaL reads the keys and the mouse,
4⍝# turns, falls, jumps, and moves one axis at a time against the solid
5⍝# blocks the player's box would overlap, stopping at the face of the
6⍝# block it hits (a swept box per axis, as the APL game collides); then
7⍝# it sets scene's first-person camera. It also tests the 32 chunks
8⍝# against the planes of the view, as the APL game culls (key c).
9⍝# Run: just demo scene voxels-walk (a new island each run; --seed 1)
10⍝# W A S D walk, Shift run, Space jump (in water: swim up; at the
11⍝# surface: climb out onto a bank one block high), drag the mouse or the
12⍝# arrows to look, c: the chunks in view, H: back to the start, q or
13⍝# close: quit
14
15ᵛˣ⁼u̲se< "Voxels"
16ˢᶜ⁼u̲se< "Scene"
17
18h ← ᵛˣh̲eights 64
19b ← ᵛˣt̲errain h
20ts ← 12 2 r̲eshape 3 + r̲oll! 24 r̲eshape 58
21b ← ts ᵛˣf̲orest b
22f ← ᵛˣw̲orldFaces b
23sv ← r̲avel ᵛˣs̲olid b
24"faces, and solid blocks:"
25(t̲ally f) c̲at '+ r̲/ sv
26
27w ← "Voxels 5: walking -- X_eTaL" ˢᶜo̲pen! 640 400
28g ← w ˢᶜf̲og! 24.0 56.0
29c ← ᵛˣc̲hunkOf f
30keys ← u̲nique (10 × c) + 5 s̲elect₂ f
31ᵘp̲ut ← { i →
32 key ← i s̲elect keys
33 sel ← key = (10 × c) + 5 s̲elect₂ f
34 head ← (f̲loat w c̲at key) c̲at (1 + key m̲od 10) s̲elect ᵛˣcolors
35 x ← head ˢᶜq̲uads! ᵛˣc̲orners sel r̲eplicate f
36 i + 1
37}
38put ← (t̲ally keys) 'ᵘp̲ut p̲ower 1
39
40⍝## The player
41
42⍝# a box 0.6 wide and 1.75 tall, the eye 1.6 up; a frame is 1/60 s
43dt ← 1.0 ÷ 60.0
44
45⍝# (i c_at v) u:s_et p: the state with element i replaced by v
46ᵘs̲et ← { l p → p + (f̲loat (r̲ange 9) = f̲loor 1 s̲elect l) × (2 s̲elect l) − p }
47
48⍝# whether the box with its feet at (x y z) overlaps a solid block:
49⍝# beyond the island's sides and below it is solid, above it is air
50ᵘh̲it ← { q →
51 x ← 1 s̲elect q
52 y ← 2 s̲elect q
53 z ← 3 s̲elect q
54 cx ← u̲nique f̲loor (x − 0.3) c̲at x + 0.3
55 cy ← u̲nique f̲loor y c̲at (y + 0.9) c̲at y + 1.75
56 cz ← u̲nique f̲loor (z − 0.3) c̲at z + 0.3
57 out ← ('+ r̲/ (cx < 0) + cx > 63) + ('+ r̲/ (cz < 0) + cz > 63) + '+ r̲/ cy < 0
58 out > 0 ? 1
59 cy ← (cy ≤ 31) r̲eplicate cy
60 0 = t̲ally cy ? 0
61 i ← 1 + (2048 × cx) '+ t̲able (64 × cy) '+ t̲able cz
62 f̲loat 0 < '+ r̲/ (r̲avel i) s̲elect sv
63}
64
65⍝# v u:s_nap a: where to stop, moving at v, before the block at a
66⍝# (the box reaches 0.3 to each side)
67ᵘs̲nap ← { v a →
68 v > 0.0 ? (f̲loat f̲loor a + 0.3) − 0.3001
69 (f̲loat 1 + f̲loor a − 0.3) + 0.3001
70}
71
72⍝# the three axes of a move: x and z stop at a wall; y lands (on the
73⍝# ground) or bumps a ceiling
74ᵘm̲x ← { p →
75 a ← (1 s̲elect p) + dt × 4 s̲elect p
76 q ← (1 c̲at a) ᵘs̲et p
77 0 = ᵘh̲it q ? q
78 (4 c̲at 0.0) ᵘs̲et (1 c̲at (4 s̲elect p) ᵘs̲nap a) ᵘs̲et p
79}
80ᵘm̲z ← { p →
81 a ← (3 s̲elect p) + dt × 6 s̲elect p
82 q ← (3 c̲at a) ᵘs̲et p
83 0 = ᵘh̲it q ? q
84 (6 c̲at 0.0) ᵘs̲et (3 c̲at (6 s̲elect p) ᵘs̲nap a) ᵘs̲et p
85}
86ᵘm̲y ← { p →
87 a ← (2 s̲elect p) + dt × 5 s̲elect p
88 q ← (9 c̲at 0.0) ᵘs̲et (2 c̲at a) ᵘs̲et p
89 0 = ᵘh̲it q ? q
90 (5 s̲elect p) > 0.0 ? (5 c̲at 0.0) ᵘs̲et (2 c̲at (f̲loat f̲loor a + 1.75) − 1.7501) ᵘs̲et p
91 (9 c̲at 1.0) ᵘs̲et (5 c̲at 0.0) ᵘs̲et (2 c̲at f̲loat 1 + f̲loor a) ᵘs̲et p
92}
93
94⍝# one frame of the player: the controls are mouse dx dy, then w a s d
95⍝# space shift left right up down (1 held)
96ᵘs̲tep ← { p →
97 k ← ˢᶜc̲ontrols w
98 yaw ← (7 s̲elect p) + (0.005 × 1 s̲elect k) + 2.0 × dt × (10 s̲elect k) − 9 s̲elect k
99 pitch ← -1.5 m̲ax 1.5 m̲in (8 s̲elect p) + (-0.005 × 2 s̲elect k) + 1.5 × dt × (11 s̲elect k) − 12 s̲elect k
100 fwd ← (3 s̲elect k) − 5 s̲elect k
101 side ← (6 s̲elect k) − 4 s̲elect k
102 ⍝ in water: all the air below the sea (14) is water; the body is in
103 ⍝ it when its middle is below the surface
104 wet ← f̲loat 14.0 > 0.9 + 2 s̲elect p
105 speed ← (1.0 − 0.4 × wet) × 4.5 × 1.0 + 8 s̲elect k
106 vx ← speed × ((s̲in yaw) × fwd) + (c̲os yaw) × side
107 vz ← speed × ((0.0 − c̲os yaw) × fwd) + (s̲in yaw) × side
108 ⍝ a jump from the ground, or from the surface of the water (feet
109 ⍝ within half a block above it, not deeper): onto a bank one block high
110 surface ← (f̲loat 14.5 > 2 s̲elect p) × f̲loat 13.0 < 2 s̲elect p
111 jump ← (1.0 m̲in (9 s̲elect p) + surface × 1.0 − wet) × 7 s̲elect k
112 ⍝ swimming: Space rises; otherwise a slow sink
113 swim ← wet × 7 s̲elect k
114 fall ← -30.0 m̲ax (5 s̲elect p) − 22.0 × dt
115 sink ← -2.0 m̲ax (5 s̲elect p) − 6.0 × dt
116 vy ← (7.5 × jump) + (1.0 − jump) × (4.0 × swim) + (1.0 − swim) × (wet × sink) + (1.0 − wet) × fall
117 p ← (7 c̲at yaw) ᵘs̲et (8 c̲at pitch) ᵘs̲et (4 c̲at vx) ᵘs̲et (5 c̲at vy) ᵘs̲et (6 c̲at vz) ᵘs̲et p
118 p ← ᵘm̲y ᵘm̲z ᵘm̲x p
119 e ← w ˢᶜe̲ye! (1 s̲elect p) c̲at ((2 s̲elect p) + 1.6) c̲at (3 s̲elect p) c̲at yaw c̲at pitch
120 p
121}
122
123⍝## The chunks in view
124
125⍝# each chunk's box against the planes of the view (left, right, bottom,
126⍝# top, and the plane of the eye): a chunk is out when its box is wholly
127⍝# behind one of them. The planes' normals are made in the camera's
128⍝# frame and turned into the world's by an inner product with the frame.
129ᵘi̲nView ← { p →
130 yaw ← 7 s̲elect p
131 pt ← 8 s̲elect p
132 right ← (c̲os yaw) c̲at 0.0 c̲at s̲in yaw
133 up ← (0.0 − (s̲in yaw) × s̲in pt) c̲at (c̲os pt) c̲at (c̲os yaw) × s̲in pt
134 ahead ← ((s̲in yaw) × c̲os pt) c̲at (s̲in pt) c̲at 0.0 − (c̲os yaw) × c̲os pt
135 v ← 0.6109
136 hh ← a̲tan 1.6 × (s̲in v) ÷ c̲os v
137 nc ← 5 3 r̲eshape (c̲os hh) c̲at 0.0 c̲at (s̲in hh) c̲at (0.0 − c̲os hh) c̲at 0.0 c̲at (s̲in hh) c̲at 0.0 c̲at (c̲os v) c̲at (s̲in v) c̲at 0.0 c̲at (0.0 − c̲os v) c̲at (s̲in v) c̲at 0.0 0.0 1.0
138 nw ← nc '+ '× i̲nner 3 3 r̲eshape right c̲at up c̲at ahead
139 j ← (r̲ange 32) − 1
140 centers ← 2 1 t̲ranspose 3 32 r̲eshape (8.0 + 16.0 × f̲loat j m̲od 4) c̲at (8.0 + 16.0 × f̲loat j d̲iv 16) c̲at 8.0 + 16.0 × f̲loat (j d̲iv 4) m̲od 4
141 eye ← (1 s̲elect p) c̲at ((2 s̲elect p) + 1.6) c̲at 3 s̲elect p
142 rel ← centers − 32 3 r̲eshape eye
143 d ← rel '+ '× i̲nner 2 1 t̲ranspose nw
144 r ← (a̲bs nw) '+ '× i̲nner 8.0 8.0 8.0
145 '∧ r̲/₂ d ≥ 32 5 r̲eshape 0.0 − r
146}
147ᵘc̲hunks ← { p →
148 m ← ᵘi̲nView p
149 a ← p̲rint! "chunks in view (of 32), and by layer (bottom, top; rows north to south):"
150 a ← p̲rint! '+ r̲/ m
151 a ← p̲rint! 2 4 4 r̲eshape m
152 p
153}
154
155⍝## The loop
156
157⍝# start above the island's highest inner column, dropping onto it, facing
158⍝# north when the middle is north of it, else south
159⍝# (the highest of the columns at least 8 from the island's sides)
160j ← (r̲ange 4096) − 1
161inner ← ((j d̲iv 64) ≥ 8) × ((j d̲iv 64) < 56) × ((j m̲od 64) ≥ 8) × (j m̲od 64) < 56
162hv ← r̲avel h
163i ← f̲irst w̲here inner × hv = 'm̲ax r̲/ inner × hv
164sx ← (f̲loat (i − 1) d̲iv 64) + 0.5
165sz ← (f̲loat (i − 1) m̲od 64) + 0.5
166yaw0 ← 3.14159 × f̲loat sz < 32.0
167start ← sx c̲at (f̲loat 3 + i s̲elect hv) c̲at sz c̲at 0.0 0.0 0.0 c̲at yaw0 c̲at 0.0 0.0
168s ← ᵘc̲hunks start
169e ← w ˢᶜe̲ye! sx c̲at (f̲loat 5 + i s̲elect hv) c̲at sz c̲at yaw0 c̲at 0.0
170
171ᵘq̲uit ← { p →
172 z ← ˢᶜc̲lose! w
173 0 r̲eshape 0.0
174}
175ᵘf̲rame ← { p →
176 0 = t̲ally p ? p
177 v ← ˢᶜn̲ext! w
178 ((v m̲atch "close") + (v m̲atch "key q") + v m̲atch "key Escape") > 0 ? ᵘq̲uit p
179 (v m̲atch "key c") ? ᵘs̲tep ᵘc̲hunks p
180 (v m̲atch "key h") ? ᵘs̲tep start
181 ᵘs̲tep p
182}
183last ← 100000 'ᵘf̲rame p̲ower start
184"bye"