code wiki / (root) / nx_wasm_shmup.nx

nx_wasm_shmup.nx source

↩ module page · 134 lines · 5983 B

1// nx_wasm_shmup.nx -- BROWSER-PLAYABLE sovereign Shoot-'em-up: BASE-RELATIVE integer core, the SAME code runs 2// native (base = a real mmap -> render a frame to PNG for eyeball verify) AND in the browser (base = 0 = our 3// sovereign WASM linear memory). NO float, NO JS logic, NO 3rd-party canvas drawing. Real-time: the shim's 4// rAF loop calls tick(input) every frame with the held-key bitmask (1=left 2=right 4=shoot); the core moves 5// the ship, fires a bullet, advances it, kills descending enemies, respawns waves endlessly, and game-overs 6// if a wave reaches the ship line (shoot restarts). HUD score drawn by our OWN font (no JS/canvas text). 7// init()/tick(input)/render()/score()/ww()/hh()/fb_off() are the wasm interface (auto-exported by nx_wasm.nx). 8// license_tier: ORIGINAL 9import "nx_nishi_font_core.nx" 10const W: i64 = 160 11const H: i64 = 192 12const NE: i64 = 6 13const SY: i64 = 176 // ship row 14const EYSTART: i64 = 20 // wave spawn y 15const O_FB: i64 = 0 // framebuffer W*H i64 (packed RGB) at offset 0 16const O_EX: i64 = 245760 // enemy x[16] (W*H*8) 17const O_EA: i64 = 245888 // enemy alive[16] 18const O_ST: i64 = 246016 // scalars[16]: 0=sx 1=bx 2=by 3=bactive 4=score 5=wave_count 6=ey 7=gameover 8=tick 19const O_MSK: i64 = 246144 // HUD glyph scratch mask (base-relative -> no sys_mmap, lowers to wasm) 20const O_STR: i64 = 254336 // HUD score string scratch 21 22func rgb(r: i64, g: i64, b: i64) -> i64 { return (r & 255) | ((g & 255) << 8) | ((b & 255) << 16) } 23 24func fillr(base: i64, x0: i64, y0: i64, x1: i64, y1: i64, c: i64) -> i64 { 25 let fb: *i64 = (base + O_FB) as *i64 26 var yy: i64 = y0; if yy < 0 { yy = 0 } 27 var ye: i64 = y1; if ye > H { ye = H } 28 while yy < ye { 29 var xx: i64 = x0; if xx < 0 { xx = 0 } 30 var xe: i64 = x1; if xe > W { xe = W } 31 while xx < xe { fb[yy*W + xx] = c; xx = xx + 1 } 32 yy = yy + 1 33 } 34 return 0 35} 36 37func spawn_wave(base: i64) -> i64 { 38 let ex: *i64 = (base + O_EX) as *i64 39 let ea: *i64 = (base + O_EA) as *i64 40 let st: *i64 = (base + O_ST) as *i64 41 var i: i64 = 0 42 while i < NE { ex[i] = 18 + i*24; ea[i] = 1; i = i + 1 } 43 st[5] = NE 44 st[6] = EYSTART 45 return 0 46} 47 48func init_impl(base: i64) -> i64 { 49 let st: *i64 = (base + O_ST) as *i64 50 st[0] = W/2; st[1] = 0; st[2] = 0; st[3] = 0; st[4] = 0; st[7] = 0; st[8] = 0; st[9] = 0 51 spawn_wave(base) 52 return 0 53} 54 55func tick_impl(base: i64, input: i64) -> i64 { 56 let ex: *i64 = (base + O_EX) as *i64 57 let ea: *i64 = (base + O_EA) as *i64 58 let st: *i64 = (base + O_ST) as *i64 59 if st[7] == 1 { if (input & 4) != 0 { init_impl(base) } return 0 } 60 if (input & 1) != 0 { st[0] = st[0] - 3; if st[0] < 8 { st[0] = 8 } } 61 if (input & 2) != 0 { st[0] = st[0] + 3; if st[0] > W-8 { st[0] = W-8 } } 62 if (input & 4) != 0 { if st[3] == 0 { st[1] = st[0]; st[2] = SY - 10; st[3] = 1; st[9] = 1 } } 63 if st[3] == 1 { 64 st[2] = st[2] - 6 65 if st[2] < 0 { st[3] = 0 } else { 66 var i: i64 = 0 67 while i < NE { 68 if ea[i] == 1 { 69 var dx: i64 = st[1] - ex[i]; if dx < 0 { dx = 0 - dx } 70 var dy: i64 = st[2] - st[6]; if dy < 0 { dy = 0 - dy } 71 if dx < 9 { if dy < 9 { ea[i] = 0; st[3] = 0; st[4] = st[4] + 10; st[5] = st[5] - 1; st[9] = 2; i = NE } else { i = i + 1 } } else { i = i + 1 } 72 } else { i = i + 1 } 73 } 74 } 75 } 76 if (st[8] % 24) == 0 { st[6] = st[6] + 5; if st[6] >= SY - 10 { st[7] = 1; st[9] = 3 } } 77 if st[5] <= 0 { spawn_wave(base); st[4] = st[4] + 5 } 78 st[8] = st[8] + 1 79 return 0 80} 81 82func render_impl(base: i64) -> i64 { 83 let fb: *i64 = (base + O_FB) as *i64 84 let ex: *i64 = (base + O_EX) as *i64 85 let ea: *i64 = (base + O_EA) as *i64 86 let st: *i64 = (base + O_ST) as *i64 87 var p: i64 = 0 88 let sky: i64 = rgb(8, 10, 24) 89 while p < W*H { fb[p] = sky; p = p + 1 } 90 // stars (deterministic scatter) 91 var s: i64 = 0 92 while s < 40 { let sx2: i64 = (s*53) % W; let sy2: i64 = (s*97) % H; fb[sy2*W + sx2] = rgb(110,110,150); s = s + 1 } 93 // enemies 94 var i: i64 = 0 95 while i < NE { 96 if ea[i] == 1 { fillr(base, ex[i]-7, st[6]-6, ex[i]+7, st[6]+6, rgb(224,80,58)); fillr(base, ex[i]-4, st[6]+6, ex[i]+4, st[6]+9, rgb(150,50,40)) } 97 i = i + 1 98 } 99 // bullet 100 if st[3] == 1 { fillr(base, st[1]-1, st[2]-4, st[1]+2, st[2]+3, rgb(250,240,120)) } 101 // ship 102 fillr(base, st[0]-7, SY-3, st[0]+8, SY+5, rgb(90,210,122)) 103 fillr(base, st[0]-2, SY-7, st[0]+3, SY-3, rgb(120,230,150)) 104 // game-over red border 105 if st[7] == 1 { 106 fillr(base, 0, 0, W, 3, rgb(200,40,40)); fillr(base, 0, H-3, W, H, rgb(200,40,40)) 107 fillr(base, 0, 0, 3, H, rgb(200,40,40)); fillr(base, W-3, 0, W, H, rgb(200,40,40)) 108 } 109 // HUD score (our sovereign font) 110 let sbuf: *u8 = (base + O_STR) as *u8 111 var slen: i64 = 0 112 var sv: i64 = st[4] 113 if sv <= 0 { sbuf[0] = 48 as u8; slen = 1 } else { 114 let tmp: *u8 = (base + O_STR + 16) as *u8 115 var k: i64 = 0 116 while sv > 0 { tmp[k] = (48 + (sv % 10)) as u8; sv = sv / 10; k = k + 1 } 117 var q: i64 = 0 118 while q < k { sbuf[q] = tmp[k - 1 - q]; q = q + 1 } 119 slen = k 120 } 121 let mask: *u8 = (base + O_MSK) as *u8 122 nf_draw_text_mem(fb, W, H, mask, 4, 3, 16, sbuf, slen, rgb(235, 240, 250)) 123 return 0 124} 125 126// ---- WASM exports (base = 0 = our sovereign linear memory) ---- 127func init() -> i64 { return init_impl(0) } 128func tick(input: i64) -> i64 { return tick_impl(0, input) } 129func sfx_event() -> i64 { let st: *i64 = (0 + O_ST) as *i64; let e: i64 = st[9]; st[9] = 0; return e } // 1=shoot 2=kill 3=gameover; cleared on read 130func render() -> i64 { return render_impl(0) } 131func score() -> i64 { let st: *i64 = (0 + O_ST) as *i64; return st[4] } 132func fb_off() -> i64 { return O_FB } 133func ww() -> i64 { return W } 134func hh() -> i64 { return H }