nx_wasm_thirdperson.nx source
↩ module page · 119 lines · 5294 B
1// nx_wasm_thirdperson.nx -- BROWSER-PLAYABLE sovereign Third-Person explorer: BASE-RELATIVE integer core, runs
2// native (-> PNG) AND in the browser (base = 0). NO float, NO JS logic, NO canvas drawing. A FOLLOW CAMERA
3// keeps the avatar centered while a world LARGER than the screen scrolls under it; move 4-directionally to
4// collect every item then reach the goal (win). init()/tick(input)/render()/score()/ww()/hh()/fb_off() = the
5// wasm interface; input bits 1=up 2=down 4=left 8=right. license_tier: ORIGINAL
6import "nx_nishi_font_core.nx"
7const W: i64 = 128 // viewport
8const H: i64 = 112
9const WW: i64 = 288 // world
10const WH: i64 = 224
11const NI: i64 = 5
12const MOVE: i64 = 2
13const O_FB: i64 = 0 // framebuffer W*H i64
14const O_IX: i64 = 114688 // item world-x[16] (W*H*8)
15const O_IY: i64 = 114816
16const O_IG: i64 = 114944 // item collected[16]
17const O_ST: i64 = 115072 // scalars[16]: 0=wx 1=wy 2=collected 3=won 4=gx 5=gy
18const O_MSK: i64 = 115200
19const O_STR: i64 = 123392
20
21func rgb(r: i64, g: i64, b: i64) -> i64 { return (r & 255) | ((g & 255) << 8) | ((b & 255) << 16) }
22func clampi(v: i64, lo: i64, hi: i64) -> i64 { if v < lo { return lo } if v > hi { return hi } return v }
23func iabs(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
24
25func fillr(base: i64, x0: i64, y0: i64, x1: i64, y1: i64, c: i64) -> i64 {
26 let fb: *i64 = (base + O_FB) as *i64
27 var yy: i64 = y0; if yy < 0 { yy = 0 }
28 var ye: i64 = y1; if ye > H { ye = H }
29 while yy < ye {
30 var xx: i64 = x0; if xx < 0 { xx = 0 }
31 var xe: i64 = x1; if xe > W { xe = W }
32 while xx < xe { fb[yy*W + xx] = c; xx = xx + 1 }
33 yy = yy + 1
34 }
35 return 0
36}
37func disc(base: i64, cx: i64, cy: i64, rad: i64, c: i64) -> i64 {
38 let fb: *i64 = (base + O_FB) as *i64
39 var dy: i64 = 0 - rad; let r2: i64 = rad*rad
40 while dy <= rad {
41 var dx: i64 = 0 - rad
42 while dx <= rad {
43 if dx*dx + dy*dy <= r2 { let x: i64 = cx+dx; let y: i64 = cy+dy
44 if x >= 0 { if y >= 0 { if x < W { if y < H { fb[y*W + x] = c } } } } }
45 dx = dx + 1
46 }
47 dy = dy + 1
48 }
49 return 0
50}
51
52func init_impl(base: i64) -> i64 {
53 let ix: *i64 = (base + O_IX) as *i64
54 let iy: *i64 = (base + O_IY) as *i64
55 let ig: *i64 = (base + O_IG) as *i64
56 let st: *i64 = (base + O_ST) as *i64
57 ix[0]=40; iy[0]=40; ix[1]=248; iy[1]=40; ix[2]=40; iy[2]=184; ix[3]=248; iy[3]=184; ix[4]=144; iy[4]=150
58 var i: i64 = 0; while i < NI { ig[i] = 0; i = i + 1 }
59 st[0]=144; st[1]=64; st[2]=0; st[3]=0; st[4]=250; st[5]=196
60 return 0
61}
62
63func tick_impl(base: i64, input: i64) -> i64 {
64 let ix: *i64 = (base + O_IX) as *i64
65 let iy: *i64 = (base + O_IY) as *i64
66 let ig: *i64 = (base + O_IG) as *i64
67 let st: *i64 = (base + O_ST) as *i64
68 if (input & 1) != 0 { st[1] = clampi(st[1] - MOVE, 8, WH - 8) }
69 if (input & 2) != 0 { st[1] = clampi(st[1] + MOVE, 8, WH - 8) }
70 if (input & 4) != 0 { st[0] = clampi(st[0] - MOVE, 8, WW - 8) }
71 if (input & 8) != 0 { st[0] = clampi(st[0] + MOVE, 8, WW - 8) }
72 var i: i64 = 0
73 while i < NI {
74 if ig[i] == 0 { if iabs(st[0] - ix[i]) < 9 { if iabs(st[1] - iy[i]) < 9 { ig[i] = 1; st[2] = st[2] + 1 } } }
75 i = i + 1
76 }
77 if iabs(st[0] - st[4]) < 11 { if iabs(st[1] - st[5]) < 11 { if st[2] == NI { st[3] = 1 } } }
78 return 0
79}
80
81func render_impl(base: i64) -> i64 {
82 let fb: *i64 = (base + O_FB) as *i64
83 let ix: *i64 = (base + O_IX) as *i64
84 let iy: *i64 = (base + O_IY) as *i64
85 let ig: *i64 = (base + O_IG) as *i64
86 let st: *i64 = (base + O_ST) as *i64
87 let camx: i64 = clampi(st[0] - W/2, 0, WW - W)
88 let camy: i64 = clampi(st[1] - H/2, 0, WH - H)
89 // checker floor (only visible tiles)
90 var ty: i64 = camy/16
91 while ty*16 - camy < H {
92 var tx: i64 = camx/16
93 while tx*16 - camx < W {
94 var col: i64 = rgb(40, 70, 46); if ((tx + ty) & 1) == 1 { col = rgb(48, 84, 54) }
95 fillr(base, tx*16 - camx, ty*16 - camy, tx*16 + 16 - camx, ty*16 + 16 - camy, col)
96 tx = tx + 1
97 }
98 ty = ty + 1
99 }
100 fillr(base, st[4]-camx-7, st[5]-camy-7, st[4]-camx+7, st[5]-camy+7, rgb(90, 210, 220)) // goal (cyan)
101 var i: i64 = 0
102 while i < NI { if ig[i] == 0 { disc(base, ix[i]-camx, iy[i]-camy, 4, rgb(245, 210, 70)) } i = i + 1 }
103 fillr(base, st[0]-camx-5, st[1]-camy-5, st[0]-camx+5, st[1]-camy+5, rgb(90, 210, 122)) // avatar (green)
104 if st[3] == 1 { fillr(base, 0,0,W,3, rgb(90,220,120)); fillr(base, 0,H-3,W,H, rgb(90,220,120)); fillr(base, 0,0,3,H, rgb(90,220,120)); fillr(base, W-3,0,W,H, rgb(90,220,120)) }
105 // HUD: collected / NI
106 let sbuf: *u8 = (base + O_STR) as *u8
107 sbuf[0] = (48 + st[2]) as u8; sbuf[1] = 47 as u8; sbuf[2] = (48 + NI) as u8
108 let mask: *u8 = (base + O_MSK) as *u8
109 nf_draw_text_mem(fb, W, H, mask, 4, 3, 16, sbuf, 3, rgb(235, 240, 250))
110 return 0
111}
112
113func init() -> i64 { return init_impl(0) }
114func tick(input: i64) -> i64 { return tick_impl(0, input) }
115func render() -> i64 { return render_impl(0) }
116func score() -> i64 { let st: *i64 = (0 + O_ST) as *i64; return st[2] }
117func fb_off() -> i64 { return O_FB }
118func ww() -> i64 { return W }
119func hh() -> i64 { return H }