code wiki / (root) / nx_wasm_pong.nx

nx_wasm_pong.nx source

↩ module page · 103 lines · 4933 B

1// nx_wasm_pong.nx -- BROWSER-PLAYABLE sovereign Pong (Sport): BASE-RELATIVE integer core, runs native (-> PNG) 2// AND in the browser (base = 0). NO float, NO JS logic, NO canvas drawing. You are the LEFT paddle (up/down); 3// a beatable AI controls the right. The ball bounces off walls + paddles with SPIN (where it hits the paddle 4// sets its vertical speed -> skill), and the AI tracks slower than max spin so you can score. Endless, scores 5// climb. init()/tick(input)/render()/score()/ww()/hh()/fb_off() = the wasm interface. license_tier: ORIGINAL 6import "nx_nishi_font_core.nx" 7const W: i64 = 200 8const H: i64 = 120 9const PADH: i64 = 16 // paddle half-height 10const LX: i64 = 8 11const RX: i64 = 192 12const O_FB: i64 = 0 // framebuffer W*H i64 13const O_ST: i64 = 192000 // scalars[16]: 0=bx 1=by 2=bvx 3=bvy 4=lpy 5=rpy 6=lscore 7=rscore 14const O_MSK: i64 = 192128 // HUD glyph scratch 15const O_STR: i64 = 200320 // HUD string scratch (left score @ +0, right score @ +32) 16 17func rgb(r: i64, g: i64, b: i64) -> i64 { return (r & 255) | ((g & 255) << 8) | ((b & 255) << 16) } 18func clampi(v: i64, lo: i64, hi: i64) -> i64 { if v < lo { return lo } if v > hi { return hi } return v } 19 20func fillr(base: i64, x0: i64, y0: i64, x1: i64, y1: i64, c: i64) -> i64 { 21 let fb: *i64 = (base + O_FB) as *i64 22 var yy: i64 = y0; if yy < 0 { yy = 0 } 23 var ye: i64 = y1; if ye > H { ye = H } 24 while yy < ye { 25 var xx: i64 = x0; if xx < 0 { xx = 0 } 26 var xe: i64 = x1; if xe > W { xe = W } 27 while xx < xe { fb[yy*W + xx] = c; xx = xx + 1 } 28 yy = yy + 1 29 } 30 return 0 31} 32 33func serve(base: i64, dir: i64) -> i64 { 34 let st: *i64 = (base + O_ST) as *i64 35 st[0] = W/2; st[1] = H/2; st[2] = dir*3; st[3] = 2 36 return 0 37} 38func init_impl(base: i64) -> i64 { 39 let st: *i64 = (base + O_ST) as *i64 40 st[4] = H/2; st[5] = H/2; st[6] = 0; st[7] = 0 41 serve(base, 1) 42 return 0 43} 44 45func tick_impl(base: i64, input: i64) -> i64 { 46 let st: *i64 = (base + O_ST) as *i64 47 if (input & 1) != 0 { st[4] = clampi(st[4] - 4, PADH, H - PADH) } 48 if (input & 2) != 0 { st[4] = clampi(st[4] + 4, PADH, H - PADH) } 49 // AI right paddle tracks the ball at speed 2 (slower than max spin -> beatable) 50 if st[5] < st[1] { st[5] = clampi(st[5] + 2, PADH, H - PADH) } 51 if st[5] > st[1] { st[5] = clampi(st[5] - 2, PADH, H - PADH) } 52 st[0] = st[0] + st[2]; st[1] = st[1] + st[3] 53 if st[1] <= 2 { st[1] = 2; st[3] = 0 - st[3] } 54 if st[1] >= H - 2 { st[1] = H - 2; st[3] = 0 - st[3] } 55 if st[2] < 0 { if st[0] <= LX + 3 { var d: i64 = st[1] - st[4]; if d < 0 { d = 0 - d } 56 if d < PADH + 3 { st[2] = 3; st[3] = clampi((st[1] - st[4]) / 4, 0 - 3, 3); st[0] = LX + 3 } } } 57 if st[2] > 0 { if st[0] >= RX - 3 { var d: i64 = st[1] - st[5]; if d < 0 { d = 0 - d } 58 if d < PADH + 3 { st[2] = 0 - 3; st[3] = clampi((st[1] - st[5]) / 4, 0 - 3, 3); st[0] = RX - 3 } } } 59 if st[0] < 0 { st[7] = st[7] + 1; serve(base, 1) } // AI scores 60 if st[0] > W { st[6] = st[6] + 1; serve(base, 0 - 1) } // player scores 61 return 0 62} 63 64func draw_num(base: i64, x: i64, off: i64, val: i64) -> i64 { 65 let fb: *i64 = (base + O_FB) as *i64 66 let sbuf: *u8 = (base + O_STR + off) as *u8 67 var slen: i64 = 0 68 var sv: i64 = val 69 if sv <= 0 { sbuf[0] = 48 as u8; slen = 1 } else { 70 let tmp: *u8 = (base + O_STR + off + 12) as *u8 71 var k: i64 = 0 72 while sv > 0 { tmp[k] = (48 + (sv % 10)) as u8; sv = sv / 10; k = k + 1 } 73 var q: i64 = 0 74 while q < k { sbuf[q] = tmp[k - 1 - q]; q = q + 1 } 75 slen = k 76 } 77 let mask: *u8 = (base + O_MSK) as *u8 78 nf_draw_text_mem(fb, W, H, mask, x, 4, 16, sbuf, slen, rgb(235, 240, 250)) 79 return 0 80} 81 82func render_impl(base: i64) -> i64 { 83 let fb: *i64 = (base + O_FB) as *i64 84 let st: *i64 = (base + O_ST) as *i64 85 var p: i64 = 0 86 while p < W*H { fb[p] = rgb(12, 16, 22); p = p + 1 } 87 var y: i64 = 4 88 while y < H { fillr(base, W/2-1, y, W/2+1, y+6, rgb(60,70,84)); y = y + 12 } // center dashes 89 fillr(base, LX-3, st[4]-PADH, LX+3, st[4]+PADH, rgb(90,210,122)) // left paddle (player) 90 fillr(base, RX-3, st[5]-PADH, RX+3, st[5]+PADH, rgb(224,90,80)) // right paddle (AI) 91 fillr(base, st[0]-2, st[1]-2, st[0]+3, st[1]+3, rgb(240,240,240)) // ball 92 draw_num(base, W/2 - 24, 0, st[6]) // player score (left) 93 draw_num(base, W/2 + 12, 32, st[7]) // AI score (right) 94 return 0 95} 96 97func init() -> i64 { return init_impl(0) } 98func tick(input: i64) -> i64 { return tick_impl(0, input) } 99func render() -> i64 { return render_impl(0) } 100func score() -> i64 { let st: *i64 = (0 + O_ST) as *i64; return st[6] } 101func fb_off() -> i64 { return O_FB } 102func ww() -> i64 { return W } 103func hh() -> i64 { return H }