nx_wasm_racing.nx source
↩ module page · 124 lines · 5095 B
1// nx_wasm_racing.nx -- BROWSER-PLAYABLE sovereign Racing: BASE-RELATIVE integer core, runs native (-> PNG) AND
2// in the browser (base = 0 = our sovereign WASM linear memory). NO float, NO JS logic, NO canvas drawing. A
3// top-down endless dodge racer: hold left/right to steer the car between descending traffic; survive to grow
4// the distance score; a collision ends the run (shoot/space restarts). init()/tick(input)/render()/score()/
5// ww()/hh()/fb_off() = the wasm interface (auto-exported). license_tier: ORIGINAL
6import "nx_nishi_font_core.nx"
7const O_MAGIC_7919: i64 = 7919
8const W: i64 = 120
9const H: i64 = 180
10const NO: i64 = 5
11const SY: i64 = 156 // player row
12const SPEED: i64 = 2
13const O_FB: i64 = 0 // framebuffer W*H i64 at offset 0
14const O_OX: i64 = 172800 // opponent x[16] (W*H*8)
15const O_OY: i64 = 172928 // opponent y[16]
16const O_ST: i64 = 173056 // scalars[16]: 0=px 1=distance 2=gameover 3=tick
17const O_MSK: i64 = 173184 // HUD glyph scratch
18const O_STR: i64 = 181376 // HUD string scratch
19
20func rgb(r: i64, g: i64, b: i64) -> i64 { return (r & 255) | ((g & 255) << 8) | ((b & 255) << 16) }
21
22func fillr(base: i64, x0: i64, y0: i64, x1: i64, y1: i64, c: i64) -> i64 {
23 let fb: *i64 = (base + O_FB) as *i64
24 var yy: i64 = y0; if yy < 0 { yy = 0 }
25 var ye: i64 = y1; if ye > H { ye = H }
26 while yy < ye {
27 var xx: i64 = x0; if xx < 0 { xx = 0 }
28 var xe: i64 = x1; if xe > W { xe = W }
29 while xx < xe { fb[yy*W + xx] = c; xx = xx + 1 }
30 yy = yy + 1
31 }
32 return 0
33}
34
35func respawn(base: i64, i: i64) -> i64 {
36 let ox: *i64 = (base + O_OX) as *i64
37 let oy: *i64 = (base + O_OY) as *i64
38 let st: *i64 = (base + O_ST) as *i64
39 oy[i] = 0 - (14 + ((st[3]*13 + i*37) % 50))
40 ox[i] = 18 + ((st[3]*O_MAGIC_7919 + i*131) % (W - 36))
41 return 0
42}
43
44func init_impl(base: i64) -> i64 {
45 let oy: *i64 = (base + O_OY) as *i64
46 let ox: *i64 = (base + O_OX) as *i64
47 let st: *i64 = (base + O_ST) as *i64
48 st[0] = W/2; st[1] = 0; st[2] = 0; st[3] = 0
49 var i: i64 = 0
50 while i < NO { oy[i] = 0 - (24 + i*38); ox[i] = 18 + (i*21) % (W - 36); i = i + 1 }
51 return 0
52}
53
54func tick_impl(base: i64, input: i64) -> i64 {
55 let ox: *i64 = (base + O_OX) as *i64
56 let oy: *i64 = (base + O_OY) as *i64
57 let st: *i64 = (base + O_ST) as *i64
58 if st[2] == 1 { if (input & 4) != 0 { init_impl(base) } return 0 }
59 if (input & 1) != 0 { st[0] = st[0] - 3; if st[0] < 14 { st[0] = 14 } }
60 if (input & 2) != 0 { st[0] = st[0] + 3; if st[0] > W-14 { st[0] = W-14 } }
61 var i: i64 = 0
62 while i < NO {
63 oy[i] = oy[i] + SPEED
64 if oy[i] > H + 14 { respawn(base, i) }
65 var dx: i64 = st[0] - ox[i]; if dx < 0 { dx = 0 - dx }
66 var dy: i64 = SY - oy[i]; if dy < 0 { dy = 0 - dy }
67 if dx < 14 { if dy < 15 { st[2] = 1 } }
68 i = i + 1
69 }
70 if st[2] == 0 { st[1] = st[1] + 1 }
71 st[3] = st[3] + 1
72 return 0
73}
74
75func car(base: i64, cx: i64, cy: i64, body: i64, top: i64) -> i64 {
76 fillr(base, cx-9, cy-12, cx+9, cy+12, body)
77 fillr(base, cx-6, cy-12, cx+6, cy-8, top)
78 fillr(base, cx-6, cy+8, cx+6, cy+12, top)
79 return 0
80}
81
82func render_impl(base: i64) -> i64 {
83 let fb: *i64 = (base + O_FB) as *i64
84 let ox: *i64 = (base + O_OX) as *i64
85 let oy: *i64 = (base + O_OY) as *i64
86 let st: *i64 = (base + O_ST) as *i64
87 var p: i64 = 0
88 let road: i64 = rgb(38, 40, 46)
89 while p < W*H { fb[p] = road; p = p + 1 }
90 fillr(base, 8, 0, 12, H, rgb(220, 210, 120)) // left edge
91 fillr(base, W-12, 0, W-8, H, rgb(220, 210, 120)) // right edge
92 var y: i64 = (st[1] % 24) - 24 // scrolling lane dashes
93 while y < H { fillr(base, W/2-2, y, W/2+2, y+12, rgb(210,210,210)); y = y + 24 }
94 var i: i64 = 0
95 while i < NO { car(base, ox[i], oy[i], rgb(224, 90, 70), rgb(60, 30, 30)); i = i + 1 }
96 car(base, st[0], SY, rgb(90, 210, 122), rgb(30, 60, 40))
97 if st[2] == 1 {
98 fillr(base, 0, 0, W, 3, rgb(200,40,40)); fillr(base, 0, H-3, W, H, rgb(200,40,40))
99 fillr(base, 0, 0, 3, H, rgb(200,40,40)); fillr(base, W-3, 0, W, H, rgb(200,40,40))
100 }
101 // HUD distance
102 let sbuf: *u8 = (base + O_STR) as *u8
103 var slen: i64 = 0
104 var sv: i64 = st[1]
105 if sv <= 0 { sbuf[0] = 48 as u8; slen = 1 } else {
106 let tmp: *u8 = (base + O_STR + 16) as *u8
107 var k: i64 = 0
108 while sv > 0 { tmp[k] = (48 + (sv % 10)) as u8; sv = sv / 10; k = k + 1 }
109 var q: i64 = 0
110 while q < k { sbuf[q] = tmp[k - 1 - q]; q = q + 1 }
111 slen = k
112 }
113 let mask: *u8 = (base + O_MSK) as *u8
114 nf_draw_text_mem(fb, W, H, mask, 4, 3, 16, sbuf, slen, rgb(235, 240, 250))
115 return 0
116}
117
118func init() -> i64 { return init_impl(0) }
119func tick(input: i64) -> i64 { return tick_impl(0, input) }
120func render() -> i64 { return render_impl(0) }
121func score() -> i64 { let st: *i64 = (0 + O_ST) as *i64; return st[1] }
122func fb_off() -> i64 { return O_FB }
123func ww() -> i64 { return W }
124func hh() -> i64 { return H }